案列:项目中一个基础数据,在新增的时候,已经判断过唯一的字段内容不能重复了,但是在云环境上,测试出了bug,新增时产生了两条一模一样的数据,我在本地测试时也重现了问题,快速点击新增两下,会有bug出现。代码如下:
解决方法一:加锁,很自然的选择了加锁,又不要改sql,easy的很,然而刚开始把锁加到serviceImpl里面了,导致任何锁都没有效果,锁是执行了,但是事务没有commit,第二次查还是查不到插入后的数据,后来把锁加到了Controller层,解决了问题。但是经理说这样实现方式不好,没有通过。(加锁可以解决单个服务器的并发异常,但是多个服务器的话还是会出现并发异常)
解决方法二:修改sql。在insert的时候加上where条件。本来以为也很简单呢,结果也是试了几次,查了几次才成功。
先放上成功的代码:
INSERT INTO ba_tag (id, partner_id, tag_name,tag_property, del_flag, creator,create_time, modifier, modify_time,ip_address) SELECT #{baTag.id}, #{baTag.partnerId}, #{baTag.tagName}, #{baTag.tagProperty}, #{baTag.delFlag}, #{baTag.creator}, #{baTag.createTime}, #{baTag.modifier}, #{baTag.modifyTime},#{baTag.ipAddress} WHERE NOT EXISTS (SELECT tag_name FROM ba_tag WHERE tag_name = #{baTag.tagName})
之前几个失败的代码:
1,INSERT INTO ba_tag (id, partner_id, tag_name,tag_property, del_flag, creator,create_time, modifier, modify_time,ip_address) VALUES #{baTag.id}, #{baTag.partnerId}, #{baTag.tagName}, #{baTag.tagProperty}, #{baTag.delFlag}, #{baTag.creator}, #{baTag.createTime}, #{baTag.modifier}, #{baTag.modifyTime},#{baTag.ipAddress} WHERE #{baTag.tagName} NOT IN(SELECT tag_name FROM ba_tag WHERE tag_name = #{baTag.tagName})
2,INSERT INTO ba_tag (id, partner_id, tag_name,tag_property, del_flag, creator,create_time, modifier, modify_time,ip_address) VALUES #{baTag.id}, #{baTag.partnerId}, #{baTag.tagName}, #{baTag.tagProperty}, #{baTag.delFlag}, #{baTag.creator}, #{baTag.createTime}, #{baTag.modifier}, #{baTag.modifyTime},#{baTag.ipAddress} WHERE tag_naem != #{baTag.tagName},
正确代码WHERE前面可以加上FROM DUAL也是可以正确执行的。加上FROM DUAL的代码可以在mysql 和sqlserver中执行,但是在oracle中不可以正确执行。
另补充一下:如果在设计表的时候把对应字段添加唯一约束的话,就能省很多事了。
示例解释:
INSERT INTO 表(
//要插入的字段 id, partner_id, tag_name,tag_property, del_flag, creator,create_time, modifier, modify_time,ip_address )
SELECT
//要插入的值,不能带括号,否则Operand should contain 1 column(s)
#{baTag.id}, #{baTag.partnerId}, #{baTag.tagName}, #{baTag.tagProperty}, #{baTag.delFlag}, #{baTag.creator}, #{baTag.createTime}, #{baTag.modifier}, #{baTag.modifyTime},#{baTag.ipAddress}
FROM DUAL
//dual是为了构建查询语句而存在的表
WHERE NOT EXISTS(SELECT tag_name FROM ba_tag WHERE tag_name = #{baTag.tagName} )
//判断tagName相同的值是否存在,存在则不添加 NOT可以根据情况省略
sql 比对-正常插入语句和insert增加判定条件语句
insert into tablename( 属性1,属性2) values ('值1',‘值2’);
insert into tablename(属性1,属性2) select '值1','值2' from dual where exists (select 1 from tablename where 子句);