文章目录
- 1 @Transactional 注解特性
- 2 事务的属性
- 3 事务的嵌套
- 4 事务超时设置
- 5 @Transaction注解不回滚的可能原因
- 6 事务的基本要素(ACID)
- 7 事务的原理
- 8 数据并发问题
- 9 数据库隔离级别
- 10 Spring隔离级别
- 11 底层所使用的不同的持久化API或框架
1 @Transactional 注解特性
- 可以在整个类上添加@Transactional,会将整个类纳入Spring事务管理,在每个业务方法执行时都会开启一个事务,不过这些事务采用相同的管理方式。
- @Transactional 注解只能应用到 public 可见度的方法上。如果应用到protected、private可见度的方法上,也不会报错,但是事务不会起作用。
- 默认情况下,spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚。 即:出现的空指针等异常,会被回滚,文件读写,网络出问题不回滚。
java里面将派生于Error或者RuntimeException(比如空指针,除数为0)的异常称为unchecked异常,
其他继承自java.lang.Exception得异常统称为Checked Exception,如IOException、TimeoutException等
- 通常情况下,仅是读取数据时,不必设置只读事务而增加额外的系统开销。
2 事务的属性
- 1、REQUIRED(默认)
业务方法需要在一个容器里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,如果没有则新建一个自己的事务。
- 2、SUPPORTS
该方法在某个事务范围内被调用,则方法称为该事务的一部分。如果方法在该事务范围外被调用,则该方法就在没有事务的环境下执行。
- 3、MANDATORY
该方法只能在一个已存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出异常。
- 4、REQUIRED_NEW
不管是否存在事务,该方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。
- 5、NOT_SUPPORTED
声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,则该事务会被挂起,调用结束后,原先的事务会恢复执行。
- 6、NEVER
该方法绝对不能在事务范围内执行。如果在就抛出异常。只有该方法没有关联到任何事务,才正常执行。
- 7、NESTED
如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。
3 事务的嵌套
- 如果使用@Transaction方法里嵌套调用的是同一个类的方法,spring代理会忽略嵌套方法的@Transaction配置。如果是其他注入对象的方法,那么@Transaction配置就会生效。
- 调用方法是REQUIRED(默认),被调用方法是NERVER,则会抛出异常,事务不会生效,也不会回滚,数据库中的数据已被修改。
- 调用方法是NEVER,被调用方法是REQUIRED,会抛出异常。因为:++NERVER 不允许当前存在事务++
- REQUIRED子事务会影响当前事务的提交、回滚,具体体现在,一个方法中调用其他对象的方法,如果失败了,会导致整个方法回滚。
- NESTED子事务回滚不会影响当前事务的提交(catch回滚异常的情况下),但是当前事务回滚会回滚子事务。也就是说只有当前事务提交成功了,子事务才会提交成功。
- NESTED(嵌套事务)和REQUIRED_NEW(新的事务):假设都是在一个REQUIRED类型的事务里调用这些事务,该REQUIRED类型方法调用抛出异常,REQUIRED_NEW的方法仍然可以提交,但是NESTED还要受到REQUIRED事务回滚而被迫回滚。
- REQUIRES_NEW会启用一个新的事务,事务拥有完全独立的能力,它不依赖于当前事务,执行时会挂起当前事务,直到REQUIRES_NEW事务完成提交后才会提交当前事务,如果当前事务与REQUIRES_NEW 存在锁竞争,会导致死锁。
- NOT_SUPPORTED会挂起当前事务,并且NOT_SUPPORTED定义的方法内部不启用显示事务,如果NOT_SUPPORTED和当前事务存在锁竞争,会发生死锁。
- MANDATORY必须包含在事务中,如果事务不存在,则抛出异常。
4 事务超时设置
@Transactional(timeout=30) //默认是30秒
5 @Transaction注解不回滚的可能原因
- 检查方法是不是public的
- 检查异常类型是不是unchecked异常
如果想要check异常也回滚,在注解上写明异常类型即可:@Transactional(rollbackFor=Exception.class),类似的还有norollbackFor,自定义不回滚的异常。
- 数据库引擎要支持事务,如果是mysql,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的。
- 检查是否开启了对注解的解析
- 查看spring是否扫描到了这个包
6 事务的基本要素(ACID)
- 原子性(Atomicity):指一个事务的全部操作是一个整体,要么执行成功,要么执行失败。
- 一致性(Consistency):在事务执行前和执行完成后,数据完整性约束没有被破坏,完全符合所有预期。
- 隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读已提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
7 事务的原理
- 纯JDBC操作
- 先获取连接 Connection conn = DriverManager.getConnection()
- 开启事务 conn.setAutoCommit(true)
- 执行相关的SQL语句
- 提交或者回滚事务 conn.commit() conn.rollback()
- 关闭连接
- Spring事务管理
- 在相关的类或者方法上通过注解@Transactional标识。
- Spring在启动时回去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transactional的相关参数进行相关配置注入,通过代理的方式处理开启、提交、回滚事务。
- 真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
8 数据并发问题
- 脏读
事务T1正在操作一条数据,此时事务T2获取该条数据纪录,如果T1异常,事务回滚,T2读取到的数据就是脏数据,这种现象称为脏读。
- 不可重复读
事务T1多次读取某条记录,在读取间隔中,事务T2更新了该记录的数据,当T1再次读取该记录时,获取到的数据不一致,这种现象称为不可重复读。产生的原因主要是数据的更新,解决不可重复读只需要锁住满足条件的行。
- 幻读
事务T1批量处理多条记录,此时事务T2新增或删除了一条或多条记录,当T1处理完成,查询处理结果,会发现有记录没有处理(T2新增的)或者发现记录少了(T2删除的),会有一种幻觉的感觉,这种现象称为幻读。主要是数据的新增或删除导致,解决幻读需要锁表。
9 数据库隔离级别
隔离级别 | 隔离级别的值 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
读未提交 Read-Uncommitted | 0 | 是 | 是 | 是 |
读提交 Read-Committed | 1 | 否 | 是 | 是 |
可重复读 Repeatable-Read | 2 | 否 | 否 | 是 |
序列化 Serializable | 3 | 否 | 否 | 是 |
- 读未提交(Read-Uncommitted)
- 定义:就是一个事务读取到其他事务未提交的数据,是级别最低的隔离机制。
- 缺点:会产生脏读、不可重复读、幻读。
- 读提交(Read-Committed)
- 定义:就是一个事务读取到其他事务提交后的数据。SqlServer、Oracle默认隔离级别。
- 缺点:会产生不可重复读、幻读。
- 可重复读(Repeatable-Read)
- 定义:就是一个事务对同一份数据读取到的相同,不在乎其他事务对数据的修改。MySQL默认的隔离级别。
- 缺点:会产生幻读。
- 序列化(Serializable)
- 定义:事务串行化执行,隔离级别最高,牺牲了系统的并发性。
- 缺点:可以解决并发事务的所有问题。但是效率地下,消耗数据库性能,一般不使用。
10 Spring隔离级别
- ISOLATION_DEFAULT
PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
- ISOLATION_READ_UNCOMMITTED(读未提交)
同数据库的Read-Committed
- ISOLATION_READ_COMMITTED(读提交)
同数据库的Read-Committed
- ISOLATION_REPEATABLE_READ(可重复读)
同数据库的Repeatable-Read
- ISOLATION_SERIALIZABLE(序列化)
同数据库的Serializable
11 底层所使用的不同的持久化API或框架
- DataSourceTransactionManager
适用于使用JDBC和iBatis进行数据持久化操作的情况,在定义时需要提供底层的数据源作为其属性,也就是 DataSource
- HibernateTransactionManager
适用于使用Hibernate进行数据持久化操作的情况,与 HibernateTransactionManager 对应的是 SessionFactory
- JpaTransactionManager
适用于使用JPA进行数据持久化操作的情况,与 JpaTransactionManager 对应的是 EntityManagerFactory。