`
faith789510
  • 浏览: 1184 次
社区版块
存档分类
最新评论

DataSourceProxyTransactionManager

阅读更多
在spring应用层扩展DataSourceTransactionManager ,判读事务属性readOnly实现读写分离

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionStatus;

/**
 * 1.事务管理由 TransactionInterceptor 拦截,执行invoke
 * 2.调用 TransactionAspectSupport#invokeWithinTransaction 实现环绕通知
 * 3.getTransaction>>doGetTransaction>>isExistingTransaction{
 *      return handleExistingTransaction
 * }
 * 4.if>>[PROPAGATION_REQUIRED || PROPAGATION_REQUIRES_NEW  || PROPAGATION_NESTED]{
 *      doBegin 在此将创建Connection,如果Connection 为新创建,绑定到TransactionSynchronizationManager#bindResource(DataSource, ConnectionHolder);
 *      prepareTransactionStatus
 *      return
 * }
 * 5.prepareTransactionStatus 将当前事务事务绑定到本地线程
 * 如果第四步没有执行,Connection 将由 DataSourceUtils#doGetConnection 创建,绑定到TransactionSynchronizationManager#bindResource(DataSource, ConnectionHolder)
 * 6.执行ReflectiveMethodInvocation#proceed 如果抛出异常执行completeTransactionAfterThrowing处理
 * 7.cleanupTransactionInfo
 * 8.commitTransactionAfterReturning>TransactionManager#commit
 *
 * Created by ShiHui on 2016/1/9.
 */
public class DataSourceProxyTransactionManager extends DataSourceTransactionManager {

    private static Logger logger = LoggerFactory.getLogger(DataSourceProxyTransactionManager.class);

    @Override
    protected Object doGetTransaction() {
        logger.debug(">>> doGetTransaction.");
        return super.doGetTransaction();
    }

    /**
     * @param transaction
     * @param definition PROPAGATION_REQUIRED || PROPAGATION_REQUIRES_NEW  || PROPAGATION_NESTED
     */
    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        logger.info(">>> doBegin transaction : {}");
        logger.info(">>> TransactionDefinition[name = {}, level = {}, propagation = {}, isReadOnly = {}]"
                ,definition.getName()
                ,getIsolationLevelName(definition.getIsolationLevel())
                ,getPropagationBehaviorName(definition.getPropagationBehavior())
                ,definition.isReadOnly());
        determineDataSource(definition);
        super.doBegin(transaction, definition);
    }
    /**
     * Initialize transaction synchronization as appropriate.
     */
    @Override
    protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
        logger.info(">>> prepareSynchronization status : {}, definition : {}", status, definition);
        determineDataSource(definition);
        super.prepareSynchronization(status, definition);
    }
    private void determineDataSource(TransactionDefinition definition){
        if(DataSourceProxyManager.isNone()){
            if(definition.isReadOnly()){
                DataSourceProxyManager.markSlave();
                logger.debug(">>> markSlave because readOnly = {}", definition.isReadOnly());
            }else{
                DataSourceProxyManager.markMaster();
                logger.debug(">>> markMaster because readOnly = {}", definition.isReadOnly());
            }
        }
    }
    @Override
    protected void doCommit(DefaultTransactionStatus status) {
        logger.debug(">>> doCommit");
        super.doCommit(status);
    }

    @Override
    protected void doRollback(DefaultTransactionStatus status) {
        logger.debug(">>> doRollback");
        super.doRollback(status);
    }

    @Override
    protected void doResume(Object transaction, Object suspendedResources) {
        logger.debug(">>> doResume");
        super.doResume(transaction, suspendedResources);
    }

    @Override
    protected Object doSuspend(Object transaction) {
        logger.debug(">>> doSuspend");
        return super.doSuspend(transaction);
    }

    @Override
    protected void doCleanupAfterCompletion(Object transaction) {
        DataSourceProxyManager.rest();
        logger.debug(">>> doCleanupAfterCompletion before rest DataSource STATUS");
        super.doCleanupAfterCompletion(transaction);
    }
    @Override
    protected boolean isExistingTransaction(Object transaction) {
        boolean isExisting = super.isExistingTransaction(transaction);
        logger.debug(">>> isExistingTransaction : {}", isExisting);
        return isExisting;
    }

    private String getIsolationLevelName(int code){
        switch (code){
            case TransactionDefinition.ISOLATION_DEFAULT:
                return "ISOLATION_DEFAULT";
            case TransactionDefinition.ISOLATION_READ_COMMITTED:
                return "ISOLATION_READ_COMMITTED";
            case TransactionDefinition.ISOLATION_READ_UNCOMMITTED:
                return "ISOLATION_READ_UNCOMMITTED";
            case TransactionDefinition.ISOLATION_REPEATABLE_READ:
                return "ISOLATION_REPEATABLE_READ";
            case TransactionDefinition.ISOLATION_SERIALIZABLE:
                return "ISOLATION_SERIALIZABLE";
            default: return "ISOLATION_DEFAULT";
        }
    }
    private String getPropagationBehaviorName(int code){
        switch (code){
            case TransactionDefinition.PROPAGATION_MANDATORY:
                return "PROPAGATION_MANDATORY";
            case TransactionDefinition.PROPAGATION_NESTED:
                return "PROPAGATION_NESTED";
            case TransactionDefinition.PROPAGATION_NEVER:
                return "PROPAGATION_NEVER";
            case TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
                return "PROPAGATION_NOT_SUPPORTED";
            case TransactionDefinition.PROPAGATION_REQUIRED:
                return "PROPAGATION_REQUIRED";
            case TransactionDefinition.PROPAGATION_REQUIRES_NEW:
                return "PROPAGATION_REQUIRES_NEW";
            case TransactionDefinition.PROPAGATION_SUPPORTS:
                return "PROPAGATION_SUPPORTS";
            default:
                return "PROPAGATION_SUPPORTS";
        }
    }
}

//####################################
/**
 * 
 * @author Stony
 *
 */
public class DataSourceProxyManager {

    private enum DataSourceType{
        MASTER,SLAVE,ALWAYS_MASTER
    }
    private static ThreadLocal<DataSourceType> holder = new ThreadLocal<DataSourceType>();

    public static boolean isMaster(){
        return DataSourceType.ALWAYS_MASTER == holder.get() || DataSourceType.MASTER == holder.get();
    }
    public static boolean isNone(){
        return null == holder.get();
    }
    public static void markSlave() {
        holder.set(DataSourceType.SLAVE);
    }
    public static void markMaster(){
        holder.set(DataSourceType.MASTER);
    }
    public static void rest(){
        holder.set(null);
    }
    public static void alwaysMaster(){
        holder.set(DataSourceType.ALWAYS_MASTER);
    }

}
///#############################
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.datasource.AbstractDataSource;
import org.springframework.util.Assert;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by ShiHui on 2016/1/9.
 */
public class DataSourceProxy extends AbstractDataSource implements InitializingBean{

    private static Logger logger = LoggerFactory.getLogger(DataSourceProxy.class);

    private DataSource master;
    private List<DataSource> slaves;
    private int slavesCount = 0;
    private AtomicInteger slaveRequest = new AtomicInteger(1);

    public DataSource getMaster() {
        return master;
    }

    public void setMaster(DataSource master) {
        this.master = master;
    }

    public List<DataSource> getSlaves() {
        return slaves;
    }

    public void setSlave(DataSource slave) {
        if(getSlaves() == null){
            setSlaves(Collections.synchronizedList(new ArrayList<DataSource>()));
        }
        getSlaves().add(slave);
    }
    public void setSlaves(List<DataSource> slaves) {
        this.slaves = slaves;
    }
    private DataSource determineDataSource(){
        if(DataSourceProxyManager.isNone()){
            logger.debug(">>> STATUS isNone current determine db is master");
            return this.master;
        }
        if(DataSourceProxyManager.isMaster()){
        	logger.debug(">>> STATUS isMaster current determine db is master");
            return this.master;
        }
        return determineSlaveDataSource();
    }

    private DataSource determineSlaveDataSource() {
        int index = slaveRequest.incrementAndGet() % slavesCount;
        if(index < 0) index = - 0;
        DataSource ds = this.slaves.get(index);
        logger.debug(">>> STATUS isSlave current determine db is slaves request count {}", slaveRequest.get());
        return ds;
    }

    @Override
    public Connection getConnection() throws SQLException {
        logger.debug("Enter");
        return determineDataSource().getConnection();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return determineDataSource().getConnection(username,password);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.master, "property master is required");
        Assert.notNull(this.slaves, "property slave/slaves is required");
        this.slavesCount = this.slaves.size();
    }
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics