Spring中的事务

目录

事务的概念

事务是什么?

事务的作用?

Spring中事务是如何实现的?

[MySQL 中的事务使用](#MySQL 中的事务使用)

编程式事务

声明式事务

@Transactional

[@Transactional 作用范围](#@Transactional 作用范围)

[@Transactional 参数说明](#@Transactional 参数说明)

注意事项

事务的隔离级别

事务特性

为什么要设置事务的隔离级别?

mysql的事务隔离级别

[Spring 事务隔离级别有 5 种](#Spring 事务隔离级别有 5 种)

隔离级别设置

Spring事务传播机制

事务传播机制是什么?

为什么需要事务传播机制?

事务传播机制有7种


事务的概念

事务是什么?

事务就是将一组操作封装到一个执行单位,执行的时候要不全部成功,要不全部失败。

事务的作用?

**保证一组相关数据的一致性。**例如,转账的时候,接收方收到转账,账户内增加相应数额金钱,那么转账的这一方账户内的金钱就应该减少对应数额,增加的数额和减少的数额要一致。

Spring中事务是如何实现的?

MySQL 中的事务使用

事务在 MySQL 有 3 个重要的操作:开启事务、提交事务、回滚事务,它们对应的操作命令如下:

sql 复制代码
-- 开启事务
start transaction;
-- 业务执⾏
-- 提交事务
commit;
-- 回滚事务
rollback;

Spring 中的事务操作分为两类:

  1. 编程式事务(⼿动写代码操作事务)。

  2. 声明式事务(利⽤注解⾃动开启和提交事务)

编程式事务

Spring ⼿动操作事务和上⾯ MySQL 操作事务类似,它也是有 3 个重要操作步骤:

  1. 开启事务(获取事务)
  2. 提交事务。
  3. 回滚事务。

SpringBoot 内置了两个对象,DataSourceTransactionManager ⽤来获取事务、提交或回滚事务,⽽ TransactionDefinition 是事务的属性,在获取事务的时候需要将 TransactionDefinition 传递进去从⽽获得⼀个事务 TransactionStatus。

  • PlatformTransactionManager: 事务管理器(用来管理事务,包含事务的提交,回滚)
  • TransactionDefinition: 事务定义信息(事务传播行为、事务隔离级别、超时、只读属性、回滚规则)
  • TransactionStatus: 事务具体运行状态

代码实现:

java 复制代码
import com.example.springmybatisdemo.model.User;
import com.example.springmybatisdemo.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/trans")
public class TransactionalController {
    @Autowired
    private UserService userService;
    //获取一个事务管理器
    @Autowired
    private PlatformTransactionManager platformTransactionManager;
//    @Autowired
//    private DataSourceTransactionManager dataSourceTransactionManager;
    //获取一个事务
    @Autowired
    private TransactionDefinition transactionDefinition;

    @RequestMapping("/add")
    public Integer addUser(String username,String password){
        TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
        User user=new User(username,password);
        Integer result=userService.insert(user);
//事务回滚
        //platformTransactionManager.rollback(transaction);
//事务提交
        platformTransactionManager.commit(transaction);
        return result;

    }

声明式事务

声明式事务就是注解式事务。声明式事务的实现很简单,只需要在需要的⽅法上添加 @Transactional 注解就可以实现了,⽆需⼿动 开启事务和提交事务,进⼊⽅法时自动开启事务,方法执行完会自动提交事务,如果中途发生了没有处 理的异常会自动回滚事务,具体实现代码如下:

java 复制代码
import com.example.springmybatisdemo.model.User;
import com.example.springmybatisdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/trans2")
public class TranscationalController2 {
    @Autowired
    private UserService userService;
    @Transactional
    @RequestMapping("/add2")
    public Integer assUser(String username,String password){
        User user=new User(username,password);
        Integer result=userService.insert(user);
        return result;

    }
}

@Transactional

@Transactional 作用范围

@Transactional 可以⽤来修饰⽅法或类:

  • 修饰⽅法时:需要注意只能应用到 public⽅法上,否则不⽣效。推荐此种⽤法。
  • 修饰类时:表明该注解对该类中所有的 public 方法都⽣效

@Transactional 参数说明

参数的添加格式:

注意事项

@Transactional 在异常被捕获 的情况下,不会进⾏事务⾃动回滚。

@Transactional 默认只在遇到运行时异常和Error时才会回滚,非运行时异常不回滚,即Exception的子类中,只有RuntimeException及其子类会回滚。

因此一般都会加上参数:

事务的隔离级别

事务特性

事务有4 ⼤特性(ACID),原⼦性、持久性、⼀致性隔离性,简称为ACID。具体概念如下:

  • 原⼦性( Atomicity,或称不可分割性**)**:⼀个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中 间某个环节。事务在执⾏过程中发⽣错误,会被回滚(Rollback)到事务开始前的状态,就像这个 事务从来没有执⾏过⼀样。
  • ⼀致性( Consistency**)**:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写⼊的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以⾃发性地完成预定的⼯作
  • 持久性( Isolation,⼜称独⽴性**)**:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
  • 隔离性( Durability**)**:数据库允许多个并发事务同时对其数据进⾏读写和修改的能⼒,隔离性可以防⽌多个事务 并发执⾏时由于交叉执⾏⽽导致数据的不⼀致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串⾏化 (Serializable)。

这 4 种特性中,只有隔离性(隔离级别)是可以设置的。

为什么要设置事务的隔离级别?

设置事务的隔离级别是⽤来保障多个并发事务执⾏更可控,更符合操作者预期的。

事务的隔离级别 就是为了防止,其他的事务影响当前事务执行的⼀种策略。

mysql的事务隔离级别

1.READ UNCOMMITTED:读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提 交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,⽽未提交的数据可能会发⽣回 滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读。

  1. READ COMMITTED:读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据, 因此它不会有脏读问题。但由于在事务的执⾏中可以读取到其他事务提交的结果,所以在不同时间 的相同 SQL 查询中,可能会得到不同的结果,这种现象叫做不可重复读。

  2. REPEATABLE READ: **可重复读,是 MySQL 的默认事务隔离级别,**它能确保同⼀事务多次查询的结果⼀致。但也会有新的问题,⽐如此级别的事务正在执⾏时,另⼀个事务成功的插⼊了某条数据,但因为它每次查询的结果都是⼀样的,所以会导致查询不到这条数据,⾃⼰重复插⼊时⼜失败 (因为唯⼀约束的原因)。明明在事务中查询不到这条信息,但⾃⼰就是插⼊不进去,这就叫幻读 (Phantom Read)。

  3. SERIALIZABLE:序列化,事务最⾼隔离级别,它会强制事务排序,使之不会发⽣冲突,从⽽解决了脏读、不可重复读和幻读问题,但因为执⾏效率低,所以真正使⽤的场景并不多。

●脏读:⼀个事务读取到了另⼀个事务修改的数据之后,后⼀个事务⼜进⾏了回滚操作,从⽽导致 第⼀个事务读取的数据是错误的。

● 不可重复读:⼀个事务两次查询得到的结果不同,因为在两次查询中间,有另⼀个事务把数据修改了。

● 幻读:⼀个事务两次查询中得到的结果集不同,因为在两次查询中另⼀个事务有新增了⼀部分数 据。

Spring 事务隔离级别有 5 种

Spring 中事务隔离级别包含以下 5 种:

  1. Isolation.DEFAULT:以连接的数据库的事务隔离级别为主。
  2. Isolation.READ_UNCOMMITTED:读未提交,可以读取到未提交的事务,存在脏读。
  3. Isolation.READ_COMMITTED:读已提交,只能读取到已经提交的事务,解决了脏读,存在不可重 复读。
  4. Isolation.REPEATABLE_READ:可重复读,解决了不可重复读,但存在幻读**(MySQL默认级 别)。**
  5. Isolation.SERIALIZABLE:串行化,可以解决所有并发问题,但性能太低。

隔离级别设置

Spring 中事务隔离级别设置 @Transactional ⾥的 isolation 属性即可:

java 复制代码
@RequestMapping("/save")
@Transactional(isolation = Isolation.SERIALIZABLE)
public Object save(User user) {
 // 业务实现
}

Spring事务传播机制

事务传播机制是什么?

Spring 事务传播机制定义了多个包含了事务的⽅法,相互调⽤时,事务是如何在这些⽅法间进⾏传递的。

为什么需要事务传播机制?

事务隔离级别是保证多个并发事务执⾏的可控性的(稳定性的),⽽事务传播机制是保证⼀个事务在多个调用方法间的可控性(稳定性的)。

事务隔离级别:解决多个事务同时调用数据库的问题

事务传播机制解决的是⼀个事务在多个节点(⽅法)中传递的问题:

事务传播机制有7种

  1. Propagation.REQUIRED默认的事务传播级别,它表示如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。

  2. Propagation.SUPPORTS:如果当前存在事务,则加⼊该事务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。

  3. Propagation.MANDATORY:(mandatory:强制性)如果当前存在事务,则加⼊该事务;如果当 前没有事务,则抛出异常。

  4. Propagation.REQUIRES_NEW:表示创建⼀个新的事务,如果当前存在事务,则把当前事务挂 起。也就是说不管外部⽅法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部⽅法会新开 启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰。

  5. Propagation.NOT_SUPPORTED:以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。

  6. Propagation.NEVER:以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。

  7. Propagation.NESTED:如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。

代码示例(REQUIRED):

前提,连接了数据库,有两张表,一张user表存放用户信息,一张userLog表存放日志信息。数据库的实现方式为Mybatis实现。这里就不对Mybatis的进行过多赘述了,感兴趣戳(Mybatis的基本操作)这里放出准备工作的实现代码:

数据库对应的实体类:

java 复制代码
@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String photo;
    private Date createtime;
    private Date updatetime;


    public User() {
    }

    public User(String username) {
        this.username=username;
    }
}
java 复制代码
@Data
public class UserLog {
    private int id;
    private String username;
    private Date createtime;
    private Date updatetime;

    public UserLog() {
    }

    public UserLog( String username) {
        this.username = username;
    }
}

mapper接口:

java 复制代码
@Mapper
public interface UserLogMapper {

    @Insert("insert into userLog(username) values(#{username}) ")
    Integer insertLog(UserLog userLog);
}
java 复制代码
@Mapper
public interface UserMapper {
 @Insert("insert into userinfo(username) values(#{username})")
    Integer insert(User user);
}

serviceA:

java 复制代码
@Service
public class UserLogService {
    @Autowired
    private UserLogMapper userLogMapper;
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer insertLog(UserLog userLog){
        int a=10/0;
        return userLogMapper.insertLog(userLog);
    }
}

serviceB:

java 复制代码
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
 

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer insert(User user) {
        return userMapper.insert(user);
    }
}

controlC:

java 复制代码
@Slf4j
@RestController
@RequestMapping("/trans3")
public class TransactionalController3 {
    @Autowired
    private UserService userService;
    @Autowired
    private UserLogService userLogService;

    @Transactional(propagation = Propagation.REQUIRED)
    @RequestMapping("/add")
    public boolean addUserLog(){
        User user=new User("wangjunkai");
        //插入用户表
        userService.insert(user);
        //插入日志表
        UserLog userLog=new UserLog("王先生");
        Integer result=userLogService.insertLog(userLog);
        log.info(result.toString());
        return true;

    }

}

三者之间的关系相当于:

相关推荐
加油=^_^=5 分钟前
MySQL基础篇的补充
数据库·python·mysql
loveLifeLoveCoding10 分钟前
Java List sort() 排序
java·开发语言
草履虫·17 分钟前
【Java集合】LinkedList
java
AngeliaXue18 分钟前
Java集合(List篇)
java·开发语言·list·集合
世俗ˊ19 分钟前
Java中ArrayList和LinkedList的比较
java·开发语言
zhouyiddd24 分钟前
Maven Helper 插件
java·maven·intellij idea
攸攸太上32 分钟前
Docker学习
java·网络·学习·docker·容器
porkczr38 分钟前
oracle rac多个实例就相当于多个数据库系统程序
数据库·oracle
Milo_K40 分钟前
项目文件配置
java·开发语言
程序员大金44 分钟前
基于SpringBoot+Vue+MySQL的养老院管理系统
java·vue.js·spring boot·vscode·后端·mysql·vim