一个 JPA 事物的问题,请大家一定要戳进来帮我看下,谢谢了! - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
palmers
V2EX    MySQL

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

  •  
  •   palmers 2014-06-10 22:21:37 +08:00 5197 次点击
    这是一个创建于 4153 天前的主题,其中的信息可能已经有所发展或是发生改变。
    是这样的:
    首先由两张表 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()方法中捕获异常 ,还可以接受 ,我在内部捕获异常且处理了 为什么还会回滚事物呢?

    之前想先查询 再插入,害怕中间的时间差导致 主键约束 所以采用这种方法,但是现在确实很多问题 只要重复就会失败
    请问这种问题应该如何解决???
    第 1 条附言    2014-06-11 14:58:39 +08:00
    部分异常信息:


    java.lang.RuntimeException: org.hibernate.exception.ConstraintViolationException: error executing work
    at com.sinosoft.one.data.jpa.repository.query.OneJadeRepositoryQuery.execute(OneJadeRepositoryQuery.java:42)
    at com.sinosoft.one.data.jpa.repository.support.OneRepositoryFactorySupport$OneQueryExecutorMethodInterceptor.invoke(OneRepositoryFactorySupport.java:338)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:91)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy537.tCorrespondSave(Unknown Source)
    第 2 条附言    2014-06-17 21:16:41 +08:00
    问题初步得到解决了! 在这里把问题解决方法记录下:
    简单说就是将两个事务分开就可以了,
    进一步说,即将事务标记到insert 操作 的DAO层,在service控制异常循环调用DAO层的数据库操作实现重新id的筛选,最后返回id更新B表. 至此在我看来问题确实得到了解决.

    这样就能实现JPA忽略异常事务回滚数据重新开始另一个事务了
    这样也就不会造成主键约束联动的外键约束异常了!
    9 条回复    2014-06-17 21:17:36 +08:00
    palmers
        1
    palmers  
    OP
       2014-06-10 22:23:32 +08:00
    哦对了 使用springmvc
    palmers
        2
    palmers  
    OP
       2014-06-11 09:16:26 +08:00
    @Livid 麻烦给看看 谢谢 !
    palmers
        3
    palmers  
    OP
       2014-06-11 10:49:43 +08:00
    @Livid 老大 能不能把我这个问题 移动到 技术节点?? 顺便 帮我看看这个问题 我实在是搞不定 非常感谢 !
    lszwycn
        4
    lszwycn  
       2014-06-11 13:08:42 +08:00
    因为JPA抛出的都是RuntimeException, 你只catch了Exception
    palmers
        5
    palmers  
    OP
       2014-06-11 14:47:57 +08:00
    @lszwycn Thank you ! 但是在getxxx 方法中我使用 Exception 确实捕获到了 然后也按照我的设想 进入了下一次循环 然后的到 id 但是在该方法调用处 却因为之前的 主键约束异常 被事务回滚了 ? 为什么??
    palmers
        6
    palmers  
    OP
       2014-06-11 14:51:44 +08:00
    @lszwycn 而且 Exception 是父类为什么会捕获不到呢?
    lszwycn
        7
    lszwycn  
       2014-06-11 22:17:23 +08:00
    按照JPA的规范, 如果一个数据库操作抛出了jpa的异常, 那么应该回滚, 关闭EM, 因为这时候, 已经不保证EM内部的状态了, 你这里, 如果我没理解错的话, 是在getxxx的方法里面抛出了异常了, 然后catch了之后, 有继续操作了EM
    palmers
        8
    palmers  
    OP
       2014-06-11 22:46:10 +08:00
    @lszwycn 是这样的 在getxxx 中有持久化操作且有异常catch 了之后 再次进行 持久化操作 ,

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

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

    你说的 EM 是指EntityManager吗? 那我说的关闭连接应该是不准确的吧 就想异常信息中描述的那样 被标记回滚了是吗? 然后再次操作数据表就不被执行 这么理解是正确的吗?
    palmers
        9
    palmers  
    OP
       2014-06-17 21:17:36 +08:00
    @lszwycn 问题找到具体的解决方案了 ,麻烦你帮我看看 是否存在隐患?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1062 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 23:07 PVG 07:07 LAX 16:07 JFK 19:07
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86