spring+mybatis读写分离配置

原创
2016/12/03 19:31
阅读数 371
<!-- 数据源的配置 -->
<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);
    }

 

展开阅读全文
打赏
0
4 收藏
分享
加载中
更多评论
打赏
0 评论
4 收藏
0
分享
返回顶部
顶部