Spring @Transactional 事务注解

一、spring 事务注解

1、实现层(方法上加)

java 复制代码
import org.springframework.transaction.annotation.Transactional;


@Transactional(rollbackFor = Exception.class)
    public JsonResult getRtransactional() {



    // 手动标记事务回滚
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

二、事务特性

1、@Transactional注解是用于事务控制的

需要知道事务的 ACID 特征:

  • 原子性(Atomicity,或称不可分割性)
  • 一致性(Consistency)
  • 隔离性(Isolation,又称独立性)
  • 持久性(Durability)

事务是用来控制数据的 ACID 特性的,用于保证数据的正确性和完整性。

2、@Transactional注解有两种使用方式:

  • 标注在类上面:当作用于类上时,该类的所有public方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
  • 标注在方法上面:当作用于方法上时,只有当该方法发生了异常才会进行回滚,其他的方法不受影响。

在项目中使用,@Transactional(rollbackFor=Exception.class),如果类加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。

在@Transactional注解中如果不配置rollbackFor属性,那么事物只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚。

三、事务传播行为与隔离级别

@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)

1、事物传播行为介绍:

2、事物超时设置:

java 复制代码
@Transactional(timeout=30) //默认是30秒

3、事务隔离级别:

java 复制代码
// 读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_UNCOMMITTED)

// 读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.READ_COMMITTED)

// 可重复读(会出现幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ)

// 串行化
@Transactional(isolation = Isolation.SERIALIZABLE):
    
// MYSQL: 默认为REPEATABLE_READ 可重复读 级别
// SQLSERVER: 默认为READ_COMMITTED 读取已提交数据  

**脏读 :**一个事务读取到另一事务未提交的更新数据。

**不可重复读 :**在同一事务中,多次读取同一数据返回的结果有所不同,即后续读取可能读到另一事务已提交的更新数据, 相反,

**可重复读:**在同一事务中多次读取数据时能够保证所读数据一样,即后续读取不能读到另一事务已提交的更新数据。

幻读 **:**一个事务读到另一个事务已提交的insert数据。

四、spring支持 编程式事务管理 和 声明式事务管理 两种方式

1、编程式事务管理使用 TransactionTemplate 或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring 推荐使用 TransactionTemplate。

2、声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务管理也有两种常用的方式:一种是基于tx和aop名字空间的xml配置文件;另一种是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

使用注解形式的方式使用事务需要在xml配置文件中配置如下信息

XML 复制代码
<!-- 服务事务管理 -->
<bean id="demoTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="demoDataSource"/>
</bean>
 <!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="demoTransactionManager"/>

五、需要注意的几点如下

1、@Transactional 注解只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能。

2、用 spring 事务管理器,由 spring 来负责数据库的打开、提交、回滚,默认遇到运行期异常(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的异常时执行回滚;而遇到需要捕获的异常(throw new Exception("注释");)不会回滚,即遇到受检查的异常(就是非运行时抛出的异常,编译器会检查到的异常叫受检异常)时,需要我们指定方式来让事务回滚。如果要想所有异常都回滚,则要加上@Transactional( rollbackFor=Exception.class),

如果让unchecked异常不回滚: @Transactional(notRollbackFor=RunTimeException.class)。如下代码所示:

java 复制代码
@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
public void methodName() {
   throw new Exception("注释");
}
@Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
public ItimDaoImpl getItemDaoImpl() {
   throw new RuntimeException("注释");
}

3、@Transactional 注解应该只被应用到public可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不具有事务功能。

4、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅是一种元数据,能够被可以识别。上面的例子中,其实正是元素的出现开启了事务行为。也就是说要有具体的 bean 出现时事务才会起作用。

5、Spring 团队建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别。因此,请接受 Spring 团队的建议,必须接受啊!

六、@Transactional注解所具有的属性

七、事务可能导致锁表

事务有可能导致锁表,从而导致查询操作超时。锁表的原因是多个事务同时操作某一张表。

mysql事务锁表参考博文:MySQL 死锁-CSDN博客

(mysql事务锁表导致查询超时)

mysql中主要是注意以下三张表:

sql 复制代码
select * from information_schema.INNODB_LOCKS;
select  * from information_schema.INNODB_LOCK_WAITS;
select * from information_schema.INNODB_TRX;
相关推荐
魔道不误砍柴功1 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2341 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨1 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟3 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity4 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天4 小时前
java的threadlocal为何内存泄漏
java
caridle4 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^4 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋34 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花4 小时前
【JAVA基础】Java集合基础
java·开发语言·windows