下面是mybatis多线程如何保证事务统一示例
@Service
public class TestServiceImpl implements TestService {
@Autowired
DataSource dataSource;
@Autowired
SqlSessionFactory sessionFactory;
@Autowired
SqlSessionTemplate sqlSessionTemplate;
@Autowired
TestServiceImpl testServiceImpl;
@Transactional(rollbackFor = Exception.class)
public void tsetttt(){
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
//int nThreads = Runtime.getRuntime().availableProcessors();
int defaultMaxPoolSize = 6 ;
int defaultCorePoolSize = 6;
taskExecutor.setCorePoolSize(defaultCorePoolSize);
taskExecutor.setMaxPoolSize(defaultMaxPoolSize);
taskExecutor.setAllowCoreThreadTimeOut(true);
taskExecutor.setQueueCapacity(10);
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
taskExecutor.setThreadFactory(new CustomizableThreadFactory("test-"));
taskExecutor.afterPropertiesSet();
//获取mybatis的sqlsession,主要是为了把SqlSessionHolder放入ThreadLocal
//如果在这个事务里前面有查询语句了可以不用这一步
SqlSession sqlSession = SqlSessionUtils.getSqlSession(sessionFactory,
sqlSessionTemplate.getExecutorType(),
sqlSessionTemplate.getPersistenceExceptionTranslator());
SqlSessionUtils.closeSqlSession(sqlSession, sessionFactory);
//获取主线程的spring事务holder
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
//获取mybatis SqlSessionHolder
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
List<String> strings = new ArrayList<>();
strings.add("11111");
strings.add("22222");
List<Future<Integer>> futures = new ArrayList<>();
for (String string : strings) {
Future<Integer> future = billOutTaskExecutor.submit(() -> {
//把主线程的spring 的 holder放入当前多线程ThreadLocal 这一步是使该线程已经存在事务
TransactionSynchronizationManager.bindResource(dataSource, conHolder);
//把主线程的SqlSessionHolder放入当前多线程ThreadLocal 这一步是使该线程已经存在session
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
Integer updatefgfff = 0;
try {
updatefgfff = testServiceImpl.updatefgfff(string);
} catch (Exception e) {
log.error("Exception ", e);
} finally {
//清除当前线程的ThreadLocal
TransactionSynchronizationManager.clear();
TransactionSynchronizationManager.unbindResource(dataSource);
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory);
}
return updatefgfff;
});
futures.add(future);
}
for (Future<Integer> future : futures) {
try {
System.out.println(future.get());
} catch (Exception e) {
log.error("Exception: ", e);
}
}
LambdaUpdateWrapper<Entity> objectLambdaUpdateWrapper = Wrappers.lambdaUpdate();
xxxMapper.update(null, objectLambdaUpdateWrapper);
System.out.println(1/0);
}
@Transactional(rollbackFor = Exception.class)
public Integer updatefgfff(String ff){
LambdaUpdateWrapper<Entity> objectLambdaUpdateWrapper1 = Wrappers.lambdaUpdate();
int update;
//多线程操作数据库一定要加锁,不然会报错 java.lang.ArrayIndexOutOfBoundsException: 2
synchronized (BillInternalAccImpl_ply.class) {
update = xxxMapper.update(null, objectLambdaUpdateWrapper1);
}
return update;
}
}
参考
1,mybatis源码 :
org.mybatis.spring.SqlSessionUtils类里面的
getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator)
2,spring的事务代码:AbstractPlatformTransactionManager类
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)方法
下面这一段源码可以自己去看一下
mybatis源码:
public final class SqlSessionUtils {
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
}
LOGGER.debug(() -> "Creating a new SqlSession");
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
}
spring事务源码:
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
//这一步是重点
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
//这一步是判断是否已经存在事务
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
}
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
protected Object doGetTransaction() {
DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
}
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
return txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive();
}
}