@Transactional 可以作用在接口、类、类方法
- 作用于类:当把@Transactional 注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息。
- 作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。
- 作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效
@Transactional注解属性
propagation:代表事务的传播行为,默认值为
Propagation.REQUIRED。
Propagation.REQUIRED:如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。( 也就是说如果A方法和B方法都添加了注解,在默认传播模式下,A方法内部调用B方法,会把两个方法的事务合并为一个事务 )
Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。
Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。( 当类A中的 a 方法用默认Propagation.REQUIRED模式,类B中的 b方法加上采用 Propagation.REQUIRES_NEW模式,然后在 a 方法中调用 b方法操作数据库,然而 a方法抛出异常后,b方法并没有进行回滚,因为Propagation.REQUIRES_NEW会暂停 a方法的事务 )
Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。
Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。
Propagation.NESTED :和 Propagation.REQUIRED 效果一样。
isolation :事务的隔离级别,默认值为
Isolation.DEFAULT。
- Isolation.DEFAULT:使用底层数据库默认的隔离级别。
- Isolation.READ_UNCOMMITTED:读未提交
- Isolation.READ_COMMITTED:读已提交
- Isolation.REPEATABLE_READ:可重复读
- Isolation.SERIALIZABLE:串行化
timeout :事务的超时时间,默认值为 -1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
readOnly :指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
rollbackFor :用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。当我们直接使用@Transactional不指定rollbackFor时,默认会回滚运行时异常及其子类,也就是RuntimeException及其子类,如果发生了Exception异常就不会回滚,因为Exception是RuntimeException的父类。
RuntimeException
和Exception
是Java中两种不同类型的异常。RuntimeException
是一种未检查异常(unchecked exception),它通常是由于程序中的逻辑错误导致的,例如空指针异常(NullPointerException
)或数组越界异常(ArrayIndexOutOfBoundsException
)。这类异常在编译时不需要被显式地捕获或声明,因为它们通常是可以避免的,如果出现了这类异常,通常意味着程序中存在bug。- 相比之下,
Exception
是一种已检查异常(checked exception),它通常表示程序运行时可能遇到的外部问题,如文件无法读取(IOException
)或数据库连接失败(SQLException
)。这类异常在编译时必须被处理,要么通过try-catch
语句块捕获异常,要么通过方法签名中的throws
关键字声明抛出异常。noRollbackFor:抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。
javax.transaction.Transactional与org.springframework.transaction.annotation.Transactional注解的差别
javax.transaction
和org.springframework.transaction
是两个不同的事务管理接口,它们分别属于Java EE和Spring框架transactionManager: Spring可以指定transactionManager,JTA不可以。
Isolation: Spring通过isolation属性提供了事务级别的隔离性,JTA隔离性只能控制在
connection级别。Propagation:两者都支持,Spring通过propagation指定,JTA通过value指定。Spring多了一个Nested传播类型。
Timeout:仅Spring支持。
Rollback: 都支持。 JTA通过rollbackOn和dontRollbackOn属性,Spring通过rollbackFor和noRollbackFor属性,并额外附加了2个属性rollbackForClassName和noRollbackForClassName。
@Transactional与 synchronized配合使用时遇到的问题:
- 问题描述:当t1线程访问getCount()方法,此时他拿到synchronized的锁,在进行获取数据并且+1操作后进行update操作,此时synchronized的锁已经被释放了,但是父事务却没有提交,也就是没有写回到数据库中,接下来t2线程过来了,也拿到了这把锁,又从数据库获取了数据,此时获得的是脏数据,最后就会导致出现了相同的code。
- 解决方法:这里是因为事务的先后提交导致,可以使用Transactional注解的配置来解决,使用@Transactional(propagation = Propagation.REQUIRES_NEW),每次都会启动一个新的事务,表示当前方法必须在自己的事务中运行,如果当前已经存在一个事务,则会挂起该事务,创建一个新的事务去执行当前方法。当当前方法执行完成后,新事务被提交,原事务恢复执行。