多数据源配置-使用spring配置多个数据源实现读写分离
来源:互联网 发布:女性情趣用品淘宝 编辑:程序博客网 时间:2024/05/20 02:26
我们在很多的项目中经常会有用到多个数据源。比如数据库读写分离,读操作都去从库里读,写操作都往主库里写。那么这里主库和从库就是两个不同的数据源。再比如要做两个数据库之间的数据转换,从一个数据库读取数据写到另一个数据库中,等等这些情况都需要系统使用两个或多个数据源。那么该如何配置多个数据源呢?我这里使用的是spring管理,数据库连接池使用的是阿里的druid。具体步骤如下:
1.修改spring的配置文件, 配置多个不同的数据源。这里不同的数据源就是由spring维护多个DruidDataSource的实例,每个实例都指定不同的数据库链接信息。配置如下:
1.修改spring的配置文件, 配置多个不同的数据源。这里不同的数据源就是由spring维护多个DruidDataSource的实例,每个实例都指定不同的数据库链接信息。配置如下:
<!-- 配置多数据源 ,druid --> <bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.master.url}" /> <property name="username" value="${jdbc.master.username}" /> <property name="password" value="${jdbc.master.password}" /> <property name="driverClassName" value="${jdbc.master.driver}" /> <!-- 最大连接池数量 --> <property name="maxActive" value="${master.maxActive}" /> <!-- 获取连接时最大等待时间,单位毫秒。 配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 --> <property name="maxWait" value="60000" /> <!-- 建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 --> <property name="testWhileIdle" value="true"></property> <property name="filters" value="stat"></property> </bean> <!-- 配置多数据源 ,druid --> <bean id="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.slave1.url}" /> <property name="username" value="${jdbc.slave1.username}" /> <property name="password" value="${jdbc.slave1.password}" /> <property name="driverClassName" value="${jdbc.slave1.driver}" /> <!-- 最大连接池数量 --> <property name="maxActive" value="${slave1.maxActive}" /> <!-- 获取连接时最大等待时间,单位毫秒。 配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 --> <property name="maxWait" value="60000" /> <!-- 建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 --> <property name="testWhileIdle" value="true"></property> <property name="filters" value="stat"></property> </bean>
我这里主要配置了两个数据源,一个是主库的数据源,名字叫masterDataSource,还有一个是从库的数据源,名字叫slaveDataSource
2.选择要使用的数据源。我们有了数据源之后我们要使用哪一个呢,所以这个时候我们需要来定义一个类,指定选择哪一个数据源,这里也很简单,只要继承spring给我们提供的AbstractRoutingDataSource类就可以了,这是一个抽象类,需要重写determineCurrentLookupKey方法,这个方法就是用来选择哪一个数据源的。
我们先给两个数据源分别打个标记,比如,读库的源就叫slave,写库的叫master,在实现这个方法的时候,我们返回一个字符串'slave' 表示要找读库,返回一个master表示要找主库。既然要动态的返回,我们就需要有一个入口能够设置选择的标记。在多线程环境下,为了保证数据安全,可以使用ThreadLocal这个类。代码如下
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DbContextHolder.getDataSource(); }}
DbContextHolder的代码如下
public class DbContextHolder { public static final String master = "master"; public static final String slave = "slave"; private static ThreadLocal<String> ds = new ThreadLocal<>(); public static void setDataSource (String dataSource) { ds.set(dataSource); } public static String getDataSource() { return ds.get(); }}
3.继续配置文件,不管我们配置了几个数据源,同一时刻生效的只有一个,于是我们要通过DynamicDataSource这个类来告诉spring我们要使用哪个数据源
<bean id="dataSource" class="com.hy.base.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" /> </bean>
这里要注意,key就是我们上面说到的标记,需要和DbContextHolder里的常量配置的相同。
到这一步,我们就可以说配置完成了,代码中就可以指定数据源,来进行数据库操作。当然我们为了更加方便,我们可以使用注解的方式来选择使用哪一个数据源,首先定义注解类
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface DataSource { String value();}
我们希望呢,在方法上打上这个注解,当这个方法执行前,我们就调用setDataSource方法来设置注解中指定的值,这样也就不需要手动设置了。下面是定义切面
public class DataSourceAspect { public void before(JoinPoint point) {// System.out.println("--------------------------"); Object target = point.getTarget(); String method = point.getSignature().getName(); Class<?>[] classz = target.getClass().getInterfaces(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes(); try { Method m = classz[0].getMethod(method, parameterTypes); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource data = m .getAnnotation(DataSource.class); DbContextHolder.setDataSource(data.value()); System.out.println(data.value()); } } catch (Exception e) {// e.printStackTrace(); } }}
下面对切面进行配置
<aop:aspectj-autoproxy> </aop:aspectj-autoproxy> <bean id="manyDataSourceAspect" class="com.hy.base.db.DataSourceAspect" /> <aop:config> <aop:aspect id="c" ref="manyDataSourceAspect"> <aop:pointcut id="tx1" expression="execution(* *(..))" /> <aop:before pointcut-ref="tx1" method="before" /> </aop:aspect> </aop:config>
OK,到现在就大功告成。下面进行测试。我们使用的是mybatis,这里的具体配置就不给大家贴了。执行两个操作,分别针对两个库,如果两个库都能正常的响应,就说明我们的配置成功了。下面的例子就是两个接口,一个去找主库,一个去找从库,分别查询在某个数据库中唯一的一张表,主库的t1表只有主库有,从库的t2表只有从库有,这样如果都能查出来数据,说名两个库都是可以连接的。下面是具体的代码。
1.mapper,两个接口,一个使用主库,一个使用从库
public interface AppMapper {
@DataSource("master")
List<Map<String, Object>> executeQuery(@Param("sql")String sql);
@DataSource("slave")
List<Map<String, Object>> executeQuery2(@Param("sql")String sql);
}
2.测试方法
@Test
public void testDatasource() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
AppMapper mapper = (AppMapper) ac.getBean("appMapper");
String sql = "select * from t1 limit 0,10";
System.out.println(mapper.executeQuery(sql));
sql = "select * from t2";
System.out.println(mapper.executeQuery2(sql));
}
这两个表在主库和从库都是唯一的。我们发现都能查出数据,说明我们配置正确了。当然了,这里数据库并没有做主从。
阅读全文
1 0
- 多数据源配置-使用spring配置多个数据源实现读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- spring多数据源配置,实现读写分离
- Spring配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- Spring 配置多数据源实现数据库读写分离
- spring+mybatis多数据源配置、读写分离
- MyBatis多数据源配置实现读写分离
- MyBatis多数据源配置(读写分离)
- MyBatis多数据源配置(读写分离)
- MyBatis多数据源配置(读写分离)
- spring hibernate配置切换数据源,实现读写分离
- java-durid、mybatis、spring 整合基于 AbstractRoutingDataSource 的多数据源读写分离配置
- Java学习day4
- 文件存取
- JAVA内部类
- iOS启动动画
- android APK应用安装过程以及默认安装路径
- 多数据源配置-使用spring配置多个数据源实现读写分离
- 函数指针和指针函数的区别
- 排序列表转换为二分查找树-LintCode
- JAVA虚拟机系列(六)
- 刨根问底KVC
- UVA1391【LA3713】 经典2-SAT
- Java中String类的concat方法
- MyBatis的resultMap简介
- 基于freemarker在本地生成word(.doc)文档,只看这一篇就够了