java 通过代码实现动态选择数据源
来源:互联网 发布:心内事无人知 蔡秋凤 编辑:程序博客网 时间:2024/06/06 00:41
类注解
import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Specify DataSource (指定数据源,用于执行事物切面时,指定其他数据源)<br> * 注意:<br> * {@code @SpecifyDS}放在类级别上等同于该类的每个公有方法都放上了{@code @SpecifyDS}<br> * {@code @SpecifyDS}只对公有法有效(与Spring的{@code @Transactional}只对公有方法有效道理是一样的,因为都是Spring AOP代理) * */@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface SpecifyDS { String value();}
线程独享的数据源对象
public class DataSourceHolder { public static final ThreadLocal<String> holder = new ThreadLocal<String>(); public static void setDataSource(String name) { holder.set(name); } public static String getDataSouce() { return holder.get(); }}
动态设置数据源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * 获取当前ThreadLocal设置的dataSource (动态设置的dataSource) */public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceHolder.getDataSouce(); }}
数据源自动选择的切面类
import java.lang.reflect.Method;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.transaction.annotation.Transactional;public class DataSourceAspect implements org.springframework.core.Ordered { private static final String READ_ONLY_METHOD_PREFFIX = "select"; private static final String DEFAULT_MASTER_SUFFIX = "MasterDataSource"; private static final String DEFAULT_SLAVE_SUFFIX = "SlaveDataSource"; private static final int DEFAULT_ORDER = -1; /** * CUD【创建(Create)、更新(Update)和删除(Delete)】所使用的数据源 * <br>默认使用 {主库} */ private String cudDBSuffix = DEFAULT_MASTER_SUFFIX; /** * R【读取(Read)】所使用的数据源 * <br>默认使用 {从库} */ private String readDBSuffix = DEFAULT_SLAVE_SUFFIX; /** * Spring Aspect的顺序,如果一个方法上有多个切面,则值越小的先执行。 */ private int order = DEFAULT_ORDER; /** * 执行事物切面时默认使用的数据源(通常配置为项目的主数据库的主库) */ private String defaultTransDb; public void before(JoinPoint point) { if (DataSourceHolder.getDataSouce() == null) { // 根据包路径名 获取dataSource的key前缀,这样效率太低,改成根据Mapper前缀来获取 Class<?>[] classz = point.getTarget().getClass().getInterfaces(); String interfacePath = classz[0].getName(); // 获取dao和mapper之间的包名,这儿包名与xml的dataSource的key前缀相同 int daoIndex = interfacePath.indexOf("dao"); int mapperIndex = interfacePath.indexOf("mapper"); String packet = interfacePath.substring(daoIndex + 4, mapperIndex - 1); if (point.getSignature().getName().indexOf(READ_ONLY_METHOD_PREFFIX) != -1) { DataSourceHolder.setDataSource(packet + readDBSuffix); } else { DataSourceHolder.setDataSource(packet + cudDBSuffix); } } } public void beforeTrans(JoinPoint point) { Signature signature = point.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); // 获取目标类 Class<?> target = point.getTarget().getClass(); Method targetMethod = null; try { targetMethod = target.getMethod(method.getName(), method.getParameterTypes()); } catch (NoSuchMethodException e) { e.printStackTrace(); } // 根据目标类方法中的注解,选择数据源 if (targetMethod != null) { Transactional transactional = targetMethod.getAnnotation(Transactional.class); if (transactional != null) { SpecifyDS specifyDSCls = target.getAnnotation(SpecifyDS.class); SpecifyDS specifyDS = targetMethod.getAnnotation(SpecifyDS.class); if (specifyDS != null) { DataSourceHolder.setDataSource(specifyDS.value()); } else if (specifyDSCls != null) { DataSourceHolder.setDataSource(specifyDSCls.value()); } else { DataSourceHolder.setDataSource(defaultTransDb); } } } } public void after() { DataSourceHolder.setDataSource(null); } @Override public int getOrder() { return order; } public void setOrder(int order){ this.order = order; } /** * @return the cudDBSuffix */ public String getCudDBSuffix() { return cudDBSuffix; } /** * @param cudDBSuffix the cudDBSuffix to set */ public void setCudDBSuffix(String cudDBSuffix) { this.cudDBSuffix = cudDBSuffix; } /** * @return the readDBSuffix */ public String getReadDBSuffix() { return readDBSuffix; } /** * @param readDBSuffix the readDBSuffix to set */ public void setReadDBSuffix(String readDBSuffix) { this.readDBSuffix = readDBSuffix; } /** * @return the defaultTransDb */ public String getDefaultTransDb() { return defaultTransDb; } /** * @param defaultTransDb the defaultTransDb to set */ public void setDefaultTransDb(String defaultTransDb) { this.defaultTransDb = defaultTransDb; }}
JDBC配置文件
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd" default-autowire="byName"><!--druid--><bean id="MasterDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClass}"/><property name="url" value="${jdbc.map.master.url}"/><property name="username" value="${jdbc.map.master.username}"/><property name="password" value="${jdbc.map.master.password}"/><property name="initialSize" value="5"/><property name="minIdle" value="5"/><property name="maxActive" value="10"/><property name="timeBetweenEvictionRunsMillis" value="5000"/><property name="minEvictableIdleTimeMillis" value="60000"/><property name="validationQuery" value="SELECT 'x'"/><property name="testWhileIdle" value="true"/><property name="testOnBorrow" value="false"/><property name="testOnReturn" value="false"/><property name="removeAbandoned" value="true"/><property name="removeAbandonedTimeout" value="1800"/><property name="logAbandoned" value="true"/><property name="filters" value="stat"/><property name="connectionProperties" value="druid.stat.slowSqlMillis=100"/></bean><bean id="SlaveDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClass}"/><property name="url" value="${jdbc.map.slave.url}"/><property name="username" value="${jdbc.map.slave.username}"/><property name="password" value="${jdbc.map.slave.password}"/><property name="initialSize" value="5"/><property name="minIdle" value="5"/><property name="maxActive" value="10"/><property name="timeBetweenEvictionRunsMillis" value="5000"/><property name="minEvictableIdleTimeMillis" value="30000"/><property name="validationQuery" value="SELECT 'x'"/><property name="testWhileIdle" value="true"/><property name="testOnBorrow" value="false"/><property name="testOnReturn" value="false"/><property name="removeAbandoned" value="true"/><property name="removeAbandonedTimeout" value="1800"/><property name="logAbandoned" value="true"/><property name="filters" value="stat"/><property name="connectionProperties" value="druid.stat.slowSqlMillis=100"/></bean> <!-- 配置DynamicDataSource代替普通dataSource,将实际数据源的DataSource赋值给它 --><bean id="dataSource" class="com.groupname.commons.db.DynamicDataSource"><property name="targetDataSources"><map key-type="java.lang.String"><entry key="MasterDataSource" value-ref="MasterDataSource"/><entry key="SlaveDataSource" value-ref="SlaveDataSource"/></map></property> <!-- 默认主库 --><property name="defaultTargetDataSource" ref="MasterDataSource"/></bean><!-- 配置数据库注解aop,mapper层选择数据源 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="multiDataSourceAspect" class="com.groupname.commons.db.DataSourceAspect"> <!-- 执行事物切面时默认使用的数据源(通常配置为项目的主数据库的主库)。如果不配置,将默认使用上面的defaultTargetDataSource --> <property name="defaultTransDb" value="mapMasterDataSource" /> <!-- 以下是默认配置,一般无需修改 --> <!-- CUD【创建(Create)、更新(Update)和删除(Delete)】所使用的数据源。默认使用 {主库} --> <!-- <property name="cudDBSuffix" value="MasterDataSource" /> --> <!-- R【读取(Read)】所使用的数据源。默认使用 {从库} --> <!-- <property name="readDBSuffix" value="SlaveDataSource" /> --> </bean> <aop:config><aop:aspect ref="multiDataSourceAspect" > <!-- 为DAO层的Mapper自动选择数据源:默认规则是select开头的方法选择从库,其他像update、insert等方法选择主库。 可更改multiDataSourceAspect的slaveSuffix的值来改变默认策略 --><aop:pointcut id="daoDataSourceAutoSelect" expression="execution(* com.groupname.*.center.dao.*.mapper.*.*(..))"/><aop:before pointcut-ref="daoDataSourceAutoSelect" method="before"/><aop:after pointcut-ref="daoDataSourceAutoSelect" method="after"/> <!-- 为事务控制自动选择数据源:扫描有@Transactional注解的service方法,默认切换到上面配置的defaultTransDb数据源去执行事务。 如果要切换其他数据源,可以在方法上再加一个@SpecifyDS({value}),在value中注明是哪个数据源ID --> <aop:pointcut id="transDataSourceAutoSelect" expression="execution(* com.groupname.*.center.service.*.*(..))||execution(* com.groupname.*.manager.service.biz.*.*(..))"/> <aop:before pointcut-ref="transDataSourceAutoSelect" method="beforeTrans"/> <aop:after pointcut-ref="transDataSourceAutoSelect" method="after"/></aop:aspect></aop:config><!-- 定义事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 事务支持注解 --><tx:annotation-driven transaction-manager="transactionManager"/><!--编程式事务使用--><bean id="txDefinition" class="org.springframework.transaction.support.DefaultTransactionDefinition"></bean></beans>
3 0
- java 通过代码实现动态选择数据源
- 枚举注册表DSN,实现用ADO动态选择数据源
- AOP切面实现动态数据源(含代码)
- Mybatis动态数据源实现
- springboot动态数据源实现
- Mybatis动态数据源实现
- Java 实现选择排序代码
- 【Android】通过java代码动态添加控件
- 改进架构,实现动态数据源,降低java维护
- 改进架构,实现动态数据源,降低java维护
- 【java】动态代理+ThreadLocal实现数据源及事务管理
- 代码动态创建ODBC数据源
- JSP动态选择复选框(通过JSTL实现)
- 枚举注册表DSN,实现用ADO动态选择数据源(MFC基于对话框 )
- Java通过JNDI获取数据源
- java通过JNDI获取数据源
- java通过JNDI连接数据源
- Spring动态数据源路由实现
- 硬件产品研发必须注意事项(必要了解的前提)
- TCP/UDP的客户端/服务器编程
- NYOJ 题目73 比大小
- BM算法详解
- 动态分配二维数组
- java 通过代码实现动态选择数据源
- Java继承
- SM2算法第二十七篇: openssl库中的BIGNUM(超赞)
- [转]python 获取脚本所在目录
- linux 使用别名
- Sharepoint之配置向导创建DB失败
- BZOJ2229—— [Zjoi2011]最小割
- 开始跟贺老师学编程了
- 带你玩转Visual Studio——性能分析与优化