Spring SSM基于注解的多数据源配置
Spring基于注解的多数据源配置(SSM)背景:近期写国土地税交互接口时,需要用到RAS解密,就需要从国土数据库获取key,写入地税数据连接的是地税中间库,这个时候就用到了数据源,参考网上资料,实现了这个功能。参考地址:https://lanjingling.github.io/2016/02/15/spring-aop-dynamicdatasource/代码环境1.
Spring基于注解的多数据源配置(SSM)
背景:
近期写国土地税交互接口时,需要用到RSA解密,就需要从国土数据库获取key,写入地税数据连接的是地税中间库,这个时候就用到了数据源,参考网上资料,实现了这个功能。
参考地址:基于spring的aop实现多数据源动态切换 | 晓的技术博客
代码环境
1. JDK: 1.8
2. 框架: Spring+SpringMvc+Mybatis
3. 应用服务器:tomcat 8.0.13
步骤
1. 数据库配置文件配置多数据源(config.propreties)
#地税中间库
jdbc.url=jdbc:mysql://{ip}:{port}/{dbname}?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username=username
jdbc.password=password
#国土预受理库
gt.jdbc.url=jdbc:mysql://{ip}:{port}/{dbname}?useUnicode=true&characterEncoding=utf-8&useSSL=false
gt.jdbc.username=username
gt.jdbc.password=password
2. 配置自定义注解以及切面
a) 配置自定义注解
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author liuch * @date 2017/11/28 19:08 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DataSourceKey { String value(); }
b) 配置数据源类,使用ThreadLocal解决线程问题
/** * @author liuch * @date 2017/11/30 9:28 */ public class HandleDataSource { public static final ThreadLocal<String> holder = new ThreadLocal<String>(); public static void putDataSource(String datasource) { holder.set(datasource); } public static String getDataSource() { return holder.get(); } }
c) 配置数据源管理类
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * @author liuch * @date 2017/11/30 9:49 */ public class ChangeDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return HandleDataSource.getDataSource(); } }
d) 配置切面,拦截自定义注解,切换数据源,自定义需要拦截的包
使用@Order(1)注解,设置优先级高优先级
import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; /** * @author liuch * @date 2017/11/30 9:28 */ @Aspect @Component
@Order(1) public class DataSourceAspect { @Pointcut("execution(* com.gisquest.realestate.modules.tax..*.*(..)))") public void pointCut(){}; @Before(value = "pointCut()") public void before(JoinPoint point) { Object target = point.getTarget(); System.out.println(target.toString()); String method = point.getSignature().getName(); System.out.println(method); Class<?>[] classz = target.getClass(); 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(DataSourceKey.class)) { DataSourceKey data = m.getAnnotation(DataSourceKey.class); HandleDataSource.putDataSource(data.value()); } } catch (Exception e) { e.printStackTrace(); } } }
3. Spring上下文配置多数据源
a) 多个数据源
<!-- 数据源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> <property name="driverClassName" value="${jdbc.driver}"/> <!-- 基本属性 url、user、password --> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- 配置初始化大小、最小、最大 --> <property name="initialSize" value="${jdbc.pool.init}"/> <property name="minIdle" value="${jdbc.pool.minIdle}"/> <property name="maxActive" value="${jdbc.pool.maxActive}"/> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="60000"/> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000"/> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000"/> <!--执行查询的超时时间(秒),执行Statement对象时如果超过此时间,则抛出SQLException --> <property name="queryTimeout" value="180"/> <!--执行一个事务的超时时间(秒),执行Statement对象时判断是否为事务,如果是且此项未设置,则使用queryTimeout --> <property name="transactionQueryTimeout" value="180"/> <!-- 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。5.5及以上版本有PSCache,建议开启。 --> <property name="poolPreparedStatements" value="${jdbc.poolPreparedStatements}"/> <property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.maxPoolPreparedStatementPerConnectionSize}"/> <property name="validationQuery" value="${jdbc.testSql}" /> <property name="testWhileIdle" value="true"/> <property name="testOnBorrow" value="false"/> <property name="testOnReturn" value="false"/> <!-- 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall --> <!-- 配置监控统计拦截的filters --> <property name="filters" value="${jdbc.filters}"/> <!--Start 慢sql监控及log4j设置拦截器--> <property name="proxyFilters"> <list> <ref bean="stat-filter"/> <ref bean="log-filter"/> </list> </property> <!--End 慢sql监控及log4j设置,不想监控的话将proxyFilters属性删除即可 --> </bean> <!-- 国土数据源 --> <bean id="gtdataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> <property name="driverClassName" value="${jdbc.driver}"/> <!-- 基本属性 url、user、password --> <property name="url" value="${gt.jdbc.url}"/> <property name="username" value="${gt.jdbc.username}"/> <property name="password" value="${gt.jdbc.password}"/> <!-- 配置初始化大小、最小、最大 --> <property name="initialSize" value="${jdbc.pool.init}"/> <property name="minIdle" value="${jdbc.pool.minIdle}"/> <property name="maxActive" value="${jdbc.pool.maxActive}"/> <!-- 超过时间限制是否回收 --> <!--<property name="removeAbandoned" value="true" />--> <!--<!– 超时时间;单位为秒。180秒=3分钟 –>--> <!--<property name="removeAbandonedTimeout" value="180" />--> <!-- 关闭abanded连接时输出错误日志此配置项会影响性能,只在排查的时候打开。系统运行时最好关闭。 --> <!--<property name="logAbandoned" value="true" />--> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="60000"/> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000"/> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000"/> <!--执行查询的超时时间(秒),执行Statement对象时如果超过此时间,则抛出SQLException --> <property name="queryTimeout" value="180"/> <!--执行一个事务的超时时间(秒),执行Statement对象时判断是否为事务,如果是且此项未设置,则使用queryTimeout --> <property name="transactionQueryTimeout" value="180"/> <!-- 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。5.5及以上版本有PSCache,建议开启。 --> <property name="poolPreparedStatements" value="${jdbc.poolPreparedStatements}"/> <property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.maxPoolPreparedStatementPerConnectionSize}"/> <property name="validationQuery" value="${jdbc.testSql}" /> <property name="testWhileIdle" value="true"/> <property name="testOnBorrow" value="false"/> <property name="testOnReturn" value="false"/> <!-- 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall --> <!-- 配置监控统计拦截的filters --> <property name="filters" value="${jdbc.filters}"/> <!--Start 慢sql监控及log4j设置拦截器--> <property name="proxyFilters"> <list> <ref bean="stat-filter"/> <ref bean="log-filter"/> </list> </property> <!--End 慢sql监控及log4j设置,不想监控的话将proxyFilters属性删除即可 --> </bean>
b) 使用multipleDataSource注入多个数据源,使用上面新建的ChangeDataSource类
<!--配置多数据源--> <bean id="multipleDataSource" class="com.gisquest.realestate.factory.ChangeDataSource"> <property name="defaultTargetDataSource" ref="dataSource"></property> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="tax" value-ref="dataSource"></entry> <entry key="gt" value-ref="gtdataSource"></entry> </map> </property> </bean>
c) 配置Spring的事务管理和mybatis的sqlSessionFactory
<!-- MyBatis begin --> <!-- 配置mybatis的sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="multipleDataSource"/> <property name="typeAliasesPackage" value="com.gisquest.realestate"/> <property name="mapperLocations" value="classpath*:/mappings/**/*.xml"/> <property name="configLocation" value="classpath:/mybatis-config.xml"></property> </bean>
<!-- 原始事务配置 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="multipleDataSource"/> </bean>
4. 功能实现
在需要切换数据源的方法上使用注解
@DataSourceKey("gt")
gt就是上面多数据源定义的key
有不足之处,忘各路大神多多指正
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)