语言选择: 简体中文简体中文 line EnglishEnglish

公司动态

transaction 事务 开启 关闭 不使用 手动控制 spring springboot mybatis

spring springboot mybatis 事务配置 Transactional的Propagation 开启事务 关闭事务_globalcoding

省流:

单元测试时,发现默认是使用事务。想要关闭事务,使用:

@Transactional(propagation = Propagation.NOT_SUPPORTED)

正文:

默认是使用事务

做单元测试的时候,发现默认是使用事务的。代码和日志如下:

@RunWith(SpringRunner.class)
@MybatisPlusTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Rollback(false)
public class T1 {

    @Autowired
    private XxxMapper xxxMapper;

    @Test
    public void t1() {
        int i = 0;
        List xxxDoList = getData();
        System.out.println("我的打印:插入数量 count:" + xxxDoList.size());
        for (XxxDo o : xxxDoList) {
            XxxDo existed = xxxMapper.selectOne(new LambdaQueryWrapper()
                                .eq(XxxDo::getId,o.getId()));
            if(null != existed){continue;}
            xxxMapper.insert(o);
            if(i==100){
                int a = 1/0;
            }
            i++;
        }
        System.out.println("我的打印:循环插入结束");
    }

    public List getData(){
        ....
        return list;
    }

}

日志:

 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.3.0 
INFO  12-10-2023 07:39:41.014 main Started T1 in 13.452 seconds (JVM running for 17.662)
INFO  12-10-2023 07:39:41.297 main {dataSource-1} inited
INFO  12-10-2023 07:39:41.652 main Began transaction (1) for test context [DefaultTestContext@5a8c93 testClass = T1, testInstance = com.ali.cloud.test.T1@3bed3315, testMethod = t1@T1, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@119b0892 testClass = T1, locations = '{}', classes = '{class com.ali.cloud.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1a3e8e24 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@20d525, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@69453e37, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4961f6af, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@f1c9823f, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4c309d4d], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@4ed4a7e4]; rollback [false]
我的打印:插入数量 count: 2000
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@63f6bed1] will be managed by Spring
==>  Preparing: SELECT xxx from xxx where xxx
==> Parameters: 4444b1e53dxxx0d09bcaaa0c6362ayyy(String), 1234b1e53dxxx0d09bcaaa0c6362axxx(String), 0(Integer)
<==      Total: 0
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7] from current transaction
==>  Preparing: INSERT INTO xxx( xxx ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 2342251622094285111(String),xxx, 2023-10-12 07:39:42.762(Timestamp), global_coding(String), 2023-10-12 07:39:42.762(Timestamp), global_coding(String)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7] from current transaction
==>  Preparing: INSERT INTO xxx( xxx ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 2342251622094285112(String),xxx, 2023-10-12 07:39:42.762(Timestamp), global_coding(String), 2023-10-12 07:39:42.762(Timestamp), global_coding(String)
<==    Updates: 1

我的打印:循环插入结束

Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
INFO  12-10-2023 07:40:10.436 main Committed transaction for test: [DefaultTestContext@5a8c93 testClass = T1, testInstance = com.ali.cloud.test.T1@3bed3315, testMethod = t1@T1, testException = java.lang.ArithmeticException: / by zero, mergedContextConfiguration = [MergedContextConfiguration@119b0892 testClass = T1, locations = '{}', classes = '{class com.ali.cloud.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1a3e8e24 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@20d525, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@69453e37, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4961f6af, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@f1c9823f, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4c309d4d], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]
INFO  12-10-2023 07:40:10.455 SpringContextShutdownHook {dataSource-1} closing ...
INFO  12-10-2023 07:40:10.463 SpringContextShutdownHook {dataSource-1} closed

通过日志发现,默认用了事务transaction,这会有一个现象,就是在事务结束前,所有的insert是没有commit的。也就是必须得等到程序结束,数据库才会有数据存进去。

并且,还发现,如果中间出现异常,异常之前的数据是会提交到数据库。

实验:在程序跑起来,循环insert的时候,去查询数据库,是查不到这些数据的。

关闭事务

如果想要插入一条,数据库就有一条,只需要不使用事务即可。关闭事务的方式是:在方法上加上如下注解:

@Transactional(propagation = Propagation.NOT_SUPPORTED)

    @Test
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void t1() {
        int i = 0;
        List xxxDoList = getData();
        System.out.println("我的打印:插入数量 count:" + xxxDoList.size());
        for (XxxDo o : xxxDoList) {
            XxxDo existed = xxxMapper.selectOne(new LambdaQueryWrapper()
                                .eq(XxxDo::getId,o.getId()));
            if(null != existed){continue;}
            xxxMapper.insert(o);
            if(i==100){
                int a = 1/0;
            }
            i++;
        }
        System.out.println("我的打印:循环插入结束");
    }

 日志如下:

 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.3.0 
INFO  13-10-2023 09:37:55.641 main Started T1 in 13.353 seconds (JVM running for 16.686)
我的打印 count: 2293
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@37348491] was not registered for synchronization because synchronization is not active
INFO  13-10-2023 09:37:56.937 main {dataSource-1} inited
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring
==>  Preparing: SELECT xxx from xxx where xxx
==> Parameters: 5555b1e53dxxx0d09bcaaa0c6362ayyy(String), 1234b1e53dxxx0d09bcaaa0c6362axxx(String), 0(Integer)
<==      Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@37348491]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66bf40e5] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring
==>  Preparing: INSERT INTO xxx( xxx ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 2342251622094285111(String),xxx, 2023-10-12 07:39:42.762(Timestamp), global_coding(String), 2023-10-12 07:39:42.762(Timestamp), global_coding(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66bf40e5]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5a515e5d] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring
==>  Preparing: SELECT xxx from xxx where xxx
==> Parameters: 5555b1e53dxxx0d09bcaaa0c6362ayyy(String), 1234b1e53dxxx0d09bcaaa0c6362axxx(String), 0(Integer)
<==      Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5a515e5d]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32f32623] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring
==>  Preparing: INSERT INTO xxx( xxx ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 2342251622094285111(String),xxx, 2023-10-12 07:39:42.762(Timestamp), global_coding(String), 2023-10-12 07:39:42.762(Timestamp), global_coding(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32f32623]

我的打印:循环插入结束

INFO  13-10-2023 09:38:00.505 SpringContextShutdownHook {dataSource-1} closing ...
INFO  13-10-2023 09:38:00.512 SpringContextShutdownHook {dataSource-1} closed

根据两个日志对比,最明显的区别是开启事务的方法只创建了一个SqlSession,没开启事务的方法每一次执行sql都会创建一个SqlSession。

日志里是这句话:Creating a new SqlSession

若开启事务,处理SqlSession的步骤:释放SqlSession,再获取SqlSession,再去执行sql。

若关闭事务,处理SqlSession的步骤:关闭SqlSession,再创建SqlSession,再去执行sql。

当然,还有更具体的细节:

1. 开始都会先初始化数据源,最后都会关闭数据源。

日志:

{dataSource-1} inited,{dataSource-1} closing ...,{dataSource-1} closed

2. jdbc connection都用的是同一个,但两处日志不一样,一个是交给spring管理,一个是没交给spring管理。

日志:

JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@63f6bed1] will be managed by Spring

JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring

手动控制事务

单独对某句sql做一个事务,即手动控制事务。

增加如下4行代码

            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus status = platformTransactionManager.getTransaction(dt);
            platformTransactionManager.commit(status);

用法是:包裹住执行sql语句即可。 

            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus status = platformTransactionManager.getTransaction(dt);
            mapper.insert(o);
            platformTransactionManager.commit(status);

这是将查询和插入都包裹住的日志:

    @Autowired
    private PlatformTransactionManager platformTransactionManager;
    
    @Test
    public void t1(){
        for(int i=0; i
 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.3.0 
INFO  13-10-2023 17:53:24.989 main Started T1 in 12.882 seconds (JVM running for 16.576)
INFO  13-10-2023 17:53:25.302 main {dataSource-1} inited
INFO  13-10-2023 17:53:25.682 main Began transaction (1) for test context [DefaultTestContext@4ed4a7e4 testClass = T1, testInstance = com.ali.cloud.iot.T1@1c7350b0, testMethod = t1@T1, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@55651434 testClass = T1, locations = '{}', classes = '{class com.ali.cloud.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@3bc4ef12 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@587e5365, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@63475ace, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@291caca8, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@44ef74f7, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@38e79ae3], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@50448409]; rollback [false]
我的打印 count: 2293
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32faa16c]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6ea246af] will be managed by Spring
==>  Preparing: SELECT xxx
==> Parameters: xxx
<==      Total: 0
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32faa16c]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32faa16c] from current transaction
==>  Preparing: INSERT INTO xxx
==> Parameters: xxx
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32faa16c]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32faa16c]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32faa16c]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32faa16c]
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e1ffe70]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6ea246af] will be managed by Spring
==>  Preparing: SELECT xxx
==> Parameters: xxx
<==      Total: 0
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e1ffe70]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e1ffe70] from current transaction
==>  Preparing: INSERT INTO xxx
==> Parameters: xxx
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e1ffe70]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e1ffe70]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e1ffe70]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e1ffe70]

我的打印:循环插入结束

INFO  13-10-2023 17:53:29.971 main Committed transaction for test: [DefaultTestContext@4ed4a7e4 testClass = T1, testInstance = com.ali.cloud.iot.T1@1c7350b0, testMethod = t1@T1, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@55651434 testClass = T1, locations = '{}', classes = '{class com.ali.cloud.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@3bc4ef12 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@587e5365, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@63475ace, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@291caca8, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@44ef74f7, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@38e79ae3], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]
INFO  13-10-2023 17:53:29.982 SpringContextShutdownHook {dataSource-1} closing ...
INFO  13-10-2023 17:53:29.993 SpringContextShutdownHook {dataSource-1} closed

这是查询在外面,单独包裹住插入的日志:

        for(int i=0; i
 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.3.0 
INFO  13-10-2023 18:58:43.950 main Started T1 in 18.362 seconds (JVM running for 22.704)
INFO  13-10-2023 18:58:44.356 main {dataSource-1} inited
INFO  13-10-2023 18:58:45.206 main Began transaction (1) for test context [DefaultTestContext@1a3e8e24 testClass = T1, testInstance = com.ali.cloud.iot.T1@4ed4a7e4, testMethod = t1@T1, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@1c7350b0 testClass = T1, locations = '{}', classes = '{class com.ali.cloud.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@55651434 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@587e5365, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@63475ace, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@291caca8, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@44ef74f7, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@38e79ae3], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@3bc4ef12]; rollback [false]
我的打印:count: 2293
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@29fe4840] will be managed by Spring
==>  Preparing: SELECT xxxx
==> Parameters: xxx
<==      Total: 0
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
Transaction synchronization suspending SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b25ab31]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@494c8f29] will be managed by Spring
==>  Preparing: INSERT INTO xxx
==> Parameters: xxx
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b25ab31]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b25ab31]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b25ab31]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b25ab31]
Transaction synchronization resuming SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c] from current transaction
==>  Preparing: SELECT xxx
==> Parameters: xxx
<==      Total: 0
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
Transaction synchronization suspending SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@574059d5]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@494c8f29] will be managed by Spring
==>  Preparing: INSERT INTO xxx
==> Parameters: xxx
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@574059d5]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@574059d5]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@574059d5]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@574059d5]
Transaction synchronization resuming SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]

我的打印:循环插入结束

Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16da476c]
INFO  13-10-2023 18:58:50.166 main Committed transaction for test: [DefaultTestContext@1a3e8e24 testClass = T1, testInstance = com.ali.cloud.iot.T1@4ed4a7e4, testMethod = t1@T1, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@1c7350b0 testClass = T1, locations = '{}', classes = '{class com.ali.cloud.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@55651434 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@587e5365, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@63475ace, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@291caca8, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@44ef74f7, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@38e79ae3], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]
INFO  13-10-2023 18:58:50.179 SpringContextShutdownHook {dataSource-1} closing ...
INFO  13-10-2023 18:58:50.190 SpringContextShutdownHook {dataSource-1} closed

根据日志,两种区别是:

第2种没有将查询包裹的,他是从事务中取出的session,fetched sqlsession from transaction,被包裹住的那个插入语句他是重新创建的session,creating a new sqlsession。

也就是说代码执行逻辑是这样:进入for循环->创建sqlsession1,执行查询sql,释放sqlsession1,挂起sqlsession1->进入到独立手动控制事务的代码->创建sqlsession2-,执行插入sql,释放、提交、注销、关闭sqlsession2,恢复sqlsession1->取出sqlsession1,执行查询sql,释放sqlsession1,挂起sqlsession1->...最后执行完了,走出for循环,执行其他代码,走出方法,提交、注销、关闭sqlsession1->关闭datasource

======================分割线==========================

文章到此已经结束,以下是紫薯布丁

@RunWith(SpringRunner.class)
@MybatisPlusTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Rollback(false)
public class T1 {

    @Autowired
    private XxxMapper xxxMapper;

    @Test

@Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void t1() {
        int i = 0;
        List xxxDoList = getData();
        System.out.println("我的打印:插入数量 count:" + xxxDoList.size());
        for (XxxDo o : xxxDoList) {
            XxxDo existed = xxxMapper.selectOne(new LambdaQueryWrapper()
                                .eq(XxxDo::getId,o.getId()));
            if(null != existed){continue;}
            xxxMapper.insert(o);
            if(i==100){
                int a = 1/0;
            }
            i++;
        }
        System.out.println("我的打印:循环插入结束");
    }

    public List getData(){
        ....
        return list;
    }

}
 

 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.3.0 
INFO  12-10-2023 07:39:41.014 main Started T1 in 13.452 seconds (JVM running for 17.662)
INFO  12-10-2023 07:39:41.297 main {dataSource-1} inited
INFO  12-10-2023 07:39:41.652 main Began transaction (1) for test context [DefaultTestContext@5a8c93 testClass = T1, testInstance = com.ali.cloud.test.T1@3bed3315, testMethod = t1@T1, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@119b0892 testClass = T1, locations = '{}', classes = '{class com.ali.cloud.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1a3e8e24 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@20d525, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@69453e37, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4961f6af, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@f1c9823f, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4c309d4d], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@4ed4a7e4]; rollback [false]
我的打印:插入数量 count: 2000
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@63f6bed1] will be managed by Spring
==>  Preparing: SELECT xxx from xxx where xxx
==> Parameters: 4444b1e53dxxx0d09bcaaa0c6362ayyy(String), 1234b1e53dxxx0d09bcaaa0c6362axxx(String), 0(Integer)
<==      Total: 0
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7] from current transaction
==>  Preparing: INSERT INTO xxx( xxx ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 2342251622094285111(String),xxx, 2023-10-12 07:39:42.762(Timestamp), global_coding(String), 2023-10-12 07:39:42.762(Timestamp), global_coding(String)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7] from current transaction
==>  Preparing: INSERT INTO xxx( xxx ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 2342251622094285112(String),xxx, 2023-10-12 07:39:42.762(Timestamp), global_coding(String), 2023-10-12 07:39:42.762(Timestamp), global_coding(String)
<==    Updates: 1

我的打印:循环插入结束

Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e62ead7]
INFO  12-10-2023 07:40:10.436 main Committed transaction for test: [DefaultTestContext@5a8c93 testClass = T1, testInstance = com.ali.cloud.test.T1@3bed3315, testMethod = t1@T1, testException = java.lang.ArithmeticException: / by zero, mergedContextConfiguration = [MergedContextConfiguration@119b0892 testClass = T1, locations = '{}', classes = '{class com.ali.cloud.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1a3e8e24 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@20d525, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@69453e37, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4961f6af, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@f1c9823f, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4c309d4d], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]
INFO  12-10-2023 07:40:10.455 SpringContextShutdownHook {dataSource-1} closing ...
INFO  12-10-2023 07:40:10.463 SpringContextShutdownHook {dataSource-1} closed

 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.3.0 
INFO  13-10-2023 09:37:55.641 main Started T1 in 13.353 seconds (JVM running for 16.686)
我的打印 count: 2293
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@37348491] was not registered for synchronization because synchronization is not active
INFO  13-10-2023 09:37:56.937 main {dataSource-1} inited
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring
==>  Preparing: SELECT xxx from xxx where xxx
==> Parameters: 5555b1e53dxxx0d09bcaaa0c6362ayyy(String), 1234b1e53dxxx0d09bcaaa0c6362axxx(String), 0(Integer)
<==      Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@37348491]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66bf40e5] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring
==>  Preparing: INSERT INTO xxx( xxx ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 2342251622094285111(String),xxx, 2023-10-12 07:39:42.762(Timestamp), global_coding(String), 2023-10-12 07:39:42.762(Timestamp), global_coding(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66bf40e5]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5a515e5d] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring
==>  Preparing: SELECT xxx from xxx where xxx
==> Parameters: 5555b1e53dxxx0d09bcaaa0c6362ayyy(String), 1234b1e53dxxx0d09bcaaa0c6362axxx(String), 0(Integer)
<==      Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5a515e5d]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32f32623] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring
==>  Preparing: INSERT INTO xxx( xxx ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 2342251622094285111(String),xxx, 2023-10-12 07:39:42.762(Timestamp), global_coding(String), 2023-10-12 07:39:42.762(Timestamp), global_coding(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32f32623]

我的打印:循环插入结束

INFO  13-10-2023 09:38:00.505 SpringContextShutdownHook {dataSource-1} closing ...
INFO  13-10-2023 09:38:00.512 SpringContextShutdownHook {dataSource-1} closed