使用JetBrains Exposed操作MySQL时如何获取insertIgnore执行结果
Exposed中insertIgnore语句获取MySQL原生影响行数的方案
核心原因
之前两次执行拿到无差异的返回值,本质是Exposed对insertIgnore的默认封装设计:
- 常规
insertIgnore{}链式调用返回的是SQL语句构建/执行实例,默认设计目标是返回表的生成自增主键,并未主动把JDBC层透传的MySQL执行状态(也就是insertIgnore特有的0/1影响行数)暴露给上层调用者 - 两次执行的底层数据库返回值其实存在差异,只是没被当前的代码逻辑捕获到,不存在封装层丢失执行结果的问题
可直接落地的实现方式
- 适配Exposed内置API的标准写法
直接调用执行实例的*executeUpdate()*方法获取JDBC透传的原生影响行数,完全匹配MySQL对insertIgnore的返回规则:
配置transaction(database) { val affectedRows = MyTable.insertIgnore(returning = false) { it[uniqueColumn] = "foo" }.executeUpdate() // affectedRows 即为需要的结果:插入成功返回1,唯一键冲突被忽略返回0 }returning = false是为了关闭不必要的主键回读逻辑,减少数据库交互开销,对获取影响行数没有任何影响。 - 低版本Exposed兼容方案
如果使用的Exposed版本较老,没有暴露executeUpdate()方法,可以直接借助事务块内置的原生JDBC执行能力拿到结果,该写法对所有兼容的数据库版本都适用:transaction(database) { val sql = "INSERT IGNORE INTO ${MyTable.tableName} (${MyTable.uniqueColumn.name}) VALUES (?)" val affectedRows = exec(sql, listOf("foo")) { preparedStmt -> preparedStmt.executeUpdate() } }
避坑提示:不要试图通过
returning子句的返回集判断插入是否成功。当insertIgnore因为唯一键冲突被触发时,returning子句不会返回任何行,这种判断逻辑仅适用于带自增主键的表,适用场景远不如直接读取影响行数全面。MySQL 5.7下的insertIgnore影响行数规则是数据库原生行为,只要拿到JDBC透传的执行返回值,就和客户端直接执行语句的结果完全一致,不存在语言层适配偏差。
内容的提问来源于stack exchange,提问作者stschmitt
相关产品推荐
相关产品推荐

