baomidou / mybatis-plus

An powerful enhanced toolkit of MyBatis for simplify development
https://baomidou.com
Apache License 2.0
16.46k stars 4.31k forks source link

saveBatch下的事务问题 #5108

Open haoxz11 opened 1 year ago

haoxz11 commented 1 year ago

当前使用版本(必填,否则不予处理)

3.5.2

该问题是如何引起的?(确定最新版也有问题再提!!!)

当调用IService下的saveBatch最终会调用SqlHelper.executeBatch方法,

方法中会调用sqlSession先提交一下

SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
        boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
        if (sqlSessionHolder != null) {
            SqlSession sqlSession = sqlSessionHolder.getSqlSession();
            //原生无法支持执行器切换,当存在批量操作时,会嵌套两个session的,优先commit上一个session
            //按道理来说,这里的值应该一直为false。
            sqlSession.commit(!transaction);
        }

虽然是非强制提交,但是,如果saveBatch上面有insert/update等操作,这个时候如果这个方法体是外包一层事务,那么insert、update会被实际执行;后续如果saveBatch报错啥的,无法回滚;

重现步骤(如果有就写完整)

@Transactional(rollbackFor = Exception.class)
public Response<Void> addData(List<Abc> list) {
     service.save(new Abc());
     service.saveBatch(list);
     throw new Exception();
}

报错信息

zengzehao commented 1 year ago

我也遇到这个问题了

caztg commented 1 year ago

有下文吗

Stephenzho commented 1 year ago

我也遇到了

lutao043 commented 6 months ago

https://github.com/baomidou/mybatis-plus/issues/4893

elcnu986 commented 2 months ago

当前使用版本(必填,否则不予处理)

3.5.2

该问题是如何引起的?(确定最新版也有问题再提!!!)

当调用IService下的saveBatch最终会调用SqlHelper.executeBatch方法,

方法中会调用sqlSession先提交一下

SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
        boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
        if (sqlSessionHolder != null) {
            SqlSession sqlSession = sqlSessionHolder.getSqlSession();
            //原生无法支持执行器切换,当存在批量操作时,会嵌套两个session的,优先commit上一个session
            //按道理来说,这里的值应该一直为false。
            sqlSession.commit(!transaction);
        }

虽然是非强制提交,但是,如果saveBatch上面有insert/update等操作,这个时候如果这个方法体是外包一层事务,那么insert、update会被实际执行;后续如果saveBatch报错啥的,无法回滚;

重现步骤(如果有就写完整)

@Transactional(rollbackFor = Exception.class)
public Response<Void> addData(List<Abc> list) {
     service.save(new Abc());
     service.saveBatch(list);
     throw new Exception();
}

报错信息

这样可以回滚啊。saveBatch 报错,这个sqlSession 的线程会被打上 rollback-only,即使是嵌套事务,内层事务 的saveBatch 异常报给 外层事务,即使外层事务把内层事务的异常给 catch了,当外层事务准备提交的时候 也会因为当前线程的 rollback-only 而报异常

测试代码:

@Service
public class MyService {

    @Autowired
    private UserService userService;
    @Autowired
    private ITestService testService;

    @Transactional(rollbackFor = Exception.class)
    public void addData(List<User> list) throws Exception {
        testService.save(new Test(100000));
        userService.save(new User("0"));
        try {
            userService.saveBatch(list);
        } catch (Exception e) {
            // 此处报Data truncation exception
            e.printStackTrace();
        }
//        throw new Exception();
    }
}

    @Test
//    @Transactional(rollbackFor = Exception.class)
    void test2() throws Exception {
        List<User> users = List.of(new User("111111111111111111111111111111111111111"), new User("2"), new User("3"), new User("4"), new User("5"));
        myService.addData(users);
    }

Debug 级别日志:

2024-09-02T15:16:30.226+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Creating new transaction with name [org.example.service.MyService.addData]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Exception
2024-09-02T15:16:30.227+08:00  INFO 23980 --- [demo-21] [           main] com.zaxxer.hikari.HikariDataSource       : HikariCorePool - Starting...
2024-09-02T15:16:30.523+08:00  INFO 23980 --- [demo-21] [           main] com.zaxxer.hikari.pool.HikariPool        : HikariCorePool - Added connection com.mysql.cj.jdbc.ConnectionImpl@64b20d9c
2024-09-02T15:16:30.524+08:00  INFO 23980 --- [demo-21] [           main] com.zaxxer.hikari.HikariDataSource       : HikariCorePool - Start completed.
2024-09-02T15:16:30.529+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Acquired Connection [HikariProxyConnection@1197981223 wrapping com.mysql.cj.jdbc.ConnectionImpl@64b20d9c] for JDBC transaction
2024-09-02T15:16:30.532+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Switching JDBC Connection [HikariProxyConnection@1197981223 wrapping com.mysql.cj.jdbc.ConnectionImpl@64b20d9c] to manual commit
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cd7128]
JDBC Connection [HikariProxyConnection@1197981223 wrapping com.mysql.cj.jdbc.ConnectionImpl@64b20d9c] will be managed by Spring
==>  Preparing: INSERT INTO test ( id, a ) VALUES ( ?, ? )
==> Parameters: 1830505061982142465(Long), 100000(Integer)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cd7128]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cd7128] from current transaction
==>  Preparing: INSERT INTO user ( id, user_name, create_time ) VALUES ( ?, ?, ? )
==> Parameters: 1830505062053445634(Long), 0(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cd7128]
2024-09-02T15:16:30.606+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Participating in existing transaction
JDBC Connection [HikariProxyConnection@1197981223 wrapping com.mysql.cj.jdbc.ConnectionImpl@64b20d9c] will be managed by Spring
==>  Preparing: INSERT INTO user ( id, user_name, create_time ) VALUES ( ?, ?, ? )
==> Parameters: 1830505062116360194(Long), 111111111111111111111111111111111111111(String), null
==> Parameters: 1830505062116360195(Long), 2(String), null
==> Parameters: 1830505062116360196(Long), 3(String), null
==> Parameters: 1830505062116360197(Long), 4(String), null
==> Parameters: 1830505062116360198(Long), 5(String), null
2024-09-02T15:16:30.710+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.SQLErrorCodesFactory    : Looking up default SQLErrorCodes for DataSource [com.zaxxer.hikari.HikariDataSource@2d527346]
2024-09-02T15:16:30.714+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.SQLErrorCodesFactory    : SQL error codes for 'MySQL' found
2024-09-02T15:16:30.714+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.SQLErrorCodesFactory    : Caching SQL error codes for DataSource [com.zaxxer.hikari.HikariDataSource@2d527346]: database product name is 'MySQL'
2024-09-02T15:16:30.714+08:00 DEBUG 23980 --- [demo-21] [           main] s.j.s.SQLErrorCodeSQLExceptionTranslator : Unable to translate SQLException with Error code '1406', will now try the fallback translator
2024-09-02T15:16:30.715+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.j.s.SQLStateSQLExceptionTranslator   : Extracted SQL state class '22' from value '22001'
2024-09-02T15:16:30.715+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Participating transaction failed - marking existing transaction as rollback-only
2024-09-02T15:16:30.715+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Setting JDBC transaction [HikariProxyConnection@1197981223 wrapping com.mysql.cj.jdbc.ConnectionImpl@64b20d9c] rollback-only
org.springframework.dao.DataIntegrityViolationException: org.example.dao.UserDao.insert (batch index #1) failed. Cause: java.sql.BatchUpdateException: Data truncation: Data too long for column 'user_name' at row 1
; Data truncation: Data too long for column 'user_name' at row 1
    at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:118)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:116)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:116)
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92)
    at com.baomidou.mybatisplus.extension.toolkit.SqlHelper.executeBatch(SqlHelper.java:202)
    at com.baomidou.mybatisplus.extension.toolkit.SqlHelper.executeBatch(SqlHelper.java:233)
    at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.executeBatch(ServiceImpl.java:283)
    at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.saveBatch(ServiceImpl.java:178)
    at com.baomidou.mybatisplus.extension.service.IService.saveBatch(IService.java:70)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720)
    at org.example.service.impl.UserServiceImpl$$SpringCGLIB$$0.saveBatch(<generated>)
    at org.example.service.MyService.addData(MyService.java:24)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720)
    at org.example.service.MyService$$SpringCGLIB$$0.addData(<generated>)
    at org.example.Demo.test2(Demo.java:37)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85)
    at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
    at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: java.sql.BatchUpdateException: Data truncation: Data too long for column 'user_name' at row 1
    at com.mysql.cj.jdbc.exceptions.SQLError.createBatchUpdateException(SQLError.java:224)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeBatchSerially(ClientPreparedStatement.java:816)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeBatchInternal(ClientPreparedStatement.java:418)
    at com.mysql.cj.jdbc.StatementImpl.executeBatch(StatementImpl.java:795)
    at com.zaxxer.hikari.pool.ProxyStatement.executeBatch(ProxyStatement.java:127)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeBatch(HikariProxyPreparedStatement.java)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:78)
    at jdk.proxy3/jdk.proxy3.$Proxy170.executeBatch(Unknown Source)
    at org.apache.ibatis.executor.BatchExecutor.doFlushStatements(BatchExecutor.java:126)
    at org.apache.ibatis.executor.BaseExecutor.flushStatements(BaseExecutor.java:129)
    at org.apache.ibatis.executor.BaseExecutor.flushStatements(BaseExecutor.java:122)
    at org.apache.ibatis.executor.CachingExecutor.flushStatements(CachingExecutor.java:115)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
    at jdk.proxy2/jdk.proxy2.$Proxy167.flushStatements(Unknown Source)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.flushStatements(DefaultSqlSession.java:252)
    at com.baomidou.mybatisplus.extension.toolkit.SqlHelper.lambda$executeBatch$1(SqlHelper.java:240)
    at com.baomidou.mybatisplus.extension.toolkit.SqlHelper.executeBatch(SqlHelper.java:192)
    ... 98 more
Caused by: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'user_name' at row 1
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:104)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1061)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeBatchSerially(ClientPreparedStatement.java:795)
    ... 117 more
2024-09-02T15:16:30.717+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Global transaction is marked as rollback-only but transactional code requested commit
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cd7128]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cd7128]
2024-09-02T15:16:30.717+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Initiating transaction rollback
2024-09-02T15:16:30.717+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Rolling back JDBC transaction on Connection [HikariProxyConnection@1197981223 wrapping com.mysql.cj.jdbc.ConnectionImpl@64b20d9c]
2024-09-02T15:16:30.721+08:00 DEBUG 23980 --- [demo-21] [           main] o.s.jdbc.support.JdbcTransactionManager  : Releasing JDBC Connection [HikariProxyConnection@1197981223 wrapping com.mysql.cj.jdbc.ConnectionImpl@64b20d9c] after transaction

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:938)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:663)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:413)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720)
    at org.example.service.MyService$$SpringCGLIB$$0.addData(<generated>)
    at org.example.Demo.test2(Demo.java:37)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
nestorbian commented 2 months ago

SqlHelper.executeBatch里的sqlSession.commit(!transaction);如果开启事务,并不会做实际提交

happy89lgk commented 1 month ago

我也遇到了,是多数据源的情况,有人解决了吗?