1.问题
1、以前对事物的了解只是停留在声明式事物,配置xml,或使用注解,事物的传播行为也只用过REQUIRED和SUPPORTS,可以说对事物的了解很模糊。
2、直到在开发中遇到问题。。
问题的描述是:
年底跑定时任务,获取用户年底过期积分,并发送积分即将过期的消息提示;
过期积分做记录,并与积分做关联记录,涉及两表的操作;
数据量较多,循环保存,要做到每次循环都会手动提交,而不是做缓存最后提交;
事物的传播行为为默认的REQUIRED,二两个表操作涉及到了嵌套事物;
So。。。
解决办法:
1声明式事物方式
@Transactional(propagation = Propagation.REQUIRES_NEW)
2采用了编程式事物
事物的传播行为选择为:PROPAGATION_REQUIRES_NEW
public boolean updateExpireCredit(Credit credit) throws Exception { // 事务开始-方法级别 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); // 传播行为: 新建事务,如果当前存在事务,把当前事务挂起 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); def.setTimeout(30); // 事务状态 TransactionStatus status = tm.getTransaction(def); boolean falg = false; try { creditRepository.save(credit); tm.commit(status); falg = true; } catch (Exception e) { e.printStackTrace(); log.error("出现异常,事务回滚:{}", e); if (!status.isCompleted()) { tm.rollback(status); } throw e; } return falg; }
2.事物的四个特性(ACID)
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
- 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
- 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
- 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
3.spring事物管理
PlatformTransactionManager
jdbc——org.springframework.jdbc.datasource.DataSourceTransactionManager
hibernate——HibernateTransactionManager
jpa——org.springframework.orm.jpa.JpaTransactionManager
java的jta——org.springframework.transaction.jta.JtaTransactionManager
4.事物属性
TransactionDefinition接口内容如下:
public interface TransactionDefinition { int getPropagationBehavior(); // 返回事务的传播行为 int getIsolationLevel(); // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据 int getTimeout(); // 返回事务必须在多少秒内完成 boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的 }
4.1传播行为
注:PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back.
4.2隔离级别
并发事务所导致的问题
在同一个应用程序或者不同应用程序中的多个事务在同一个数据集上并发执行时,可能会出现许多意外的问题。
并发事务所导致的问题可以分为以下三类:
① 脏读:脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
② 不可重复读:不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间更新了数据
③ 幻读:幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录
注:
不可重复读的重点是修改
幻读的重点在于新增或者删除
5.事物状态
PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一个实现,这个接口的内容如下:
public interface TransactionStatus{ boolean isNewTransaction(); // 是否是新的事物 boolean hasSavepoint(); // 是否有恢复点 void setRollbackOnly(); // 设置为只回滚 boolean isRollbackOnly(); // 是否为只回滚 boolean isCompleted; // 是否已完成 }
6.编程时事物和声明式事物
http://blog.didispace.com/springboottransactional/
https://blog.csdn.net/trigl/article/details/50968079#t7