SPRING+MYBATIS多数据源切换(注解方式配置)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yangwenbo086/article/details/80525333

应公司要求,需要在项目中切换多个数据源,在百度其他大牛的总结后,决定自己总结一下,如有不完善的地方还请大家多多提出建议,废话不多说,进入主题


  1. 目录结构



2.模块介绍

如上图所示,由于项目采用MAVEN聚合工程设计,为达到配置文件公用的效果,集中将配置文件放在config工程中

我的项目目录是 config工程下的src/main/resources/ 我这里account模块需要引用config中spring的配置

3.配置文件打包

将配置文件放在公共配置的config目录中(如果是用idea的朋友) 请在config/pom文件中加入如下配置

(idea在maven打包的时候不会把xml文件打包进去,这里加入如下配置即可)

<build>
    <resources>
        <resource>
            <directory>${basedir}/src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
        <resource>
            <directory>${basedir}src/main/resources</directory>
            <includes>
                <include>**.*</include>
                <include>**/**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>


4.配置文件的依赖

上述3配置好后,接下来就是如何依赖config中的配置文件,在要依赖的项目模块中插件

   <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>unpack</id>
                        <phase>package</phase>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>com.wkp</groupId>
                                    <artifactId>wkp-config</artifactId>
                                    <!--idea 下使用此配置 注意前后端配置-->
                                         <outputDirectory>${project.build.directory}/wkp-account-server/WEB-INF/classes</outputDirectory>
<!--                                     <outputDirectory>${project.build.directory}/classes</outputDirectory> -->
                                    <includes>
                                        **/conf/spring/spring-mybatis.xml
                                    </includes>
                                    <!--Eclispe下使用此配置-->
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>

在打包的时候回回从config中copy到要依赖的目录中目录按照自己的配置即可


5,配置多数据源

上述准备工作完成后,开始配置数据源 我的数据源是配置在spring-mybatis.xml中

<bean id="baseDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"
      abstract="true">
    <!-- 连接池最大值-->
    <property name="maxActive" value="${payCenter.db.maxActive}"/>
    <!-- 初始化大小 -->
    <property name="initialSize" value="${payCenter.db.initialSize}"/>
    <!-- 获取连接最大等待时间 -->
    <property name="maxWait" value="${payCenter.db.maxWait}"/>
    <!-- 连接池最小空闲 -->
    <property name="minIdle" value="${payCenter.db.minIdle}"/>
    <!-- 逐出连接的检测时间间隔 -->
    <property name="timeBetweenEvictionRunsMillis" value="${payCenter.db.timeBetweenEvictionRunsMillis}"/>
    <!-- 最小逐出时间  -->
    <property name="minEvictableIdleTimeMillis" value="${payCenter.db.minEvictableIdleTimeMillis}"/>
    <!-- 检测连接是否有效的SQL-->
    <property name="validationQuery" value="${payCenter.db.validationQuery}"/>
    <!-- 借出连接时是否做测试-->
    <property name="testWhileIdle" value="${payCenter.db.testWhileIdle}"/>
    <!-- 借出连接时是否做测试-->
    <property name="testOnBorrow" value="${payCenter.db.testOnBorrow}"/>
    <!--归还连接时是否做测试-->
    <property name="testOnReturn" value="${payCenter.db.testOnReturn}"/>
    <!-- 超过时间限制是否回收 -->
    <property name="removeAbandoned" value="${payCenter.db.removeAbandoned}"/>
    <!-- 超过时间限制多长-->
    <property name="removeAbandonedTimeout" value="${payCenter.db.removeAbandonedTimeout}"/>
    <!--借出连接时是否做测试-->
    <property name="poolPreparedStatements" value="true"/>
    <!--Statement缓存大小-->
    <property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
</bean>

<!-- ========================================分隔线========================================= -->
<!--多数据源配置 start-->
<!--数据源 :开发库-->
<bean id="local" parent="baseDataSource">
    <property name="url" value="${deve.url}"/>
    <property name="username" value="${deve.username}"/>
    <property name="password" value="${deve.password}"/>
</bean>

<!--数据源 :测试库-->
<bean id="server" parent="baseDataSource">
    <property name="url" value="${test.url}"/>
    <property name="username" value="${test.username}"/>
    <property name="password" value="${test.password}"/>
</bean>


<bean id="dataSource" class="com.DynamicDataSource">
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <entry key="local" value-ref="local"/>
            <entry key="server" value-ref="server"/>
        </map>
    </property>
    <!-- 默认使用server的数据源 -->
    <property name="defaultTargetDataSource" ref="local"></property>
</bean>
<!--多数据源配置 end-->
<!-- ========================================数据源配置========================================= -->

dataSource这个bean中 配置多少数据源就要加多少个entity的节点 


6.创建类


为了达到每个模块都能使用,我是将这些类放在common模块中,根据自己的配置来

DataSource.java

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

/**
 * 数据源
 *
 * @author jiangnan
 *         * @see com.stech.system.interceptor.DataSourceAspect
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value() default "";
}

DynamicDataSource.java

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

/**
 * Created by Administrator on 2018/5/18.
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

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

DynamicDataSourceHolder.java

public class DynamicDataSourceHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    /**
     * @param dataSourceType 数据库类型
     * @return void
     * @throws
     * @Description: 设置数据源类型
     */
    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    /**
     * @param
     * @return String
     * @throws
     * @Description: 获取数据源类型
     */
    public static String getDataSourceType() {
        return contextHolder.get();
    }

    /**
     * @param
     * @return void
     * @throws
     * @Description: 清除数据源类型
     */
    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

DynamicDataSourceInterceptor.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;

/**
 * Created by Administrator on 2018/5/18.
 */
public class DynamicDataSourceInterceptor {

    /**
     * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
     *
     * @param point
     * @throws Exception
     */
    public void intercept(JoinPoint point) throws Exception {
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        resolveDataSource(target, signature.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.setDataSourceType(source.value());
            }
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource source = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSourceType(source.value());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

7.引用

@DataSource(DataSourceConstans.server)
public int insert(List value){
    return mapper.insert(value);
}

8。注意 

数据源切换的时候会影响事物,本人是将service 和dao直接加了一层repository  在service中控制事物在repository中切换数据源,具体情况还要看具体的应用,很多人在control层进行切换数据源


项目中的配置只是一些主要的数据源方面的配置,详细配置还要根据各位的具体场景来应用,如果有不妥之处还请各位大神多多留言,共同进步,共同成长

                                                                                            -------蒙着脸的驴



展开阅读全文

没有更多推荐了,返回首页