다중 insert시 PK중복인 데이터 update 처리
예전에 검색해서 알았는데도 잊어버려서 적어둔다. 기억력이란.. 자주 쓰지 않으면 역시 잊어버리는 듯.
일단 다중 insert문은 간단하다.
<insert id="insertData" parameterType="java.util.List">
insert into user (NICK, NAME, PHONE)
values
<foreach collection="list" item="item" separator=",">
(#{item.nick,jdbcType=VARCHAR}, #{item.phone,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR})
</foreach>
</insert>
여기서 NICK 이라는 PK가 중복 되었을 때, 다른 정보는 update를 시켜주고 싶다면?
일단 >on duplicate key update<가 생각날 것이다.
<insert id="insertData" parameterType="java.util.List">
insert into user (NICK, NAME, PHONE)
values
<foreach collection="list" item="item" separator=",">
(#{item.nick,jdbcType=VARCHAR}, #{item.phone,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR})
</foreach>
on duplicate key update PHONE = #{item.phone,jdbcType=VARCHAR}, NAME = #{item.name,jdbcType=VARCHAR}
</insert>
그렇다고 이런 식으로 작성하면 item이 foreach문에서만 유효한 지역변수이기 때문에 밖에서 사용할 수 없어 에러가 난다.
그렇다면 이건 어떻까?
<insert id="insertData" parameterType="java.util.List">
<foreach collection="list" item="item" separator=",">
insert into user (NICK, NAME, PHONE)
values
(#{item.nick,jdbcType=VARCHAR}, #{item.phone,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR})
on duplicate key update PHONE = #{item.phone,jdbcType=VARCHAR}, NAME = #{item.name,jdbcType=VARCHAR}
</foreach>
</insert>
옛날에는 이렇게도 해봤었지만.. 이제 그럴 연차는 아니니 그만두도록 하자.
정답은 valuse()였다.
예전에 구글링 했을 때 values()를 사용해야한다는 걸 봤는데 어디서 봤는지 찾을 수 없었다..
<insert id="insertData" parameterType="java.util.List">
insert into user (NICK, NAME, PHONE)
values
<foreach collection="list" item="item" separator=",">
(#{item.nick,jdbcType=VARCHAR}, #{item.phone,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR})
</foreach>
on duplicate key update PHONE = values(phone), NAME = values(name)
</insert>
이렇게 작성하게 되면 깔끔하게 실행된다.
참고 사이트
dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
opinionminer.blogspot.com/2012/10/mybatis-insert-multiple-rows-if-doesnt.html