mybatis+mysql 批量更新
最近项目开发是遇到了原来遇到的问题,给忘了,又在网上查询了一次,这次在这里记录下来
我这里采用的是最通用的批量更新(为了方便阅读删除了一些字段)
代码
<update id="updateBatch" parameterType="java.util.List" > <foreach collection="list" item="item" index="index" open="" close="" separator=";"> update purchase_order_detail <set > <if test='item.consumeCode !=null and item.consumeCode !=""' >consumeCode = #{item.consumeCode},</if> <if test='item.consumeName !=null and item.consumeName !=""' >consumeName = #{item.consumeName},</if> <if test='item.productId !=null and item.productId !=""' >productId = #{item.productId},</if> </set> WHERE purchaseOrderDetailId = #{item.purchaseOrderDetailId} </foreach> </update>
注意实体属性前一定要加对应的item——对应的颜色加深的地方,否侧会报错说参数不存在
然而在执行时一直报错,当时没太认真分析,只是通过后台代码个各种情况调试时发现,一条数据的更新是可以的,但是多条就不行也就是传入的参数list的size大于1时是无法执行的;
感觉问题逐渐清晰,然后就出网上查了一下,可能是问题描述不够清晰,网上有一些其他的批量更新语句
像这样的更新值相同的
<update id="updateStatus"> UPDATE purchase_order_detail set status= #{status} WHERE id in <foreach collection="ids" index="index" item="id" separator="," open="(" close=")"> #{id} </foreach> </update>
还有这样的
<update id="updateListByHouseId" parameterType="java.util.ArrayList"> <foreach close=";" collection="list" index="index" item="item" open="" separator=";"> update rba_house_status <trim prefix="set" suffixOverrides=","> last_push_time = now(), <if test="item.pushStatus != null">push_status = #{item.pushStatus},</if> <if test="item.createStatus != null">create_status = #{item.createStatus},</if> <if test="item.houseCreateTime != null">house_create_time = #{item.houseCreateTime},</if> <if test="item.updateStatus != null">update_status = #{item.updateStatus},</if> update_time = now(), <if test="item.auditStatus != null">audit_status = #{item.auditStatus},</if> <if test="item.auditDesc != null">audit_desc = #{item.auditDesc},</if> <if test="item.hotelId != null">hotel_id = #{item.hotelId},</if> </trim> <where>house_id = #{item.houseId}</where> </foreach> </update>
看着就感觉易读性较差;还是想用第一种批量更新,然后查了一下相关资料,其中说到mysql需要开启支持批量执行sql语句——————也就是以这种 “;” 隔开的sql语句在批量执行时需要添加msyql 支持
在数据库连接串后面添加
allowMultiQueries=true
例如
url: jdbc:mysql://127.0.0.1:3306/clouddo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
拓展:此时本人就思考问什么没有加入支持时第二种那样的局部循环条件就可以执行呢,包括一些局部循环的插入语句
<insert id="insertBatch"> INSERT INTO purchase_order( purchaseOrderId, purchaseOrderNo, purchaseOrderName, purchaseApplyNo, purchaseOrderType, purchaseOrderTypeName, supplierId, supplierName, hosptialId, hosptialName, purchaseOrderAmount, purchaseOrderStatus, purchaseOrderDate, shippingAddress, shippingPerson, shippingPhone ) VALUES <foreach collection ="list" item="purchaseOrder" separator =","> ( #{purchaseOrder.purchaseOrderId}, #{purchaseOrder.purchaseOrderNo}, #{purchaseOrder.purchaseOrderName}, #{purchaseOrder.purchaseApplyNo}, #{purchaseOrder.purchaseOrderType}, #{purchaseOrder.purchaseOrderTypeName}, #{purchaseOrder.supplierId}, #{purchaseOrder.supplierName}, #{purchaseOrder.hosptialId}, #{purchaseOrder.hosptialName}, #{purchaseOrder.purchaseOrderAmount}, #{purchaseOrder.purchaseOrderStatus}, #{purchaseOrder.purchaseOrderDate}, #{purchaseOrder.shippingAddress}, #{purchaseOrder.shippingPerson}, #{purchaseOrder.shippingPhone} ) </foreach> </insert>
抱着试一试的心态我在后台将sql打印了出来
INSERT INTO distribution_order_detail ( distributionOrderNo, distributionOrderDetailNo, purchaseOrderNo, purchaseOrderDetailNo, consumeCode, ) VALUES ( ?, ?, ?, ?, ? ), ( ?, ?, ?, ?, ? )
此时发现这是后的sql语句虽然达到了批量的目的但是只是一条语句 而第一种批量跟新的sql语句却是两条sql 语句只是用“;”隔开了
update purchase_order_detail SET waitDistributionCount = ? WHERE purchaseOrderDetailId = ? ;
update purchase_order_detail SET waitDistributionCount = ? WHERE purchaseOrderDetailId = ?
第二种修改值相同的批量更新就更是一条sql了
UPDATE consume_material SET consumeStatus = ? WHERE consumeId in ( ? , ? )
这里再记录说明一下我遇到的其他问题
在mybaits 中针对时间的字段进行判断时
<if test='sterilizationExpirationDate !=null and sterilizationExpirationDate !=""' >sterilizationExpirationDate = #{sterilizationExpirationDate},</if>
报错
invalid comparison: java.sql.Timestamp and java.lang.String
错误的原因是
mybatis 3.3.0中对于时间参数进行比较有的一个bug. 如果拿传入的时间类型参数与空字符串”进行对比判断则会引发异常. 所以在上面的代码中去该该判断, 只保留非空判断就正常了
修改后
<if test='sterilizationExpirationDate !=null ' >sterilizationExpirationDate = #{sterilizationExpirationDate},</if>
这样就可以了
以上仅是个人理解并作为记录,不对之处希望各位帮忙指正一下。