spring+mybatis多数据源配置、读写分离
来源:互联网 发布:图像特征匹配算法 编辑:程序博客网 时间:2024/06/05 17:04
实现思路:在spring中配置多个数据源,然后在service层通过注解方式标明方法所要使用的数据源,利用springAOP在service方法执行前根据方法上的注解明确所要使用的数据源。如下图
首先,介绍spring 的AbstractRoutingDataSource 类
AbstractRoutingDataSource这个类 是spring2.0以后增加的,我们先来看下AbstractRoutingDataSource的定义:
- public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {}
- public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
- private Map<Object, Object> targetDataSources;
- private Object defaultTargetDataSource;
- private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
- private Map<Object, DataSource> resolvedDataSources;
- private DataSource resolvedDefaultDataSource;
AbstractRoutingDataSource继承了AbstractDataSource ,而AbstractDataSource 又是DataSource 的子类。
DataSource 是javax.sql 的数据源接口,定义如下:
- public interface DataSource extends CommonDataSource,Wrapper {
- Connection getConnection() throws SQLException;
- Connection getConnection(String username, String password)
- throws SQLException;
- }
DataSource 接口定义了2个方法,都是获取数据库连接。我们在看下AbstractRoutingDataSource 如何实现了DataSource接口:
- public Connection getConnection() throws SQLException {
- return determineTargetDataSource().getConnection();
- }
- public Connection getConnection(String username, String password) throws SQLException {
- return determineTargetDataSource().getConnection(username, password);
- }
很显然就是调用自己的determineTargetDataSource() 方法获取到connection。determineTargetDataSource方法定义如下:
- protected DataSource determineTargetDataSource() {
- Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
- Object lookupKey = determineCurrentLookupKey();
- DataSource dataSource = this.resolvedDataSources.get(lookupKey);
- if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
- dataSource = this.resolvedDefaultDataSource;
- }
- if (dataSource == null) {
- throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
- }
- return dataSource;
- }
我们最关心的还是下面2句话:
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
determineCurrentLookupKey方法返回lookupKey,resolvedDataSources方法就是根据lookupKey从Map中获得数据源。resolvedDataSources 和determineCurrentLookupKey定义如下:
private Map<Object, DataSource> resolvedDataSources;
protected abstract Object determineCurrentLookupKey()
看到以上定义,我们是不是有点思路了,resolvedDataSources是Map类型,我们可以把MasterDataSource和SlaveDataSource存到Map中,如下:
key value
master MasterDataSource
slave SlaveDataSource
我们在写一个类DynamicDataSource 继承AbstractRoutingDataSource,实现其determineCurrentLookupKey() 方法,该方法返回Map的key,master或slave。这样就达到了切换数据库的目的。
现在开始介绍实现方式:
1. 创建注解类,用来标记service方法所要使用的数据源key
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface DataSource {
- String value();
- }
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class DynamicDataSource extends AbstractRoutingDataSource {private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();public static void setDataSourceKey(String dataSource) {dataSourceKey.set(dataSource);}public static String getDatasourcekey() {return dataSourceKey.get();}protected Object determineCurrentLookupKey() {return dataSourceKey.get();}}
方法中实现了determineCurrentLookupKey()方法,该方法会从ThreadLocal对象中获取到一个key来表明所要使用的数据源
3. 实现springAop来根据service中方法上的注解设置ThreadLocal对象
import java.lang.reflect.Method;import org.springframework.core.annotation.AnnotationUtils;import org.springframework.transaction.support.TransactionSynchronizationManager;import com.chinalife.clap.core.MultDataSource;import com.chinalife.clap.core.annotation.DataSource;public class DataSourceAspect {public void before(JoinPoint joinPoint) {if (TransactionSynchronizationManager.isActualTransactionActive()&& DynamicDataSource.getDatasourcekey() != null)return;// 获取方法签名Method declareMethod = ((MethodSignature) joinPoint.getSignature()).getMethod();Method instanceMethod = joinPoint.getTarget().getClass().getMethod(declareMethod.getName(),declareMethod.getParameterTypes());DataSource methodAnnotation = AnnotationUtils.findAnnotation(instanceMethod, DataSource.class);if (methodAnnotation == null)return;if (methodAnnotation != null) {MultDataSource.setDataSourceKey(methodAnnotation.value());}}/** * 方法执行完后置空 */public void after(JoinPoint joinPoint) {if (TransactionSynchronizationManager.isActualTransactionActive())return;if (TransactionSynchronizationManager.isSynchronizationActive())TransactionSynchronizationManager.clearSynchronization();MultDataSource.setDataSourceKey(null);}}
3.开始配置spring数据源 application-jdbc.xml
<bean id="masterdataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:3306/shop" /> <property name="username" value="root" /> <property name="password" value="yangyanping0615" /> </bean> <bean id="slavedataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:3306/test" /> <property name="username" value="root" /> <property name="password" value="yangyanping0615" /> </bean> <beans:bean id="dynamicDataSource" class="com.air.shop.common.db.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <!-- write --> <entry key="master" value-ref="masterdataSource"/> <!-- read --> <entry key="slave" value-ref="slavedataSource"/> </map> </property> <property name="defaultTargetDataSource" ref="masterdataSource"/> </beans:bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dynamicDataSource" /> </bean> <!-- 配置SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dynamicDataSource" /> <property name="configLocation" value="classpath:config/mybatis-config.xml" /> </bean> <!-- 配置数据库注解aop --> <beans:bean id="manyDataSourceAspect" class="com.air.shop.proxy.DataSourceAspect" /> <aop:config> <aop:aspect id="c" ref="manyDataSourceAspect"> <aop:pointcut id="tx" expression="execution(* com.air.shop.mapper.service.*(..))"/> <aop:before pointcut-ref="tx" method="before"/> <aop:after pointcut-ref="tx" method="after"/> </aop:aspect> </aop:config> <!-- 配置数据库注解aop -->
下面给出service实例
public interface Userservic { @DataSource("master") public void add(User user); @DataSource("master") public void update(User user); @DataSource("master") public void delete(int id); @DataSource("slave") public User loadbyid(int id); }
- spring+mybatis多数据源配置、读写分离
- MyBatis多数据源配置(读写分离)
- MyBatis多数据源配置(读写分离)
- MyBatis多数据源配置(读写分离)
- java-durid、mybatis、spring 整合基于 AbstractRoutingDataSource 的多数据源读写分离配置
- MyBatis多数据源配置实现读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- spring多数据源配置,实现读写分离
- Spring配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- spring AOP多数据源读写分离
- spring boot + mybatis 多数据源,mysql服务主从读写分离
- jquery运用
- C#中重写(override)和覆盖(new)的区别
- Android-动画详解
- ios UIWebview中网页宽度自适应手机
- 小马激活工具对比暴风激活工具
- spring+mybatis多数据源配置、读写分离
- ListView使用技巧总结
- 二叉树前序、中序、后序遍历相互求法
- java通过filter单点登陆
- vc socket 多线程 (记录一次自己调用window 底层API编写 vc socket 多线程的服务器网络程序)
- cocoscreate 官方例子说明-创建项目 by:adady
- Centos7上MySQL5.7.12系统不兼容启动失败问题处理
- AndroidStudio配置SVN以及第一次上传代码和关联svn
- iOS:KVO的概述与使用