(1)序列化
同一时间只能有一个事务执行,所有事务串行执行
(2)可重复读
InnoDB引擎默认的隔离级别,当前事务的变化不会被外部看到
(3)提交读
当前事务可以看到其他事务对数据的修改
(4)未提交读
(1)查看全局的隔离级别和查看当前会话的隔离级别(mysql5.7版本的命令)
(2)修改当前会话的隔离级别
(3)测试序列化
先执行会话1的这前两行代码,但是不执行提交事务
然后执行会话2的这前两行代码,也不执行提交事务
会发现事务2的事务开启不了,必须要等前一个事务提交完
执行完会话1的commit后,会话2就能开启事务
安全性最高,但是效率不好
(4)测试可重复读
修改当前会话的隔离级别
然后会话1开启事务,并且查询值,但是不提交事务。此时查询的money结果是99
然后会话2开启事务,并且修改值(此时两个事务可以同时进行了),将money值修改为100。但是不提交事务
再回到会话1,执行查询语句,money结果还是99
会话1的事务提交完后,重新执行查询,money结果才是100(此时会话2的事务还没有提交)
也就是说,在当前事务中查询的结果不变,即使这个数据已经被其他事务修改过了,当前事务对其他事务的修改是不可见的
(5)可重复读造成的幻读
会话2事务提交成功了,但是因为事务未提交前不可见,所以会话1读到的值跟最终的实际值还是可能不一样。
(6)测试提交读(不可重复读)
会话1的事务提交完后,必须等到会话2的事务也提交完,才能查到会话2修改的值。即使会话2把money改成100了,只要会话2还没有提交事务,会话1读到的就一直是99。
这种隔离级别也可能会出现幻读。
可重复读造成幻读的原因就是会话2事务提交成功,导致会话1读到的值跟最终的实际值不一样。而不可重复读造成的幻读的原因就是会话2修改值后还没有提交事务,会话1就可以读到修改后的值100了,但是如果会话2回滚了呢,最终的真实结果应该还是99。但是会话1已经获取100并使用了
例如两个会话开启事务后,都先执行select语句,都发现没有这个数据,然后都执行一个insert方法插入数据,执行insert就会加锁,那第二个事务进来就会被锁住。
(7)未提交读
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.9.RELEASEversion>
<relativePath/>
parent>
<groupId>com.allengroupId>
<artifactId>transactionalartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>transactionalname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.21version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
server.port=8081
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sharding-jdbc-order?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
logging.level.root=debug
package com.allen.transactional.Con;
import com.allen.transactional.Service.UserService01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ClassName: TestController
* @Author: AllenSun
* @Date: 2022/12/20 下午10:37
*/
@RestController
public class TestController {
@Autowired
UserService01 userService01;
@GetMapping("/hello")
public void hello () {
userService01.transfer();
}
}
package com.allen.transactional.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @ClassName: UserService01
* @Author: AllenSun
* @Date: 2022/12/20 下午10:38
*/
@Service
public class UserService01 {
@Autowired
JdbcTemplate jdbcTemplate;
@Autowired
UserService02 userService02;
@Transactional
public void transfer() {
jdbcTemplate.update("update order_1 set count = ? where user_id=?;",1,101);
int i=1/0;
}
}
package com.allen.transactional.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
/**
* @ClassName: UserService01
* @Author: AllenSun
* @Date: 2022/12/20 下午10:38
*/
@Service
public class UserService02 {
@Autowired
JdbcTemplate jdbcTemplate;
public void update() {
jdbcTemplate.update("update order_1 set count = ? where user_id=?;",100,103);
}
}
http://127.0.0.1:8081/hello
注意的是在transfer方法中添加了一行int i=1/0;导致抛出异常,触发事务,可以看看日志的详细内容
事务传播行为是为了解决业务层方法之间互相调用的事务问题,当一个事务方法被另一个事务方法调用时,事务该以何种状态存在?例如新方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行,等等,这些规则就涉及到事务的传播性。
默认是Required。
用的比较多的就是REQUIRED、REQUIRES_NEW、NESTED这三种,90%的情况下使用REQUIRED就可以解决了
@Transactional注解的默认属性就是REQUIRED
方法和它的内部方法共用同一个事务
(1)如果transfer方法已经开启事务了,那么update方法就不会再开启新的事务,而是加到transfer方法的事务中来
(2)如果transfer方法没有开启事务,那么update才会开启自己的新的事务
(3)如果transfer方法抛出异常也会造成update方法的回滚
查看控制台的日志内容
# 创建transfer方法的事务
o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
# 执行tranfer方法的sql
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 将update方法添加到transfer方法的事务中去
o.s.j.d.DataSourceTransactionManager : Participating in existing transaction
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 抛出异常,开始回滚
o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@79ede17d]]]
o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection
因为是把update方法加入到transfer方法的事务中去的,所以两个方法共用一个事务,如果发生回滚的话,两个方法是都要回滚的
(1)如果外部有事务,内部也会开启自己的事务,会将外部的事务挂起,内部的事务独自运行。可能会同时存在两个事务
1-transfer方法抛出异常后会回滚,但是update方法不会跟着回滚,因为update方法开启的是自己的事务
2-如果transfer方法正常执行,而update方法抛出异常回滚,那就要看update方法的异常是否会处理掉,如果update的异常被处理了,transfer方法就不会回滚,否则受到update的异常影响也会回滚
(2)如果外部没有事务,内部还是会开启自己的事务
这里有个细节,如果对user_id字段没有加数据库索引,在执行的时候,transfer方法会对表加表锁,那么update方法执行sql的时候就会陷入死锁的情况,访问超时。所以可以给user_id字段加上唯一索引,这样transfer方法就只会加行锁,就不会出现死锁的问题了
查看控制台日志
# 创建transfer方法的事务
2022-12-21 00:01:31.146 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:01:31.147 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5f489349]]] for JDBC transaction
2022-12-21 00:01:31.147 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5f489349]]] to manual commit
# 准备执行transfer方法的sql
2022-12-21 00:01:31.147 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:01:31.147 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:01:31.149 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 挂起transfer方法的事务,创建update方法的事务
2022-12-21 00:01:31.149 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Suspending current transaction, creating new transaction with name [com.allen.transactional.Service.UserService02.update]
2022-12-21 00:01:31.150 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@201ca654]]] for JDBC transaction
2022-12-21 00:01:31.151 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@201ca654]]] to manual commit
# 准备执行update方法的事务
2022-12-21 00:01:31.151 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:01:31.151 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:01:31.151 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 提交update方法的事务
2022-12-21 00:01:31.152 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Initiating transaction commit
2022-12-21 00:01:31.152 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@201ca654]]]
2022-12-21 00:01:31.152 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@201ca654]]] after transaction
2022-12-21 00:01:31.152 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
# 唤醒transfer方法的事务,然后提交
2022-12-21 00:01:31.153 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Resuming suspended transaction after completion of inner transaction
2022-12-21 00:01:31.153 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Initiating transaction commit
2022-12-21 00:01:31.153 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5f489349]]]
是因为内部的update方法抛出异常后没有进行处理,导致外部的方法也会出现异常,导致两个方法都会回滚
查看控制台日志
# 创建transfer方法的事务
2022-12-21 00:11:17.147 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:11:17.153 DEBUG 67348 --- [nio-8081-exec-2] o.a.tomcat.jdbc.pool.PooledConnection : Instantiating driver using class: com.mysql.jdbc.Driver [url=jdbc:mysql://127.0.0.1:3306/sharding-jdbc-order?characterEncoding=UTF-8]
2022-12-21 00:11:17.414 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@771338ee]]] for JDBC transaction
2022-12-21 00:11:17.416 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@771338ee]]] to manual commit
# 执行transfer方法的sql
2022-12-21 00:11:17.421 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:11:17.421 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:11:17.433 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 挂起transfer方法的事务,并且创建update方法的事务
2022-12-21 00:11:17.435 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Suspending current transaction, creating new transaction with name [com.allen.transactional.Service.UserService02.update]
2022-12-21 00:11:17.435 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6e1ad23e]]] for JDBC transaction
2022-12-21 00:11:17.435 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6e1ad23e]]] to manual commit
# 执行update方法的sql
2022-12-21 00:11:17.437 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:11:17.437 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:11:17.438 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 发现异常,准备回滚update方法
2022-12-21 00:11:17.439 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2022-12-21 00:11:17.439 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6e1ad23e]]]
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6e1ad23e]]] after transaction
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
# 唤醒transfer方法的事务
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Resuming suspended transaction after completion of inner transaction
# transfer方法也开始回滚
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@771338ee]]]
2022-12-21 00:11:17.442 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@771338ee]]] after transaction
两个方法都发生了回滚,接下来对内部update方法的异常进行处理然后再看update的方法对transfer方法有没有影响
再来看看控制台日志
# 创建transfer方法的事务
2022-12-21 00:22:55.704 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:22:55.710 DEBUG 68808 --- [nio-8081-exec-1] o.a.tomcat.jdbc.pool.PooledConnection : Instantiating driver using class: com.mysql.jdbc.Driver [url=jdbc:mysql://127.0.0.1:3306/sharding-jdbc-order?characterEncoding=UTF-8]
2022-12-21 00:22:55.955 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@559824e7]]] for JDBC transaction
2022-12-21 00:22:55.956 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@559824e7]]] to manual commit
# 执行transfer方法的sql
2022-12-21 00:22:55.959 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:22:55.959 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:22:55.973 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 挂起transfer方法的事务,并且创建update方法的事务
2022-12-21 00:22:55.974 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Suspending current transaction, creating new transaction with name [com.allen.transactional.Service.UserService02.update]
2022-12-21 00:22:55.975 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6b1e08a1]]] for JDBC transaction
2022-12-21 00:22:55.975 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6b1e08a1]]] to manual commit
# 执行update方法的sql
2022-12-21 00:22:55.977 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:22:55.977 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:22:55.979 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# update方法出现异常,开始回滚update的sql
2022-12-21 00:22:55.979 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2022-12-21 00:22:55.979 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6b1e08a1]]]
2022-12-21 00:22:55.981 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6b1e08a1]]] after transaction
2022-12-21 00:22:55.982 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
# 唤醒transfer方法的事务
2022-12-21 00:22:55.982 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Resuming suspended transaction after completion of inner transaction
2022-12-21 00:22:55.982 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Initiating transaction commit
# 提交transfer方法的事务
2022-12-21 00:22:55.982 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@559824e7]]]
2022-12-21 00:22:55.983 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@559824e7]]] after transaction
查看结果,可以看到transfer方法修改成功了,update方法没有修改成功
# 创建transfer方法的事务
2022-12-21 00:31:25.591 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:31:25.833 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@17ce73b0]]] for JDBC transaction
2022-12-21 00:31:25.835 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@17ce73b0]]] to manual commit
# 执行transfer方法的sql
2022-12-21 00:31:25.839 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:31:25.839 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:31:25.852 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 挂起transfer方法的事务,创建update方法的事务
2022-12-21 00:31:25.854 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Suspending current transaction, creating new transaction with name [com.allen.transactional.Service.UserService02.update]
2022-12-21 00:31:25.854 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@7f5ec022]]] for JDBC transaction
2022-12-21 00:31:25.854 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@7f5ec022]]] to manual commit
# 执行update方法的sql
2022-12-21 00:31:25.856 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:31:25.856 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:31:25.856 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 提交update方法的事务
2022-12-21 00:31:25.857 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Initiating transaction commit
2022-12-21 00:31:25.857 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@7f5ec022]]]
2022-12-21 00:31:25.858 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@7f5ec022]]] after transaction
2022-12-21 00:31:25.858 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
# 唤醒transfer方法的事务
2022-12-21 00:31:25.859 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Resuming suspended transaction after completion of inner transaction
# transfer方法出现异常,开始回滚transfer方法的sql
2022-12-21 00:31:25.859 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2022-12-21 00:31:25.859 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@17ce73b0]]]
2022-12-21 00:31:25.861 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@17ce73b0]]] after transaction
2022-12-21 00:31:25.861 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
查看数据库结果,transfer方法回滚了,没有修改成功,而update方法事务成功提交了,修改成功
如果主事务发生了回滚,子事务也会跟着回滚
# 创建transfer方法的事务
2022-12-21 00:43:43.676 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:43:43.915 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5e363a1d]]] to manual commit
# 执行transfer方法的sql
2022-12-21 00:43:43.920 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:43:43.921 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:43:43.937 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 创建嵌套子事务update方法的事务
2022-12-21 00:43:43.938 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Creating nested transaction with name [com.allen.transactional.Service.UserService02.update]
# 执行update方法的sql
2022-12-21 00:43:43.943 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:43:43.943 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:43:43.944 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
2022-12-21 00:43:43.945 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Releasing transaction savepoint
# transfer方法出现异常,开始回滚,主事务和子事务都会回滚,两个事务都没有提交
2022-12-21 00:43:43.945 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2022-12-21 00:43:43.945 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5e363a1d]]]
2022-12-21 00:43:43.946 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5e363a1d]]] after transaction
2022-12-21 00:43:43.946 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
两个方法都没有修改数据库,数据库的数据不变
# 创建transfer方法的事务
2022-12-21 00:53:26.042 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
# 执行transfer方法的sql
2022-12-21 00:53:26.317 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:53:26.318 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:53:26.332 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# 创建内部方法update的子事务
2022-12-21 00:53:26.334 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Creating nested transaction with name [com.allen.transactional.Service.UserService02.update]
# 执行update方法的sql
2022-12-21 00:53:26.339 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2022-12-21 00:53:26.339 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:53:26.340 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
# update方法出现异常,开始回滚
2022-12-21 00:53:26.341 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Rolling back transaction to savepoint
# 提交transfer方法的事务
2022-12-21 00:53:26.342 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Initiating transaction commit
2022-12-21 00:53:26.342 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@57a99f1]]]
2022-12-21 00:53:26.344 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection
MANDATORY的方法事务不能独立存在,必须加到一个事务中去
(1)如果transfer方法有事务,那么update方法就加入到transfer方法的事务中去
(2)如果transfer方法没有事务,那么update方法的事务就会报错
(1)如果transfer方法有事务,那么update方法就加入到transfer方法的事务中去
(2)如果transfer方法没有事务,那么update方法的事务加了也没用,直接用非事务的方式继续运行
加了这个属性以后,如果当前方法加了事务,就把事务挂起,以非事务的方式运行
加了这个属性以后,如果当前方法加了事务,就会直接抛出异常,必须以非事务的方式运行
什么情况下才会回滚?
只有在遇到运行时异常RuntimeException 的时候才会回滚,如果遇到的是检查性异常,就不会触发回滚
(1)添加一个IOException,那么就不会触发回滚,因为不是运行时异常
(2)添加rollbackfor参数,修改回滚的规则,指定哪种异常会回滚
这个时候就可以触发回滚了
(3)也可以用noRollbackFor参数,指定哪种异常不回滚
如果一个业务方法只有一个查询sql,那就没有必要添加事务了,添加事务反而会导致执行的效率变慢。
但是如果一个业务方法中有多个查询sql,默认情况下,每个查询sql都会开启一个独立的事务,这个时候如果有并发任务修改了数据的话,一个方法中的多个查询sql可能就会查出不同的结果,多个事务使用隔离级别就无法解决。
开启只读之后,就可以保证多个查询事务的查询结果是一样的
如果只有一个查询sql就没必要添加了,如果有多个查询sql,可以视情况判断是否要添加
设置一个超时时间,如果在这个时间内事务还没有执行完,就会自动回滚这个事务,避免出现大事务
如果加在private方法,会直接爆红线;如果加在protected方法,虽然不会爆红,但是事务不会生效
没有事务的m1方法内部调用了有事务的transfer方法,但是其他方法调用m1方法的时候,transfer方法的事务会失效
原因就是事务注解的原理为AOP代理,代理模式只会拦截通过代理传入的方法
注解写到方法的实现类上,不要写到接口上去