Java SSM 框架多数据源注解切换

Posted unknownregister

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java SSM 框架多数据源注解切换相关的知识,希望对你有一定的参考价值。

既然是多数据源切换,必定会遇到一下问题

  1、我的多个数据源如何配置

  2、数据源如何切换

  3、数据源如何通过注解切换

问题一 、我的多个数据源如何配置

当然是再我们的jdbc.properties中写两份连接地址(或者更多份)

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/vee?useUnicode=true&characterEncoding=utf8
username=root
password=6665508a

sqlserver.jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
sqlserver.jdbc.url=jdbc:sqlserver://192.168.88.170:1433;DatabaseName=BigDataDB
sqlserver.jdbc.username=sa
sqlserver.jdbc.password=root

sqlserver1.jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
sqlserver1.jdbc.url=jdbc:sqlserver://192.168.88.170:1433;DatabaseName=BigDataAss
sqlserver1.jdbc.username=sa
sqlserver1.jdbc.password=root

#u5B9Au4E49u521Du59CBu8FDEu63A5u6570   
initialSize=0   
#u5B9Au4E49u6700u5927u8FDEu63A5u6570   
maxActive=20   
#u5B9Au4E49u6700u5927u7A7Au95F2   
maxIdle=20   
#u5B9Au4E49u6700u5C0Fu7A7Au95F2   
minIdle=1   
#u5B9Au4E49u6700u957Fu7B49u5F85u65F6u95F4   
maxWait=60000  

再去修改“spring-db.xml”或者“spring-dao.xml”,这个就要看你的db配置到那个文件里了,对我们的DB信息进行创建多个数据

    <!--数据源1 BigDataAss库-->
    <bean id="dataSourceBigDataDb" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${sqlserver.jdbc.driver}" />
        <property name="url" value="${sqlserver.jdbc.url}" />
        <property name="username" value="${sqlserver.jdbc.username}" />
        <property name="password" value="${sqlserver.jdbc.password}" />
        <!-- 初始化连接大小 -->   
        <property name="initialSize" value="${initialSize}"></property>   
        <!-- 连接池最大数量 -->   
        <property name="maxActive" value="${maxActive}"></property>   
        <!-- 连接池最大空闲 -->   
        <property name="maxIdle" value="${maxIdle}"></property>   
        <!-- 连接池最小空闲 -->   
        <property name="minIdle" value="${minIdle}"></property>   
        <!-- 获取连接最大等待时间 -->   
        <property name="maxWait" value="${maxWait}"></property>   
    </bean>
    <!--数据源2  BigDataDB库-->
    <bean id="dataSourceBigDataAss" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <!-- 配置连接池属性 -->
        <property name="driverClassName" value="${sqlserver1.jdbc.driver}" />
        <property name="url" value="${sqlserver1.jdbc.url}" />
        <property name="username" value="${sqlserver1.jdbc.username}" />
        <property name="password" value="${sqlserver1.jdbc.password}" />
        <!-- 初始化连接大小 -->   
        <property name="initialSize" value="${initialSize}"></property>   
        <!-- 连接池最大数量 -->   
        <property name="maxActive" value="${maxActive}"></property>   
        <!-- 连接池最大空闲 -->   
        <property name="maxIdle" value="${maxIdle}"></property>   
        <!-- 连接池最小空闲 -->   
        <property name="minIdle" value="${minIdle}"></property>   
        <!-- 获取连接最大等待时间 -->   
        <property name="maxWait" value="${maxWait}"></property> 
    </bean>

问题二、数据源如何切换

把多个数据源整合到一个源里边便于我们对数据源的管理同时对事务的处理是始终是一个事务配置。

  <bean id="dataSource" class="com.cly.core.source.DynamicDataSource">
        <property name="defaultTargetDataSource" ref="dataSourceBigDataAss" />
        <property name="targetDataSources">
            <map>
                <entry key="dataSourceBigDataAss" value-ref="dataSourceBigDataAss"></entry>
                <entry key="dataSourceBigDataDb" value-ref="dataSourceBigDataDb"></entry>
            </map>
        </property>
    </bean>

载入加入DynamicDataSource类,继承与org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource即spring-jdbc这个包,具体是啥们就看个人理解吧,其他的文章我也没找到。

package com.cly.core.source;

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

public class DynamicDataSource extends AbstractRoutingDataSource  {

    @Override
    protected Object determineCurrentLookupKey() {
        // TODO Auto-generated method stub
        System.out.println("Intercept data source....");
        return DynamicDataSourceHolder.getDataSource();
    }
}

然后就是相关的DynamicDataSourceHolder类,当然这里并没有操作实际的代码,只是用来存储数据源的名称。

package com.cly.core.source;

import org.apache.log4j.Logger;
import org.slf4j.LoggerFactory;

public class DynamicDataSourceHolder {
    public static final org.slf4j.Logger logger = LoggerFactory.getLogger(DynamicDataSourceHolder.class);
   
    private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();

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

    public static void setDataSource(String dataSource) {
        logger.debug(dataSource);
        THREAD_DATA_SOURCE.set(dataSource);
    }

    public static void clearDataSource() {
        THREAD_DATA_SOURCE.remove();
    }
}

到现在,我们已经可以在service层中通过DynamicDataSourceHolder.setDataSource(“xxxxx”)来切换数据源了

 问题三、数据源如何通过注解切换

注解嘛,当然要有我们自己的注解,声明一个名为“DataSource”的注解,当然你想起啥名都行,随你....

package com.cly.core.annotation;


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

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

 重点来了,这里我们需要依赖org.aspectj的AOP切面注入,这里需要把这个类交给springmav即使用注解@Component使其定义为spring的资源

然后通过@Aspect()使其aspectj能识别以及进行切片能使我们的代码在spring对类进行初始化的时候,获取到初始化的类以及我们自己的@DataSource的注解,再通过DynamicDataSourceHolder.setDataSource(“xxxxx”)来进行数据源的切换(这里我记得是有再配置文件里写的方式,但是我没有实验成功)

package com.cly.core.source;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.cly.core.annotation.DataSource;

@Component
@Aspect()
@Order(1)
public class DynamicDataSourceInterceptor {
    
    public DynamicDataSourceInterceptor() {
        System.out.println("DynamicDataSource....");
    }

    @Before(value = "execution(* com.cly.service..*.*(..))")
    public void before(JoinPoint point) {
        Class<?> target = point.getTarget().getClass();  
        MethodSignature signature = (MethodSignature) point.getSignature(); 
        System.out.println("AOP Write data source");
        resolveDataSource(target, signature.getMethod());  
    }


    @After(value = "execution(* com.cly.service..*.*(..))")
    public void after() {
        DynamicDataSourceHolder.setDataSource(null);
    }

    @AfterThrowing(throwing="ex",pointcut="execution(* com.cly.service.*.*(..))")
    public void afterThrowing(Throwable ex) {
        System.out.println("[Aspect2] afterThrowing advise");
    }
    
    private void resolveDataSource(Class<?> clazz, Method method) {  
        try {  
            Class<?>[] types = method.getParameterTypes();  

            if (clazz.isAnnotationPresent(DataSource.class)) {  
                DataSource source = clazz.getAnnotation(DataSource.class);  
                DynamicDataSourceHolder.setDataSource(source.value());  
            }  
  
            Method m = clazz.getMethod(method.getName(), types);  
            if (m != null && m.isAnnotationPresent(DataSource.class)) {  
                DataSource source = m.getAnnotation(DataSource.class);  
                DynamicDataSourceHolder.setDataSource(source.value());  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }
    
   

}

注:aspectj必须开启和DynamicDataSourceInterceptor类在配置文件里一定要包含在springmvc 的检索路径底下

技术图片

 

 

 附赠一个完整版(我进行了一点点的升级)

 

以上是关于Java SSM 框架多数据源注解切换的主要内容,如果未能解决你的问题,请参考以下文章

JavaEE(SSM框架,黑马程序员) P179~P192

ssm多数据源

java SSM框架 多数据源 代码生成器 websocket即时通讯 shiro redis 后台

java注解

在ssm框架中前后台数据交互均使用json格式

Java---注解与反射