篇十八:SpringMVC整合Mybatis-Proxy

参考博客:http://www.cnblogs.com/liujiduo/p/5004691.html

     http://www.cnblogs.com/surge/p/3582248.html

一、概览

  1、在Linux中配置数据库主从复制、读写分离;

  2、SpringMVC整合数据库,通过注解实现读写分离

 

二、整合

  1、配置多个数据源(主库、从库),jdbc.properties文件也对应配置多个数据源的连接消息

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/tx 
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 主库:基于Druid数据库链接池的数据源配置 -->
    <bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 基本属性driverClassName、 url、user、password -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="${master.url}" />
        <property name="username" value="${master.username}" />
        <property name="password" value="${master.password}" />
        <!-- 配置初始化大小、最小、最大 -->
        <!-- 通常来说,只需要修改initialSize、minIdle、maxActive -->
        <property name="initialSize" value="2" />
        <property name="minIdle" value="2" />
        <property name="maxActive" value="30" />
        <property name="testWhileIdle" value="false" />

        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="5000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="30000" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 解密密码必须要配置的项 -->
        <property name="filters" value="config" />
        <property name="connectionProperties" value="config.decrypt=false" />
    </bean>
    
    <!-- 从库 -->
    <bean id="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 基本属性driverClassName、 url、user、password -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="${slave.url}" />
        <property name="username" value="${slave.username}" />
        <property name="password" value="${slave.password}" />
        <!-- 配置初始化大小、最小、最大 -->
        <!-- 通常来说,只需要修改initialSize、minIdle、maxActive -->
        <property name="initialSize" value="2" />
        <property name="minIdle" value="2" />
        <property name="maxActive" value="30" />
        <property name="testWhileIdle" value="false" />

        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="5000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="30000" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 解密密码必须要配置的项 -->
        <property name="filters" value="config" />
        <property name="connectionProperties" value="config.decrypt=false" />
    </bean>
    
    <!-- 动态分配数据库连接源 -->
    <bean id="dynamicDataSource" class="com.common.core.dao.proxy.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="masterDataSource" value-ref="masterDataSource"></entry>
                <entry key="slaveDataSource" value-ref="slaveDataSource"></entry>
            </map>
        </property>
        <property name="defaultTargetDataSource" ref="masterDataSource" />
    </bean>
    
    <!-- SqlSession模板类实例 -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype" destroy-method="close">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    <!-- 将数据源映射到sqlSessionFactory中 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
        <property name="dataSource" ref="dynamicDataSource" />
        <property name="plugins">
            <array>
                   <bean class="com.github.pagehelper.PageHelper">
                       <property name="properties">
                           <value>
                               dialect=hsqldb
                           </value>
                       </property>
                   </bean>
            </array>
        </property>
    </bean>

    <!--======= 事务配置 Begin ================= -->
    <!-- 事务管理器(由Spring管理MyBatis的事务) -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 关联数据源 -->
        <property name="dataSource" ref="dynamicDataSource"></property>
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager" />
    <!--======= 事务配置 End =================== -->


    <!-- 读取数据库配置文件 -->
    <context:property-placeholder location="/jdbc.properties"/>
    
    <!-- 配置切面 -->
    <bean id="dataSourceAspect" class="com.common.core.dao.proxy.DataSourceAspect" />
    <aop:config>
        <aop:aspect ref="dataSourceAspect">
            <aop:pointcut id="dataSourcePointcut" expression="execution(* com.common.dao..*(..))"/>
            <aop:before pointcut-ref="dataSourcePointcut" method="intercept"/>
        </aop:aspect>
    </aop:config>
</beans>

  jdbc.properties

#mysql数据库
#db.dbType=mysql
jdbcDriverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/common?useUnicode=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&rewriteBatchedStatements=true
jdbc.username=root
jdbc.password=abcd%1234



#######读写分离配置连接
master.url=jdbc:mysql://192.168.1.86:3306/test?useUnicode=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&rewriteBatchedStatements=true
master.username=root
master.password=life%1234


slave.url=jdbc:mysql://192.168.1.59:3306/test?useUnicode=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&rewriteBatchedStatements=true
slave.username=root
slave.password=life%1234

  

  2、创建DynamicDataSource类,继承AbstractRoutingDataSource

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 
 * @author liuguangping
 * 调用DynamicDataSourceHolder,获取配置的数据源
 */
public class DynamicDataSource extends AbstractRoutingDataSource{

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getDataSource();
    }

}

 

  3、创建DynamicDataSourceHolder,动态修改当前数据库连接源

package com.common.core.dao.proxy;

/**
 * 
 * @author liuguangping
 *
 */
public class DynamicDataSourceHolder {

    /**
     * 设置线程
     */
    public static final ThreadLocal<String> holder = new ThreadLocal<String>();
    
    /**
     * 设置连接源
     * @param name
     */
    public static void putDataSource(String name){
        holder.set(name);
    }
    
    /**
     * 获取连接源
     * @return
     */
    public static String getDataSource(){
        return holder.get();
    }
}

 

  4、创建DataSourceAspect,通过AOP在执行数据库操作时,动态配置数据源

package com.common.core.dao.proxy;

import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import com.common.core.dao.proxy.annotation.DataSource;

/**
 * aop切面,拦截所有DaoImpl的方法
 * @author liuguangping
 *
 */
public class DataSourceAspect {
    
    public void intercept(JoinPoint point) throws Exception{
        Class<?> target = point.getTarget().getClass();
        MethodSignature signnature = (MethodSignature) point.getSignature();
        for(Class<?> clazz : target.getInterfaces()){
            resolveDataSource(clazz, signnature.getMethod());
        }
        resolveDataSource(target, signnature.getMethod());
    }
    
    private void resolveDataSource(Class<?> clazz,Method method)
    {
        try {
            Class<?>[] types = method.getParameterTypes();
            if(clazz.isAnnotationPresent(DataSource.class))
            {
                DataSource source = clazz.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.putDataSource(source.value());
            }
            //方法注解可以覆盖类型注解
            Method m = clazz.getMethod(method.getName(), types);
            if(m != null && m.isAnnotationPresent(DataSource.class))
            {
                DataSource source = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.putDataSource(source.value());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

  5、创建注解DataSource

package com.common.core.dao.proxy.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value();
}

 

posted @ 2017-01-09 14:27  刘广平  阅读(227)  评论(0)    收藏  举报