wordpress提交订单,青岛seo建站,医生做网站不违法,wordpress 获取分类链接在Spring中进行事务管理非常简单#xff0c;只需要在方法上加上注解Transactional#xff0c;Spring就可以自动帮我们进行事务的开启、提交、回滚操作。甚至很多人心里已经将Spring事务Transactional划上了等号#xff0c;只要有数据库相关操作就直接给方法加上Transactiona… 在Spring中进行事务管理非常简单只需要在方法上加上注解TransactionalSpring就可以自动帮我们进行事务的开启、提交、回滚操作。甚至很多人心里已经将Spring事务Transactional划上了等号只要有数据库相关操作就直接给方法加上Transactional注解。 /** * 代码片段1 */ Transactional(rollbackFor Exception.class) public void save(RequestBillDTO requestBillDTO){ //调用流程HTTP接口创建工作流 workflowUtil.createFlow(BILL,requestBillDTO); //转换DTO对象 RequestBill requestBill JkMappingUtils.convert(requestBillDTO, RequestBill.class); requestBillDao.save(requestBill); //保存明细表 requestDetailDao.save(requestBill.getDetail()) } 先通过http接口调用工作流引擎创建审批流然后保存而为了保证 操作的事务在整个方法上加上了Transactional注解仔细想想这样真的能保证事务吗 。 代码发布上线后系统开始出现了故障数据库监控平台一直收到告警短信数据库连接不足出现大量死锁日志显示调用流程引擎接口出现大量超时同时一直提示CannotGetJdbcConnectionException数据库连接池连接占满。在发生故障后我们尝试过杀掉死锁进程也进行过暴力重启只是不到10分钟故障再次出现。 我们知道Transactional 注解是使用 AOP 实现的本质就是在目标方法执行前后进行拦截。在目标方法执行前加入或创建一个事务在执行方法执行后根据实际情况选择提交或是回滚事务。 当 Spring 遇到该注解时会自动从数据库连接池中获取 connection并开启事务然后绑定到 ThreadLocal 上对于Transactional注解包裹的整个方法都是使用同一个connection连接 。如果我们出现了耗时的操作比如第三方接口调用业务逻辑复杂大批量数据处理等就会导致我们我们占用这个connection的时间会很长数据库连接一直被占用不释放。一旦类似操作过多就会导致数据库连接池耗尽。 在一个事务中执行RPC操作导致数据库连接池撑爆属于是典型的长事务问题 类似的操作还有在事务中进行大量数据查询业务规则处理等...
何为长事务
顾名思义就是运行时间比较长长时间未提交的事务也可以称之为大事务 。
长事务会引发哪些问题
长事务引发的常见危害有 数据库连接池被占满应用无法获取连接资源 容易引发数据库死锁 数据库回滚时间长 在主从架构中会导致主从延时变大。
如何避免长事务
解决长事务的宗旨就是 对事务方法进行拆分尽量让事务变小变快减小事务的颗粒度。
既然提到了事务的颗粒度我们就先回顾一下Spring进行事务管理的方式。
声明式事务
首先我们要知道通过在方法上使用Transactional注解进行事务管理的操作叫声明式事务 。
使用声明式事务的优点 很明显就是使用很简单可以自动帮我们进行事务的开启、提交以及回滚等操作。使用这种方式程序员只需要关注业务逻辑就可以了。
声明式事务有一个最大的缺点 就是事务的颗粒度是整个方法无法进行精细化控制。
与声明式事务对应的就是编程式事务 。基于底层的API开发者在代码中手动的管理事务的开启、提交、回滚等操作。在spring项目中可以使用TransactionTemplate类的对象手动控制事务。 private TransactionTemplate transactionTemplate; ... public void save(RequestBill requestBill) { transactionTemplate.execute(transactionStatus - { requestBillDao.save(requestBill); //保存明细表 requestDetailDao.save(requestBill.getDetail()); return Boolean.TRUE; }); }
使用编程式事务最大的好处就是可以精细化控制事务范围。
所以避免长事务最简单的方法就是不要使用声明式事务Transactional而是使用编程式事务手动控制事务范围。
有的同学会说Transactional使用这么简单有没有办法既可以使用Transactional又能避免产生长事务
那就需要对方法进行拆分将不需要事务管理的逻辑与事务操作分开 Service public class OrderService{ public void createOrder(OrderCreateDTO createDTO){ query(); validate(); saveData(createDTO); } //事务操作 Transactional(rollbackFor Throwable.class) public void saveData(OrderCreateDTO createDTO){ orderDao.insert(createDTO); } }
query()与validate()不需要事务我们将其与事务方法saveData()拆开。
当然这种拆分会命中使用Transactional注解时事务不生效的经典场景很多新手非常容易犯这个错误。Transactional注解的声明式事务是通过spring aop起作用的而spring aop需要生成代理对象直接在同一个类中方法调用使用的还是原始对象事务不生效。其他几个常见的事务不生效的场景为 “ Transactional 应用在非 public 修饰的方法上 Transactional 注解属性 propagation 设置错误 Transactional 注解属性 rollbackFor 设置错误 同一个类中方法调用导致Transactional失效 异常被catch捕获导致Transactional失效 ” 正确的拆分方法应该使用下面两种 可以将方法放入另一个类如新增 manager层通过spring注入这样符合了在对象之间调用的条件。 Service public class OrderService{ Autowired private OrderManager orderManager; public void createOrder(OrderCreateDTO createDTO){ query(); validate(); orderManager.saveData(createDTO); } } Service public class OrderManager{ Autowired private OrderDao orderDao; Transactional(rollbackFor Throwable.class) public void saveData(OrderCreateDTO createDTO){ orderDao.saveData(createDTO); } } 启动类添加EnableAspectJAutoProxy(exposeProxy true)方法内使用AopContext.currentProxy()获得代理类使用事务。 SpringBootApplication.java EnableAspectJAutoProxy(exposeProxy true) SpringBootApplication public class SpringBootApplication {} OrderService.java public void createOrder(OrderCreateDTO createDTO){ OrderService orderService (OrderService)AopContext.currentProxy(); orderService.saveData(createDTO); } 小结 使用Transactional注解在开发时确实很方便但是稍微不注意就可能出现长事务问题。所以对于复杂业务逻辑我这里更建议你使用编程式事务来管理事务当然如果你非要使用Transactional可以根据上文提到的两种方案进行方法拆分。