package com.easyooo.framework.sharding.transaction;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionUtils;
import org.mybatis.spring.transaction.SpringManagedTransaction;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**
*
* 接管MyBatis Spring 事务,如果使用了多数据源的事务则由Spring拦截器统一管理事务
* <code>openTransaction\commit\rollback</code>
*
* 如果在无事务的情况下,则会每次操作数据库都打开新的连接,自动commit/rollbak, 在返回结果之前关闭连
* 接,效率较低。
*
* 建议:使用Spring代理所有有关数据库的事务,包括只读事务,
* 这样每次操作一个数据源只会打开一个连接 同库操作多次时只会使用第一次打开的连接。
*
* @see com.easyooo.show.business.support.sharding.transaction.DataSourceUtils#getConnection(DataSource)
*
* @see TransactionInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
* @see RoutingSynchronizationManager
* @see SqlSessionFactoryBean
* @see SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory,
* org.apache.ibatis.session.ExecutorType,
* org.springframework.dao.support.PersistenceExceptionTranslator)
*
* @author Killer
*/
public class RoutingSpringManagedTransaction extends SpringManagedTransaction {
private final DataSource dataSource;
private Connection nonTransactionConnection;
public RoutingSpringManagedTransaction(DataSource dataSource) {
super(dataSource);
this.dataSource = dataSource;
}
/**
* 多数据源的情况下不能缓存同一个连接,因此每次都从数据源获取一个连接,
* 只有在同一个数据源的情况下是可以持有一个连接对象
*
* @see DataSourceUtils#getConnection(DataSource)
*/
public Connection getConnection() throws SQLException {
if(hasRoutingDataSourceTransactionManager()){
return openConnection();
}else{
return this.nonTransactionConnection = openConnection();
}
}
private Connection openConnection() throws SQLException {
return this.dataSource.getConnection();
}
public void commit() throws SQLException {
if(hasRoutingDataSourceTransactionManager()){
// Does nothing
}else{
super.commit();
}
}
public void rollback() throws SQLException {
if(hasRoutingDataSourceTransactionManager()){
// Does nothing
}else{
super.rollback();
}
}
public void close() throws SQLException {
if(nonTransactionConnection == null){
// Does nothing
}else{
DataSourceUtils.releaseConnection(this.nonTransactionConnection, null);
}
}
protected boolean hasRoutingDataSourceTransactionManager(){
return RoutingSynchronizationManager.isSynchronizationActive();
}
}