一个 JPA 事物的问题,请大家一定要戳进来帮我看下,谢谢了!

2014-06-10 22:21:37 +08:00
 palmers
是这样的:
首先由两张表 A . B
A表中有一个字段 主键id 在B表中是外键 且 这两个表被两个以上系统同时使用.

然后 流程中需要将生成四个 6位字符,挑选一个 A表不存在的字符添加到A表中。然后使用该字符关联数据到B表中.

大概方法结构是这样的:

@Transactional(rollbackFor=Exception.class,value="transactionManager")
xxx F ()throws Exception{
String enbleId=getxxx();//这里是循环将四个字符插入到A表 如果成功没有异常则使用该ID
updatexxx(enbleId); //在这里经过得到的有效id 更新到B表
}

getxxx()方法结果是这样的:

getxxx(){
//准备好四个6位的字符串数组 ids [];
for(String srcid : ids){
try{
//这里使用srcid insert 到A表如果异常 进入catch 进行下一次循环
//如果没有问题 break; 结束循环 返回这个 有效字符串到上面方法 F ()
return enbleid;
} catch(Exception e){
continue;
}
}
}


上面这种结果 ,会出现这样几个问题:

1. 当 在getxxx 方法中 只要有主键唯一约束异常存在则在F() 处被事物管控回滚 ,即使 我使用catch 处理 然后得到有效字符串 。也会回滚并且抛出异常。
2.在方法F ()中调用的getxxx 方法中一次生成的四个id 字符串 为了有效使用 依次插入 设想 异常 必定为主键惟一约束所以进入catch 进入下一轮循环,然后得到有效id insert 到A表 然后返回再更新到B表。
但是 并不是设想的那般, 当在getxxx 方法中存在依次主键约束异常,得到有效id后 回到F()方法都会被JPA事物拦截 回滚事物 然后导致B表不能更新抛出异常

请问这是为什么 ?
如果我在F()方法中捕获异常 ,还可以接受 ,我在内部捕获异常且处理了 为什么还会回滚事物呢?

之前想先查询 再插入,害怕中间的时间差导致 主键约束 所以采用这种方法,但是现在确实很多问题 只要重复就会失败
请问这种问题应该如何解决???
4824 次点击
所在节点    MySQL
9 条回复
palmers
2014-06-10 22:23:32 +08:00
哦对了 使用springmvc
palmers
2014-06-11 09:16:26 +08:00
@Livid 麻烦给看看 谢谢 !
palmers
2014-06-11 10:49:43 +08:00
@Livid 老大 能不能把我这个问题 移动到 技术节点?? 顺便 帮我看看这个问题 我实在是搞不定 非常感谢 !
lszwycn
2014-06-11 13:08:42 +08:00
因为JPA抛出的都是RuntimeException, 你只catch了Exception
palmers
2014-06-11 14:47:57 +08:00
@lszwycn Thank you ! 但是在getxxx 方法中我使用 Exception 确实捕获到了 然后也按照我的设想 进入了下一次循环 然后的到 id 但是在该方法调用处 却因为之前的 主键约束异常 被事务回滚了 ? 为什么??
palmers
2014-06-11 14:51:44 +08:00
@lszwycn 而且 Exception 是父类为什么会捕获不到呢?
lszwycn
2014-06-11 22:17:23 +08:00
按照JPA的规范, 如果一个数据库操作抛出了jpa的异常, 那么应该回滚, 关闭EM, 因为这时候, 已经不保证EM内部的状态了, 你这里, 如果我没理解错的话, 是在getxxx的方法里面抛出了异常了, 然后catch了之后, 有继续操作了EM
palmers
2014-06-11 22:46:10 +08:00
@lszwycn 是这样的 在getxxx 中有持久化操作且有异常catch 了之后 再次进行 持久化操作 ,

“按照JPA的规范, 如果一个数据库操作抛出了jpa的异常, 那么应该回滚, 关闭EM” 你这句话的意思 是不是这样的 :

我这里的getxxx 方法中 第一次主键约束异常发生,虽然我catch 了 也按照我的方式捕获到了异常, 进行下一次循环,但是这时候 已经关闭了A表连接,所以我虽然下次循环得到了有效的id 执行了 insert A表,但实际并没有持久化操作,导致后面更新B表的时候就发生外间不存在异常 然后事务回滚了
是这样的吗?

你说的 EM 是指EntityManager吗? 那我说的关闭连接应该是不准确的吧 就想异常信息中描述的那样 被标记回滚了是吗? 然后再次操作数据表就不被执行 这么理解是正确的吗?
palmers
2014-06-17 21:17:36 +08:00
@lszwycn 问题找到具体的解决方案了 ,麻烦你帮我看看 是否存在隐患?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/116779

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX