Spring Boot出现UnexpectedRollbackException事务回滚异常 无法删除MySQL数据
异常触发原因
- 核心原因是SQL语法错误:代码直接拼接字符串类型的查询条件,没有给字符串字段加单引号,生成的SQL不符合MySQL语法,执行时抛出
SQLGrammarException,该异常属于持久层运行时异常,会自动将当前事务标记为*rollback-only(仅回滚)*状态。 - 次要原因是异常被静默吞噬:业务代码捕获所有异常后没有任何处理也没有重新抛出,事务管理器在方法执行结束尝试提交事务时,发现事务已经被标记为仅回滚,因此抛出
UnexpectedRollbackException。 - 附加问题:DELETE类型的原生查询错误传入了实体类作为第二个参数,该参数仅用于SELECT语句的结果映射,删除操作不需要,也可能触发不必要的校验异常。
排查修复方案
- 修复SQL语法与注入风险
放弃直接拼接SQL的写法,改用参数绑定的方式传入查询条件,框架会自动处理字符串的引号转义,同时避免SQL注入风险。 - 完善异常处理逻辑
不要静默吞噬异常,至少要打印异常栈方便排查问题,若需要保留捕获逻辑,可以在捕获后主动抛出运行时异常触发事务正常回滚,或者手动设置事务返回状态。 - 修正原生查询写法
删除操作的原生查询不需要指定返回实体类,使用无结果映射参数的createNativeQuery重载方法即可。 - 调整HTTP请求方法
将接口的请求方法从GET改为DELETE,符合REST接口规范,避免爬虫、预加载等场景误触发删除操作。 - 快速验证方法
修改前可以先打印拼接后的完整SQL,放到MySQL客户端直接执行,即可快速确认语法错误的具体位置。
修复后代码示例
@Transactional @RequestMapping(value = {"/org/deleteqrcodepoint/{orgid}/{mobile}/{nameofqrcodepoint}"}, method= RequestMethod.DELETE) @ResponseBody public Object deleteteqrcodepoint(@PathVariable String orgid, @PathVariable String mobile, @PathVariable String nameofqrcodepoint) { Jsonmessageanddata jsondata = new Jsonmessageanddata(); try { // 使用占位符进行参数绑定 String deleteSql = "DELETE FROM orgmultipleqrcode WHERE orgid = ?1 AND mobile = ?2 AND nameofqrcodepoint = ?3"; Query query = manager.createNativeQuery(deleteSql); query.setParameter(1, orgid); query.setParameter(2, mobile); query.setParameter(3, nameofqrcodepoint); int affectedRows = query.executeUpdate(); jsondata.setSuccess(true); jsondata.setMsg("删除成功,共影响" + affectedRows + "条记录"); } catch (Exception e) { // 打印异常日志用于排查 e.printStackTrace(); jsondata.setSuccess(false); jsondata.setMsg("删除失败:" + e.getMessage()); // 若需要事务正常回滚可取消下方注释 // throw new RuntimeException("删除操作执行失败", e); } return jsondata; }
内容的提问来源于stack exchange,提问作者Am Ventures
相关产品推荐
相关产品推荐

