mybatis多数据库动态切换实现

 <bean id="propertyConfigurer"  
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
        <!-- ignoreUnresolvablePlaceholders为是否忽略不可解析的Placeholder --> 
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="locations">
            <list>       
                <value>classpath:conf.properties</value>
            </list>
        </property>
    </bean> 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"  

        destroy-method="close">  
        <property name="driverClassName" value="${jdbc.driver}" />  
        <property name="url" value="${jdbc.url}" />  
        <property name="username" value="${jdbc.username}"/> 
        <property name="password" value="${jdbc.password}" />
      <!--maxActive: 最大连接数量-->    
        <property name="maxActive" value="150"/>  
        <!--minIdle: 最小空闲连接-->    
        <property name="minIdle" value="5"/>  
        <!--maxIdle: 最大空闲连接-->    
        <property name="maxIdle" value="20"/>  
        <!--initialSize: 初始化连接-->    
        <property name="initialSize" value="30"/>  
        <!-- 连接被泄露时是否打印 -->  
        <property name="logAbandoned" value="true"/>  
        <!--removeAbandoned: 是否自动回收超时连接-->    
        <property name="removeAbandoned"  value="true"/>  
        <!--removeAbandonedTimeout: 超时时间(以秒数为单位)-->    
        <property name="removeAbandonedTimeout" value="10"/>  
        <!--maxWait: 超时等待时间以毫秒为单位 1000等于60秒-->  
        <property name="maxWait" value="1000"/>  
        <!-- 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. -->  
        <property name="timeBetweenEvictionRunsMillis" value="10000"/>  
        <!--  在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->  
        <property name="numTestsPerEvictionRun" value="10"/>  
        <!-- 1000 * 60 * 30  连接在池中保持空闲而不被空闲连接回收器线程-->  
        <property name="minEvictableIdleTimeMillis" value="10000"/>  
    <property name="validationQuery" value="SELECT NOW() FROM DUAL"/>    
    </bean>
    
    <!-- 读数据库 -->
<bean id="dataSourceR" parent="dataSource"  p:url="${jdbc.slave.url}" p:username="${jdbc.slave.username}" p:password="${jdbc.slave.password}"/>
<!-- 写数据库 -->
<bean id="dataSourceRW" parent="dataSource" />



    <!-- 多数据库动态切换 --> 
<bean id="dynamicDataSource" class="com.tvjoy.btop.webapp.dataSource.DynamicDataSource">  
   <!-- 通过key-value关联数据源 -->  
   <property name="targetDataSources">  
       <map>  
           <entry value-ref="dataSourceRW" key="dataSourceKeyRW"></entry>  
           <entry value-ref="dataSourceR" key="dataSourceKeyR"></entry>  
       </map>  
   </property>  
   <property name="defaultTargetDataSource" ref="dataSourceRW" />      

</bean> 


<!--
2. mybatis的SqlSession的工厂: SqlSessionFactoryBean dataSource:引用数据源


MyBatis定义数据源,同意加载配置
-->
<bean id="sqlSessionFactoryBeanName" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"></property>
    <property name="configLocation" value="classpath:mybatis-config.xml" />
<!-- <property name="mapperLocations" value="classpath:com/tvjoy/btop/webapp/mapper/*.xml"></property> 
 --> </bean>



<!--
3. mybatis自动扫描加载Sql映射文件/接口 : MapperScannerConfigurer sqlSessionFactory
basePackage:指定sql映射文件/接口所在的包(自动扫描)
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.tvjoy.btop.webapp.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBeanName"></property>
</bean> 


 <!-- 配置数据库注解aop开始 -->  
<bean id="DynamicDataSourceAspect" class="com.tvjoy.btop.webapp.dataSource.DynamicDataSourceAspect" />

<aop:config  expose-proxy="true">   
        <aop:aspect  ref="DynamicDataSourceAspect" order="1">
            <!--配置com.tvjoy.btop..service包下所有类或接口的所有方法     -->
            <aop:pointcut id="serviceTier"  
                expression="execution(* com.tvjoy.btop.webapp..*.*(..))" />   
            <aop:before pointcut-ref="serviceTier" method="doBefore"/>   
            <aop:after pointcut-ref="serviceTier" method="doAfter"/>   
            <aop:around pointcut-ref="serviceTier" method="doAround"/>   
            <aop:after-throwing pointcut-ref="serviceTier" method="doThrowing" throwing="ex"/>   
        </aop:aspect>
    </aop:config>
    <!-- 配置数据库注解aop 结束--> 


一、自定义一个注解

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


/**
 * RUNTIME 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
 * 
 * @author wanggang
 * 
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
String value();
}


二、建立一个动态设置数据库的类

public class DBContextHolder {


/**
* 线程threadlocal
*/
private static ThreadLocal<String> contextHolder = new ThreadLocal<String>();


public static void putDataSource(String datasource) {
contextHolder.set(datasource);
}


public static String getDataSource() {
return contextHolder.get();
}
}


三、重写Spring框架里的AbstractRoutingDataSource类中的determineCurrentLookupKey

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


public class DynamicDataSource extends AbstractRoutingDataSource {


/*
* (non-Javadoc)

* @see javax.sql.CommonDataSource#getParentLogger()
*/
@Override
public java.util.logging.Logger getParentLogger() {
// TODO Auto-generated method stub
return null;
}


/**

* override determineCurrentLookupKey
* <p>
* Title: determineCurrentLookupKey
* </p>
* <p>
* Description: 自动查找datasource
* </p>

* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return DBContextHolder.getDataSource();
}


}


四、自定义一个组件用来可以动态设置数据库

import java.lang.reflect.Method;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class DynamicDataSourceAspect {
private static final Logger log = LoggerFactory
.getLogger(DynamicDataSourceAspect.class);


public DynamicDataSourceAspect() {
}


public void doBefore(JoinPoint point) {
Object target = point.getTarget();
// System.out.println(target.toString());
String method = point.getSignature().getName();
// System.out.println(method);
Class<?>[] classz = target.getClass().getInterfaces();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
.getMethod().getParameterTypes();
try {
Method m = classz[0].getMethod(method, parameterTypes);
// System.out.println(m.getName());
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m.getAnnotation(DataSource.class);
DBContextHolder.putDataSource(data.value());
}


} catch (Exception e) {
e.printStackTrace();
}
}


public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long time = System.currentTimeMillis();
Object retVal = pjp.proceed();
time = System.currentTimeMillis() - time;
log.debug("DoAround process time: {} ms", Long.valueOf(time));
return retVal;
}


public void doAfter(JoinPoint jp) {
log.debug("DoAfter method: {}.{}", jp.getTarget().getClass().getName(),
jp.getSignature().getName());
}


public void doThrowing(JoinPoint jp, Throwable ex) {
log.debug("DoThrowing method: {}.{} throw exception", jp.getTarget()
.getClass().getName(), jp.getSignature().getName());
log.debug("throwable{}", ex);
}
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值