深入Spring数据库事务管理
来源:互联网 发布:五轴联动数控机床编程 编辑:程序博客网 时间:2024/06/16 11:05
相关问题
一、@Transactional的失效问题
1.对于静态(static)方法和非public方法,注解@Transactional是失效的。
2.自调用,就是一个类的一个方法去调用自身另外一个方法的过程。如下:
@Autowiredprivate RoleDao roleDao;@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)public int insertRole(Role role){ return roleDao.insertRole(role);}@Override@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)public int insertRoleList(List<Role> roleList) { int count = 0; for (Role role:roleList) { try { //调用自身类的方法,产生自调用问题 insertRole(role); count++; }catch (Exception ex){ log.info(ex); } } return count;}分析:角色插入两次都使用的是同一事务,也就是说在insertRole方法上标注的@Transactional失效了。原因在于AOP的实现原理,这里不再赘述。
解决:①使用两个服务类。【推荐】
@Servicepublic class RoleServiceImpl implements RoleService { @Autowired private RoleDao roleDao; @Override @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED) public int insertRole(Role role) { return roleDao.insertRole(role); }}②从IOC容器中获取RoleService代理对象。【不推荐,从容器获取代理对象有侵入之嫌,我们需要依赖于SpringIOC容器】
@Override@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)public int insertRoleList(List<Role> roleList) { int count = 0; //从容器中获取RoleService对象,实际是一个代理对象 RoleService roleService = ctx.getBean(RoleService.class); for (Role role:roleList) { try { insertRole(role); count++; }catch (Exception ex){ log.info(ex); } } return count;}
二、典型错误用法
1.错误使用Service
场景:在一个Controller中插入两个角色,并且两个角色需要在同一个事务中处理。
错误代码:
public class RoleController { @Autowired private RoleService roleService; public void errorUseServices(){ Role role = new Role(); role.setRoleName("role_name_"); role.setNote("note_"); roleService.insertRole(role); Role role2 = new Role(); role2.setRoleName("role_name_2"); role2.setNote("note_2"); roleService.insertRole(role2); }}分析:如果这个service标注用@Transactional,那么它就会启用一个事务,而一个service方法完成后,它就会释放该事务,所以前后两个insertRole是在两个不同的事务中完成的。这样如果第一个插入成功了,第二个插入失败了,就会使数据库数据库数据不完全同时成功或者失败,可能产生严重的数据不一致的问题。
2.过长时间占用事务
场景:在插入角色后还需要操作一个文件,比如处理图片的上传之类的操作。
代码:
@Override@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)public int insertRole(Role role) { //return roleDao.insertRole(role); int result = roleDao.insertRole(role); //做一些与数据库无关的操作 doSomethingForFile(); return result;}分析:当insertRole方法结束后Spring才会释放数据库事务资源,也就是说要等到doSomethingForFile()方法执行完成后,返回result后才会关闭数据库资源。高并发情况下就会出现卡顿状态,甚至因得不到数据库资源而导致系统宕机。
解决:这个方法放在controller中执行
@RequestMapping("/addRole")@ResponseBodypublic Role addRole(Role role){ roleService.insertRole(role); //做一些与数据库无关的操作 doSomethingForFile(); return role;}
3.错误捕捉异常
场景:购买商品。其中ProductService是产品服务类,而TransactionService是记录交易信息,需求就是产品减库存和保存交易在同一个事务例,要么同时成功,要么同时失败。假设传播行为都是REQUIRED。
代码:
@Autowiredprivate ProductService productService;@Autowiredprivate TransactionService transactionService;@Override@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)public int doTransaction(TransactionBean trans){ int result = 0; try { //介绍库存 productService.decreaseStock(trans.getProductId, trans.getQuantity()); //如果介绍库存成功则保存记录 if(result>0){ transactionService.save(trans); } }catch (Exception ex){ //自行处理异常代码 //记录异常日志 log.info(ex); } return result;}分析:这里的问题是方法已经存在异常了,由于开发者不了解Spring的事务约定,在两个操作方法里面加入了自己的try.catch...语句,就可能发生这样的结果:当减少库存成功了,但是保存交易信息时失败而发生了异常。由于加入的try.catch...语句,Spring在数据库事务所约定的流程中再也得不到任何异常信息了,此时Spring就会提交事务,啊这样就出现了库存减少,而交易记录却没有的糟糕情况。
解决:在catch中自行抛出异常,这样在Spring的事务流程汇总,就会捕捉到这个异常,进行事务回滚。
@Autowiredprivate ProductService productService;@Autowiredprivate TransactionService transactionService;@Override@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)public int doTransaction(TransactionBean trans){ int result = 0; try { //介绍库存 productService.decreaseStock(trans.getProductId, trans.getQuantity()); //如果介绍库存成功则保存记录 if(result>0){ transactionService.save(trans); } }catch (Exception ex){ //自行处理异常代码 //记录异常日志 log.info(ex); //自行抛出异常,让Spring事务管理流程获取异常,进行事务管理 throw new RuntimeException(ex); } return result;}
阅读全文
0 0
- 深入Spring数据库事务管理
- 深入理解spring事务管理
- Spring 数据库事务管理
- spring 数据库事务管理
- 深入理解Spring的事务管理
- spring 不能插入数据库 事务管理
- Spring学习(4):Spring数据库事务管理
- 数据库事务 及 Spring 对 Hibernate 事务管理
- Spring的数据库操作和事务管理
- 事务管理之Spring事务管理
- spring 事务管理 1(使用spring的JdbcTemplate访问数据库)
- Spring JDBC-Spring事务管理之数据库事务基础知识
- 深入解读Spring Framework事务管理(第二弹:编程式事务管理的使用方式)
- 深入解读Spring Framework事务管理(第三弹:基于AspectJ的XML声明式事务管理)
- 深入解读Spring Framework事务管理(第四弹:基于@Transactional注解的声明式事务管理)
- Spring事务管理
- spring事务管理
- Spring事务管理
- sprintf() 格式化数字,小数位数,四舍五入
- IT行业的风投
- 关于 stm32 启动文件的总结
- 在windows系统下安装Ubuntu双系统
- anr 分析
- 深入Spring数据库事务管理
- JavaScript入门
- Jquery隐藏div 根据id
- Android6.0动态权限
- linux下安装python2.7
- go时间格式化必须精确地限定到 golang 指定的时间原点:2006-01-02 15:04:05
- (17)读取ini文件的键值对
- python变量和数据类型
- destoon 新建一个新模块