spring+mybatis讀寫分離配置

<!-- 數據源的配置 -->
<bean id="masterHikariConfig" class="com.zaxxer.hikari.HikariConfig">
    <property name="poolName" value="springHikariCP"/>
    <property name="connectionTestQuery" value="SELECT 1"/>
    <property name="dataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"/>
    <property name="dataSourceProperties">
        <props>
            <prop key="url">${jdbc.master.url}</prop>
            <prop key="user">${jdbc.master.username}</prop>
            <prop key="password">${jdbc.master.password}</prop>
        </props>
    </property>
    <property name="autoCommit" value="true"/>
</bean>

<bean id="slave01HikariConfig" class="com.zaxxer.hikari.HikariConfig">
    <property name="poolName" value="springHikariCP"/>
    <property name="connectionTestQuery" value="SELECT 1"/>
    <property name="dataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"/>
    <property name="dataSourceProperties">
        <props>
            <prop key="url">${jdbc.slave01.url}</prop>
            <prop key="user">${jdbc.slave01.username}</prop>
            <prop key="password">${jdbc.slave01.password}</prop>
        </props>
    </property>
    <property name="autoCommit" value="true"/>
</bean>

<!--主數據源-->
<bean id="masterDataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
    <constructor-arg ref="masterHikariConfig"/>
</bean>
<!--從數據源-->
<bean id="slave01DataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
    <constructor-arg ref="slave01HikariConfig"/>
</bean>


<!--定義dynamic數據源-->
<bean id="dataSource" class="com.xwtec.activity.datasource.DynamicDataSource">
    <!-- 設置多個數據源 -->
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <!-- 這個key需要和程序中的key一致 -->
            <entry key="master" value-ref="masterDataSource"/>
            <entry key="slave" value-ref="slave01DataSource"/>
        </map>
    </property>
    <!-- 設置默認的數據源,這裏默認走寫庫 -->
    <property name="defaultTargetDataSource" ref="masterDataSource"/>
</bean>
<!-- 定義AOP切面處理器 -->
<bean class="com.xwtec.activity.datasource.DataSourceAspect" id="dataSourceAspect"/>


<!-- 配置數據庫註解aop -->
<bean id="dynamicDataSourceAspect" class="com.xwtec.activity.datasource.DataSourceAspect" />
<aop:config>
    <aop:aspect id="c" ref="dynamicDataSourceAspect">
        <!--如果只針對活動,則配置改爲execution(* com.xwtec.activity.dao.*.*(..))-->
        <aop:pointcut id="route" expression="execution(* com.xwtec.*.dao.*.*(..))"/>
        <aop:before pointcut-ref="route" method="before"/>
    </aop:aspect>
</aop:config>
<!-- 配置數據庫註解aop -->
/**
 * 定義數據源的AOP切面,通過該Service的方法名判斷是應該走讀庫還是寫庫
 *
 */
public class DataSourceAspect {

    /**
     * 在進入Service方法之前執行
     *
     * @param point 切面對象
     */
    public void before(JoinPoint point) {
        // 獲取到當前執行的方法名
        String methodName = point.getSignature().getName();
        if (isSlave(methodName)) {
            // 標記爲讀庫
            DynamicDataSourceHolder.markSlave();
        } else {
            // 標記爲寫庫
            DynamicDataSourceHolder.markMaster();
        }
    }

    /**
     * 判斷是否爲讀庫
     *
     * @param methodName
     * @return
     */
    private Boolean isSlave(String methodName) {
        // 方法名以query、find、get開頭的方法名走從庫
        return StringUtils.startsWithAny(methodName, new String[]{"query", "find", "get","select"});
    }
/**
 * 定義動態數據源,實現通過集成Spring提供的AbstractRoutingDataSource,只需要實現determineCurrentLookupKey方法即可
 * <p>
 * 由於DynamicDataSource是單例的,線程不安全的,所以採用ThreadLocal保證線程安全,由DynamicDataSourceHolder完成。
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        // 使用DynamicDataSourceHolder保證線程安全,並且得到當前線程中的數據源key
        return DynamicDataSourceHolder.getDataSourceKey();
    }

}
/**
 * 使用ThreadLocal技術來記錄當前線程中的數據源的key
 */
public class DynamicDataSourceHolder {

    //寫庫對應的數據源key
    private static final String MASTER = "master";

    //讀庫對應的數據源key
    private static final String SLAVE = "slave";

    //使用ThreadLocal記錄當前線程的數據源key
    private static final ThreadLocal<String> holder = new ThreadLocal<String>();

    /**
     * 設置數據源key
     *
     * @param key
     */
    public static void putDataSourceKey(String key) {
        holder.set(key);
    }


    /**
     * 獲取數據源key
     *
     * @return
     */
    public static String getDataSourceKey() {
        return holder.get();
    }

    /**
     * 標記寫庫
     */
    public static void markMaster() {
        putDataSourceKey(MASTER);
    }

    /**
     * 標記讀庫
     */
    public static void markSlave() {
        putDataSourceKey(SLAVE);
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章