A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 superhi 于 2018-10-19 09:09 编辑

最近学习了ssm框架,在学习spring的时候,有讲到jdk代理,然后做了一个银行转账的案例,在该案例里面使用了jdk代理对转账的功能进行事务控制,即转账人账户扣钱和收账人账户加钱需要同时成功或者同时失败。该案例我使用的是纯注解方式来做的,我在debug时发现,单步调试的结果和直接运行的结果不一致,单步调试的时候,会发现转账功能在出现异常的情况下,回滚会失败。
测试类:


动态代理类:


被代理类:


直接运行时,程序是正常的,会进行回滚,即转账人不会扣钱,收账人不会收到钱。但当断点打在动态代理类上,进行单步调试则不行,然后我在动态代理类上添加了打印方法名称的语句,即打印被代理的方法名称,然后进行单步调试,会发现控制台不止打印了transfer方法, 还打印了toString方法。
控制台输出(debug):

控制台输出(run):


原因:代理类会代理AccountServiceImpl类的所有方法包括toString方法,单步调试时IDEA会调用被代理类的toString方法。但是为什么调用了toString会导致transfer异常时回滚失败呢?是因为该案例的事务控制是通过使用TheadLoacl对象把Connection和当前线程绑定,从而使一个线程中只能有一个能控制事务的连接对象。而toString方法在transfer方法被调用之前调用的,在transfer方法出异常回滚之前,已经执行了transcationManager.release()方法,将连接释放并且与线程解绑,这就导致transfer方法出异常进行回滚时会失败,因为事务开始时使用的连接和回滚时使用的连接不是同一个连接,于是导致回滚失败,即转账人的钱扣了,但是收账人并没有收到钱。

7 个回复

倒序浏览
厉害了,大神
回复 使用道具 举报
大神
回复 使用道具 举报
加油大神
回复 使用道具 举报
加油,加油
回复 使用道具 举报
大神加油
回复 使用道具 举报
加油   努力   做更好的自己
回复 使用道具 举报
大神
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马