场景是,别人给我传一张表中的数据list,其中的数据有些是数据库中有的,有些是新的,已经有的我要更新,新的我要插入,oracle提供了merge into语句来实现这个功能
MERGE INTO [target-table] A USING [source-table sql] B ON([conditional expression] and [...]...)
WHEN MATCHED THEN
[UPDATE sql]
WHEN NOT MATCHED THEN
[INSERT sql]
- merge into没有返回值,返回值只有insert,update,delete三个基本的DML语句才有
- meige into只能把表A和表B进行比较,要么表B是已经存在的表,要么用select "常量" from dual来建立临时的只有一条数据的表
原本打算用mybatis+foreach将list中的每一条数据建立临时表和原有表进行比较,如下
但是发现执行中,如果有不止一条数据进来,就会报如下错
sql injection violation, multi-statement not allow
可以看到,我的foreach,separator=";",也就是说我最后要执行的是很多个sql,java不允许这样做。
方法二(暂时采用的方法)
在java中,用foreach循环,对list的每一条记录merge into
在使用merge into的时候,有时候会报错
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='roomInfo.roomType', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting null for parameter #5 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 无效的列类型: 1111
错在我没有为变量指定类型,识别出来的类型为other,所以当这个字段为null时,插入不成功。解决办法是指定类型,比如#{roomInfo.roomLayer,jdbcType=VARCHAR}
这里我只将有可能为null值的字段指定,其他没管。
方法三
在数据库中创建一个临时表,将list插入数据库,再将原表和临时表进行merge into,最后将临时表的记录delete