Spring 事务管理
一.事务:是正确执行一系列的操作(或动作),使得数据库从一种状态抓换成另一种状态,且保证操作保证全部成功,或者全部失败。(如银行取钱)
-
原则:
- 必须服从ISO/IEC所制定的原则
- ACID原则具体内涵如下:
- 原子性:即不分割性,事务要么全部被执行,要么就全部不被执行
- 一致性:事务的执行使数据库从一种正确状态转换成另一种正确状态
- 隔离性:在事务正确提交之前,它可能的结果不应显示给任何其它事务
- 持久性:事务正确提交之后,其结果将永久保存在数据库中
-
java事务:机制和原理就是确保数据库操作的ACID特性
- java事务的产生:程序操作数据库的需要,在java编写的程序或系统中,实现ACID的操作
- java事务实现范围:通过JDBC相应方法间接来实现对数据库的增删改查把事务转移到java程序代码中进行控制;确保事务要么全部执行成功,要么撤消不执行。
- java事务的实现:
- -通过java代码来实现对数据库的事务性操作。
- java事务类型:
- JDBC事务:用Connection对象控制,包括手动模式和自动模式(控制的局限性在一个数据库链接内,但其使用简单)
- JTA(Java Transaction API)事务:与实现无关的,与协议无关的API(功能强大,可跨越多个数据库或DAO,使用比较复杂)
- 容器事务:应用服务器提供的,且大多是基于JTA完成(通常基于JDNI的相当复杂的API实现)(主要指的是J2EE应用服务器提供的事务管理,局限与EJB)
-
Spring 事务接口:
-
Spring事务属性:理解成事务的一些基本配置,描述了事务策略如何应用到方法上,事务属性包含了5个方面
- 上面讲到的事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性
- 上面讲到的事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性
public interface TransactionDefinition {
int getPropagationBehavior(); // 返回事务的传播行为
// 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
int getIsolationLevel();
int getTimeout(); // 返回事务必须在多少秒内完成
boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
}
* 数据读取类型说明:并发事务引起的问题
* 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的
* 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新
* 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
* 事务隔离级别: 定义了一个事务受其它并发事务影响的程度
隔离级别 | 含义 |
---|---|
ISOLATION_DEFAULT | 使用后端数据库默认的隔离级别 |
ISOLATION_READ_UNCOMMITTED | 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 |
ISOLATION_READ_COMMITTED | 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 |
ISOLATION_REPEATABLE_READ | 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 |
ISOLATION_SERIALIZABLE | 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的 |
* 事务传播行为:当事务方法被另一个事务调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行
传播行为 | 含义 |
---|---|
PROPAGATION_REQUIRED | 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务 |
PROPAGATION_SUPPORTS | 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 |
PROPAGATION_NESTED | 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务 |
* 事务是否只读:事务的第三个特性是它是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。
* 事务超时:为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。
* 事务回滚:事务五边形的最后一个方面是一组规则,这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)
* 但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
- Spring事务状态:
- 事务接口:通过事务任务管理器获取TransactionStatus实例
控制事务在回滚或提交的时候需要应用对应的事务状态
spring事务接口:
//上面讲到的调用PlatformTransactionManager接口的getTransaction()的方法
//得到的是TransactionStatus接口的一个实现
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
二.编程式事务管理
- 编程式事务实现方式:
- 事务管理器(PlatformTransactionManager)方式
- 类似应用JTA UserTransaction API方式,但异常处理更简洁
- 核心类为:spring事务管理的三个接口类以及JdbcTemlate类
- 模板式(TransactionTemplate)的方式
- Spring官方团队推荐的编程式事务管理方法
- 主要工具为JdbcTemplate类
- 事务管理器(PlatformTransactionManager)方式