当前位置: 首页 > news >正文

【JavaEE】(22) Spring 事务

一、Spring 中事务的实现

        事务是一系列操作的集合,是原子的。要么都成功,要么都失败。比如转账:A账户-100,B账户+100,只有部分操作成功会导致业务逻辑错误。

1、准备工作

        创建数据库:

-- 创建数据库
DROP DATABASE IF EXISTS trans_test;CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;USE trans_test;-- 用户表
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR (128) NOT NULL,`password` VARCHAR (128) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '用户表';-- 操作日志表
DROP TABLE IF EXISTS log_info;
CREATE TABLE log_info (`id` INT PRIMARY KEY auto_increment,`user_name` VARCHAR ( 128 ) NOT NULL,`op` VARCHAR ( 256 ) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now() 
) DEFAULT charset 'utf8mb4';

        创建 Spring Boot 项目。引入依赖 Spring Web、MyBatis、MySQL驱动、lombok 工具。配置数据库连接、MyBatis 日志和驼峰自动转换。

        实体类:

package com.edu.spring.trans.demo.entity;import lombok.Data;import java.util.Date;@Data
public class UserInfo {private Integer id;private String userName;private String password;private Date createTime;private Date updateTime;
}package com.edu.spring.trans.demo.entity;import lombok.Data;import java.util.Date;@Data
public class LogInfo {private Integer id;private String userName;private String op;private Date createTime;private Date updateTime;
}

        mapper 插入一个用户:

package com.edu.spring.trans.demo.mapper;import com.edu.spring.trans.demo.entity.UserInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper {@Insert("insert into user_info(user_name, password) values(#{userName}, #{password})")Integer insert(UserInfo userInfo);
}

        service:

package com.edu.spring.trans.demo.service;import com.edu.spring.trans.demo.entity.UserInfo;
import com.edu.spring.trans.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public Integer register(UserInfo userInfo) {return userMapper.insert(userInfo);}
}

2、Spring 编程方式实现

package com.edu.spring.trans.demo.controller;import com.edu.spring.trans.demo.entity.UserInfo;
import com.edu.spring.trans.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowired// 事务管理器private DataSourceTransactionManager dataSourceTransactionManager;@Autowired// 事物的配置private TransactionDefinition transactionDefinition;@GetMapping("/register")public String register(UserInfo userInfo) {// 开启事务TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);// 注册用户Integer result = userService.register(userInfo);// 回滚事务
//        dataSourceTransactionManager.rollback(transactionStatus);// 提交事务dataSourceTransactionManager.commit(transactionStatus);return "注册成功 result=" + result;}
}

3、Spring 注解声明方式实现

        配置事务依赖:

<dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId>
</dependency>

        在事务类或方法上加注解 @Transactional,只对 public 修饰的方法生效

(1)程序正常执行,事务提交

(2)异常捕获,提交

(3)异常未捕获(Error、RuntimeException),回滚

        抛出了异常,才能识别到异常,才回滚。

(4)异常未捕获(受查异常),提交

(5)异常捕获又抛出,回滚

(6)希望异常捕获仍回滚,手动回滚

        希望触发异常时,就算捕获了,也不要提交。

二、@Transactional 详解

1、rollbackFor、noRollbackFor

2、isolation 事务的隔离级别

3、propagation 事务的传播机制

        当事务方法 A 调用事务方法 B 时,B 是加入 A 的事务还是需要开启新的事务,以及方法 B 抛出异常时对 A 事务是否存在影响,是由事务的传播机制决定。

        准备:事务方法 A 调用了事务方法 B 注册用户和事务方法 C 插入操作日志。

        以下级别是控制被调用事务(B、C 事务)。

(1)REQUIRED(*)

        默认事务传播级别。若存在事务 A,B 则加入;若不存在事务 A,B 则创建新事务

        ① 事务 B、C 共用方法 A 的事务,事务 C 抛出异常,导致整个事务回滚。

        ② 事务 A不存在,B 创建新事务。 B 抛出异常,会回滚

(2)SUPPORTS

        若 A 存在事务,B 则加入;A 不存在事务,B 以非事务方法运行。

        ① 事务 A 存在,与 REQUIRED 相同。

        ② 事务 A 不存在,直接调用事务 B,B 以非事务方式运行。B 抛出异常,不会回滚

(3)MANDATORY

        若 A 存在事务,B 则加入事务;若 A 不存在事务,B 则抛出异常。

(4)REQUIRES_NEW(*)

        不管 A 是否有事务,B 都创建新事务。

        A 存在事务,B 创建独立于 A 的新事务,B 抛出异常回滚,但 A 会提交。

(5)NOT_SUPPORTED

        不管 A 是否有事务,B 都以非事务方式运行。

        A 有事务,B 触发异常,B 会提交。

 

(6)NEVER

        若 A 存在事务,则抛出异常

(7)NESTED

        若 A 存在事务,B 创建 A 的嵌套事务;若 A 不存在事务,B 创建新事务。

(8)NESTED 和 REQUIRED 的区别

        在例子中,它们的部分事务发生异常时,所有事务都回滚了。

        但 NESTED 可以实现部分回滚(事务 C 发生异常后手动回滚,事务 B 就提交了),而 REQUIRED 只能全部回滚(事务 C 发生异常后手动回滚,会导致整个 A 事务回滚)。

http://www.xdnf.cn/news/1439029.html

相关文章:

  • 飞算JavaAI炫技赛:一天完成学生成绩综合统计分析系统开发(含源码)
  • 【Axure高保真原型】区间缩放柱状图
  • 数据结构从青铜到王者第二十话---Map和Set(3)
  • 漫谈《数字图像处理》之图像清晰化处理
  • 配置机载电脑开机自启动ros2节点和配置can0
  • 【第四章:大模型(LLM)】10.微调方法与实战-(1)Prompt Tuning
  • C++ 多线程编程
  • c++多线程(1)------创建和管理线程td::thread
  • logging:报告状态、错误和信息消息
  • 《用 Flask + SQLAlchemy 构建任务管理应用:从基础架构到实战优化》
  • 面试题:JVM与G1要点总结
  • 哪些AI生成PPT的软件或网站支持多平台使用?都支持哪些平台?
  • Linux之centos 系统常用命令详解(附实战案例)
  • 多路复用 I/O 函数——`select`函数解析
  • 一次惊心动魄的线上事故:记一次内存泄漏Bug的排查与解决全过程
  • 从一道面试题开始:如何让同时启动的线程按顺序执行?
  • Bug排查日记:从发现到解决的完整记录
  • 在word中使用lateX公式的方法
  • 力扣115:不同的子序列
  • Unity Android 文件的读写
  • Delphi 5 中操作 Word 表格时禁用鼠标交互
  • 更新远程分支 git fetch
  • 揭开PCB隐形杀手:超周期报废的技术真相
  • AI编码生产力翻倍:你必须掌握的沟通、流程、工具与安全心法
  • 一键掌握服务器健康状态与安全风险
  • 同步工具的底层依赖:AQS
  • Kubernetes 中为 ZenTao 的 Apache 服务器添加请求体大小限制
  • 如何开发一款高稳定、低延迟、功能全面的RTSP播放器?
  • 时序数据库选型指南:为何Apache IoTDB成为工业物联网首选
  • JVM分析(OOM、死锁、死循环)(JProfiler、arthas、jvm自带工具)