Open2

MySQLのINSERT ... ON ON DUPLICATE KEY UPDATE 構文実行時の返却値

sagittariussagittarius

INSERT ... ON DUPLICATE KEY UPDATE 構文

UPSERT処理を行う構文で、
指定したカラムでユニーク or 主キーに重複したものがあれば(既にレコードがあれば)更新処理を、
存在しなければ挿入処理を行う。
https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html

返却値

MySQLのINSERT構文は影響を受けた行数カウントを返すことが可能なので、
Mybatisのmapperなどで返却値としてint型が使える。

@Update("INSERT INTO user_info (user_id, name, email) "
        + "VALUES (#{userId}, #{name}, #{email}) AS t1"
        + "ON DUPLICATE KEY UPDATE "
        + "name = t1.name, "
        + "email = t1.email")
public int updateUserInfo(String userId, String name, String email);

公式ドキュメントの記載通り、

ON DUPLICATE KEY UPDATE を使用した場合、行ごとの影響を受けた行の値は、
その行が新しい行として挿入された場合は 1、
既存の行が更新された場合は 2、
既存の行がその現在の値に設定された場合は 0

となる。最後の0となる場合は既存の行との内容差分がなく実質更新不要という意味。

sagittariussagittarius

JDBCを通して呼ばれている場合、CLIENT_FOUND_ROWS フラグ がデフォルトで設定され、

既存の行がその現在の値に設定された場合は 0

のパターンにおいては0でなく1が返される。これを防ぐため、
MySQLのConnection URLでuseAffectedRows=trueにすることでCLIENT_FOUND_ROWS フラグ をキャンセルし、0が返されるようにできる。

参考

https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-connp-props-connection.html#cj-conn-prop_useAffectedRows

https://novoland.github.io/数据库/2015/08/17/INSERT ON DUPLICATE KEY UPDATE 几个要注意的问题.html

https://stackoverflow.com/questions/52242152/mysql-java-driver-returns-1-when-executing-on-duplicate-key-update-v-v