1. 程式人生 > >2500-使用MyBatis操作MySQL進行批量更新的注意事項

2500-使用MyBatis操作MySQL進行批量更新的注意事項

原則上一條SQL只更新一條資料庫操作,但有時需要批量操作資料,特別是一些DML語句,在操作資料庫時,資料庫會報出異常,不允許混合語句,此時需要額外配置進行相容。

例如:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'update purchase_instrument_bill_detail   
                 SET out_count = '1',
' at line 8
Caused by: java.sql.SQLException: sql injection violation, multi-statement not
allowcom.alibaba.druid.wall.WallFilter.check(WallFilter.java:714) 
atcom.alibaba.druid.wall.WallFilter.connection_prepareStatement(WallFilter.java:240) 
atcom.alibaba.druid.filter.FilterChainImpl.connection_prepareStatement(FilterChainImpl.java:448)
atcom.alibaba.druid.filter.FilterAdapter.connection_prepareStatement(FilterAdapter.java:928) 

解決方案:

  1. 資料庫連線加引數
  2. 連線池需要配置

1. 資料庫連線加引數

新增引數allowMultiQueries=true

可解決資料庫連線層面的異常問題,指定連線資料庫時,可執行混合SQL。

參考連線配置: jdbc:mysql://\({datasource.host}:\){datasource.port}/${datasource.name}?relaxAutoCommit=true&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&useSSL=false&allowMultiQueries=true

2. 連線池需要配置

如果使用的資料庫連線池是Druid,則需要額外配置引數。其他種類連線池,如C3P0,DBCP等,尚未考證。

## 配置監控統計攔截的filters,去掉後監控介面sql無法統計,'wall'用於防火牆,此處去除防火牆
spring.datasource.druid.filters=config,stat,slf4j
## 配置過濾器wall的引數
spring.datasource.druid.filter.wall.config.use-allow=false
spring.datasource.druid.filter.wall.config.multi-statement-allow=true

wall是com.alibaba.druid.wall.WallFilter的簡稱,提供sql的檢查和過濾等功能,預設這裡會對混合SQL進行攔截,此處為了執行大SQL,可關閉防火牆功能。(有SQL注入風險,謹慎使用)


附上一個MyBatis的xml指令碼demo:


    <update id="batchUpdateForRepay" parameterType="com.xxx.settle.credit.generate.domain.bo.RepayUpdateCreditInfoBO">

        <foreach collection="list" index="index" item="item" separator=";">
            update tb_credit_info
            <trim prefix="set" suffixOverrides=",">
                <if test="item.state != null">state = #{item.state},</if>
                <if test="item.leftPrincipalAmount != null">left_principal = left_principal - #{item.leftPrincipalAmount},</if>
                <if test="item.currentPeriodChange != null">current_period = current_period + #{item.currentPeriodChange},</if>
                <if test="item.receivedPrincipalAmount != null">received_principal = received_principal + #{item.receivedPrincipalAmount},</if>
                <if test="item.remark != null">remark = #{item.remark},</if>
            </trim>
            where product_id = #{item.productId} and credit_id = #{item.creditId}
        </foreach>

    </update>