8、SpringBoot 事务
系列导航
6、SpringBoot-mybatis分页实现pagehelper
9、SpringBoot-mybatis-druid多源数据多源数据
10、SpringBoot-mybatis-plus-druid多源数据
11、SpringBoot-mybatis-plus-druid多源数据事务
12、SpringBoot-mybatis-plus-ehcache
14、SpringBoot-easyexcel导出excle
完结
关于springBoot中的事务如何出里这里做了一些实验分享给大家
1数据库中创建表
oracle脚本
CREATE TABLE TEST_BLOCK_T
(
BLOCK_ID VARCHAR2(10 BYTE) PRIMARY KEY, --编码
BLOCK_NAME VARCHAR2(200 BYTE) --资源名称
);
2、pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.1.17.RELEASE</spring-boot.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <!-- oracle驱动 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency> <!-- 集成druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency> <!-- 集成mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.17.RELEASE</version>
<configuration>
<mainClass>com.example.demo.DemoApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> </project>
3、 application.properties配置
# 应用名称
spring.application.name=demo
# 应用服务 WEB 访问端口
server.port=8080 # 数据库设置
spring.datasource.driverClassName=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@192.168.0.100:1521:orcl
spring.datasource.username=zy
spring.datasource.password=1 # druid配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# druid参数调优(可选)
# 初始化大小,最小,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
# 测试连接
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters
spring.datasource.filters=stat
# asyncInit是1.1.4中新增加的配置,如果有initialSize数量较多时,打开会加快应用启动时间
spring.datasource.asyncInit=true #mybatis-plus控制台打印sql
mybatis-plus.configuration.log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4、文件目录
5、源码
启动类
注意要开启事务@EnableTransactionManagement
package com.example.demo; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication
@EnableTransactionManagement
@MapperScan("com.example.demo.mapper")
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} }
数据连接配置类
package com.example.demo.config; import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import javax.sql.DataSource;
import java.sql.SQLException; @Configuration
public class DruidConfig {
private Logger logger = LoggerFactory.getLogger(DruidConfig.class); @Value("${spring.datasource.url}")
private String dbUrl; @Value("${spring.datasource.username}")
private String username; @Value("${spring.datasource.password}")
private String password; @Value("${spring.datasource.driver-class-name}")
private String driverClassName; @Value("${spring.datasource.initial-size}")
private int initialSize; @Value("${spring.datasource.min-idle}")
private int minIdle; @Value("${spring.datasource.max-active}")
private int maxActive; @Value("${spring.datasource.max-wait}")
private int maxWait; @Value("${spring.datasource.time-between-eviction-runs-millis}")
private int timeBetweenEvictionRunsMillis; @Value("${spring.datasource.min-evictable-idle-time-millis}")
private int minEvictableIdleTimeMillis; // @Value("${spring.datasource.validation-query}")
// private String validationQuery; @Value("${spring.datasource.test-while-idle}")
private boolean testWhileIdle; @Value("${spring.datasource.test-on-borrow}")
private boolean testOnBorrow; @Value("${spring.datasource.test-on-return}")
private boolean testOnReturn; @Value("${spring.datasource.pool-prepared-statements}")
private boolean poolPreparedStatements; @Value("${spring.datasource.max-pool-prepared-statement-per-connection-size}")
private int maxPoolPreparedStatementPerConnectionSize; @Value("${spring.datasource.filters}")
private String filters; @Bean //声明其为Bean实例
@Primary //在同样的DataSource中,首先使用被标注的DataSource
public DataSource dataSource(){
DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName); //configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("druid configuration initialization filter", e);
}
// datasource.setConnectionProperties(connectionProperties); return datasource;
}
}
controller类
package com.example.demo.controller; import com.example.demo.service.TransActionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/hello")
public class TransActionController { @Autowired
TransActionService transActionService; @GetMapping("/test1")
@ResponseBody
public String test1() {
transActionService.test1();
return "success";
} @GetMapping("/test2")
@ResponseBody
public String test2() {
transActionService.test2();
return "success";
} @GetMapping("/test3")
@ResponseBody
public String test3() {
transActionService.test3();
return "success";
} @GetMapping("/test3_1")
@ResponseBody
public String test3_1() {
transActionService.test3_1();
return "success";
} @GetMapping("/test4")
@ResponseBody
public String test4() {
transActionService.test4();
return "success";
}
}
实体类
package com.example.demo.domain; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; /**
* <p>
* 。
* </p>
*
* @author yc
* @since 2021-09-18
*/
@TableName(value = "TEST_BLOCK_T")
public class Block {
private static final long serialVersionUID = 1L; @TableId
private String blockId;
/**
* $field.comment。
*/
private String blockName; public String getBlockId() {
return blockId;
} public void setBlockId(String blockId) {
this.blockId = blockId;
} public String getBlockName() {
return blockName;
} public void setBlockName(String blockName) {
this.blockName = blockName;
} @Override
public String toString() {
return "XyDicBlockT{" +
"blockId='" + blockId + '\'' +
", blockName='" + blockName + '\'' +
'}';
}
}
mapper类
package com.example.demo.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.domain.Block; public interface BlockMapper extends BaseMapper<Block> { }
service类
package com.example.demo.service; import com.example.demo.domain.Block;
import com.example.demo.mapper.BlockMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport; import java.sql.SQLException; @Service
public class TransActionService { //SpringBoot在使用事物Transactional的时候,要在main方法上加上 @EnableTransactionManagement
// 注解开发事物声明,在使用的service层的公共方法加上 @Transactional (spring)注解。 @Autowired
BlockMapper BlockMapper; @Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition; //那么首先我们来看下 @Transactional 这个注解的使用方法吧,只需要你在需要添加公共方法上面添加该注解即可。
// 但是这么使用的话需要你将异常抛出,由spring进行去控制。
@Transactional
public void test1() {
Block block1 = new Block();
block1.setBlockId("1");
BlockMapper.insert(block1); Block block2 = new Block();
block2.setBlockId("1");
BlockMapper.insert(block2);
} //如果我们在使用事物 @Transactional 的时候,想自己对异常进行处理的话,那么我们可以进行手动回滚事物。
// 在catch中加上 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
// 方法进行手动回滚。不过需要注意的是发生异常需要第一时间进行手动回滚事物,也就是要在异常抛出之前!
@Transactional
public boolean test2() {
try {
Block block1 = new Block();
block1.setBlockId("1");
BlockMapper.insert(block1); Block block2 = new Block();
block2.setBlockId("1");
BlockMapper.insert(block2);
} catch (Exception e) {
System.out.println("发生异常,进行手动回滚!");
// 手动回滚事物
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
e.printStackTrace();
}
return false;
} //如果我们在使用事物 @Transactional 的时候,调用了其他的子方法进行了数据库的操作,
//但是我们想使其事物生效的话,我们可以使用rollbackFor注解或者将该子方法的异常抛出由调用的方法进行处理,
//不过这里需要注意的是,子方法也必须是公共的方法!
@Transactional
public boolean test3() {
try {
deal1();
deal2();
} catch (Exception e) {
System.out.println("发生异常,进行手动回滚!");
// 手动回滚事物
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
e.printStackTrace();
}
return false;
} public void deal1() throws SQLException { Block block = new Block();
block.setBlockId("1");
BlockMapper.insert(block);
System.out.println("执行方法deal1:"); } @Transactional(rollbackFor = SQLException.class)
public void deal2() { Block block = new Block();
block.setBlockId("1");
BlockMapper.insert(block);
System.out.println("执行方法deal2:");
} //这样写经过测试事务也是生效的。好像子方法里不加throws SQLException 和 @Transactional(rollbackFor = SQLException.class) 事务也是生效的
@Transactional
public boolean test3_1() {
deal1_1();
deal2_1();
return false;
} public void deal1_1() {
Block block = new Block();
block.setBlockId("1");
BlockMapper.insert(block);
System.out.println("执行方法deal1_1:");
} public void deal2_1() {
Block block = new Block();
block.setBlockId("1");
BlockMapper.insert(block);
System.out.println("执行方法deal2_1:");
} //----------------------------------- // 如果我们不想使用事物 @Transactional 注解,想自己进行事物控制(编程事物管理),控制某一段的代码事物生效,
// 但是又不想自己去编写那么多的代码,那么可以使用springboot中的DataSourceTransactionManager和TransactionDefinition这两个类来结合使用,
// 能够达到手动控制事物的提交回滚。不过在进行使用的时候,需要注意在回滚的时候,要确保开启了事物但是未提交,
// 如果未开启或已提交的时候进行回滚是会在catch里面发生异常的!
public boolean test4() {
/*
* 手动进行事物控制
*/
TransactionStatus transactionStatus=null;
boolean isCommit = false;
try {
transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); // 进行新增/修改
Block block1 = new Block();
block1.setBlockId("1");
BlockMapper.insert(block1); Block block2 = new Block();
block2.setBlockId("1");
BlockMapper.insert(block2);
//手动提交
dataSourceTransactionManager.commit(transactionStatus);
isCommit= true;
System.out.println("手动提交事物成功!"); } catch (Exception e) {
//如果未提交就进行回滚
if(!isCommit){
System.out.println("发生异常,进行手动回滚!");
//手动回滚事物
dataSourceTransactionManager.rollback(transactionStatus);
}
e.printStackTrace();
}
return false;
} }
6、启动项目测试项目
1、测试1-1
(1)TEST_BLOCK_T中数据清空
(2)TransActionService中test1()注销掉@Transactional
//@Transactional
public void test1()
postman中执行
代码报主键冲突,但是数据库里有一条数据,说明该方法没有事务
2、测试1-2
(1)TEST_BLOCK_T中数据清空
(2)TransActionService中test1()增加@Transactional
@Transactional
public void test1()
postman中执行
代码报主键冲突,数据库一条数据也没有,说明事务生效
其他几个测试差不多就不重复了。自己看代码实验,代码里注释还比较清晰
8、SpringBoot 事务的更多相关文章
- 【原创】003 | 搭上基于SpringBoot事务思想实战专车
前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍 该趟专车是开往基于Spring Boot事务思想实战的专车,在上一篇 搭 ...
- 【原创】004 | 搭上SpringBoot事务诡异事件分析专车
前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本专车系列文章 目前连载到第四篇,本专题是深入讲解Springboot源码,毕竟是 ...
- SpringBoot学习笔记(三):SpringBoot集成Mybatis、SpringBoot事务管理、SpringBoot多数据源
SpringBoot集成Mybatis 第一步我们需要在pom.xml里面引入mybatis相关的jar包 <dependency> <groupId>org.mybatis. ...
- java事务/springboot事务/redis事务
java事务(数据库事务):jdbc事务--ACID springboot事务:@Transactional--ACID redis事务:命令集合 将redis事务与mysql事务对比: Mysq ...
- springboot 事务创建流程源码分析
springboot 事务创建流程源码分析 目录 springboot 事务创建流程源码分析 1. 自动加载配置 2. InfrastructureAdvisorAutoProxyCreator类 3 ...
- springboot事务的传播行为和隔离级别
springboot事务的传播行为和隔离级别 在springboot中事务的传播行为和隔离级别都是在TransactionDefinition这个接口中定义的 传播行为定义了7种,分别用0-6来表示 ...
- springboot 事务执行全流程分析
springboot 事务执行全流程分析 目录 springboot 事务执行全流程分析 1. 事务方法执行前的准备工作 2. 业务代码的调用 3. 事务方法执行后处理 4. 业务代码在事务和非事务中 ...
- 第六章 springboot + 事务(转载)
本篇博客转发自:http://www.cnblogs.com/java-zhao/p/5350106.html 在实际开发中,其实很少会用到事务,一般情况下事务用的比较多的是在金钱计算方面. myba ...
- 第六章 springboot + 事务
在实际开发中,其实很少会用到事务,一般情况下事务用的比较多的是在金钱计算方面. mybatis与spring集成后,其事务该怎么做?其实很简单,直接在上一节代码的基础上在相应的方法(通常是servic ...
- SpringBoot事务注解@Transactional
SpringBoot提供了非常方便的事务操作,通过注解就可以实现事务的回滚,非常方便快捷,下面我们就说一下如何进行事务操作. 1. 事务说明 在Spring中,事务有两种实现方式,分别是编程式事务管理 ...
随机推荐
- Net 高级调试之十二:垃圾回收机制以及终结器队列、对象固定
一.简介 今天是<Net 高级调试>的第十二篇文章,这篇文章写作时间的跨度有点长.这篇文章我们主要介绍 GC 的垃圾回收算法,什么是根对象,根对象的存在区域,我们也了解具有析构函数的对象是 ...
- [USACO2022OPENS] Visits
题目描述 Bessie 的 \(N\)(\(2\le N\le 10^5\))个奶牛伙伴(编号为 \(1\cdots N\))每一个都拥有自己的农场.对于每个 \(1\le i\le N\),伙伴 i ...
- ubuntu安装cudnn
有些忙,这一段时间,博客就随便写写了--- 默认cuda安装好了,这里就不多说了,我们从cuda的环境变量开始说起: 配置cuda环境变量: 打开终端,输入"gedit ~/.bashrc& ...
- MongoDB中的分布式集群架构
MongoDB 中的分布式集群架构 前言 Replica Set 副本集模式 副本集写和读的特性 Sharding 分片模式 分片的优势 MongoDB 分片的组件 分片键 chunk 是什么 分片的 ...
- 16、strconv
1.strconv是什么? strconv是用来处理字符串和基本类型之间的转换的 2.strconv的使用 /** * @author ly (个人博客:https://www.cnblogs.com ...
- Git日志的相关操作
显示日志 最单纯的日志命令 git log 单条显示 git log -条数 # 例如 git log -2 显示两条 提交信息单行输出 git log --oneline 日志图表显示 git lo ...
- jenkins安装部署、主从架构、slave镜像、K8S对接
介绍 CI/CD工具,自动化持续集成和持续部署,用于构建各种自动化任务. 官方提供了docker镜像https://hub.docker.com/r/jenkins/jenkins 使用Deploym ...
- 文件不落地上线sliver
接着二开sliver,给他添加一个生成powershell payload上线的功能,生成并复制到剪切板. 准备 首先,先开启监听,不多说直接mtls默认的就行,sliver可以生成配置文件来实现 ...
- Docker本地部署Firefox火狐浏览器并远程访问
Docker本地部署Firefox火狐浏览器并远程访问 Firefox是一款免费开源的网页浏览器,由Mozilla基金会开发和维护.它是第一个成功挑战微软Internet Explorer浏览器垄断地 ...
- 文心一言 VS 讯飞星火 VS chatgpt (127)-- 算法导论11.2 2题
二.用go语言,位向量(bit vector)是一个仅包含0和1的数组.长度为m的位向量所占空间要比包含m个指针的数组少得多.请说明如何用一个位向量来表示一个包含不同元素(无卫星数据)的动态集合.字典 ...