【www.bbyears.com--php应用】
在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库。Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询。因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,从而影响用户体验。我们通常的做法就是把查询从主库中抽取出来,采用多个从库,使用负载均衡,减轻每个从库的查询压力。
废话不多说,多数据源配置和主从数据配置原理一样
1、首先配置 jdbc.properties 两个数据库 A 和 B
#============ 双数据源 ======# #----------------------A servers--------------------------# A.driver=com.mysql.jdbc.Driver A.url=jdbc:mysql://localhost:3619/gps4?useUnicode=true&characterEncoding=utf8 A.username=gpsadmin A.password=1qaz&619 #----------------------B servers--------------------------# B.driver=com.mysql.jdbc.Driver B.url=jdbc:mysql://localhost:3619/gps6?useUnicode=true&characterEncoding=utf8 B.username=gpsadmin B.password=1qaz&619
2、配置 spring-mybatis.xml 文件【重要】
3、编写几个java类动态调用数据源【重要】
a:自定义一个注解,负责动态调用数据源
package com.ifengSearch.common.database; import java.lang.annotation.*; /** * 设置 数据源 注解标签的用法 写上注解标签, * 调用相应方法切换数据源咯(就跟你设置事务一样) * 【也可以配置 主从数据库】 * * @author flm * @2017年9月12日 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DataSource { public static String dataSourceA = "dataSourceA"; // A数据源 public static String dataSourceB = "dataSourceB"; // B数据源 String value(); }
b、数据源的获取 Object aop实现 (反射)
package com.ifengSearch.common.database; import java.lang.reflect.Method; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; /** * 数据源的获取 * aop实现 (反射) * @author flm * @2017年9月12日 */ public class DataSourceAspect{ private Logger log = Logger.getLogger(DataSourceAspect.class); public void before(JoinPoint point) { 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); DataSourceHolder.setDataSource(data.value()); log.info("数据源的获取 DataSource: "+data.value()); } } catch (Exception e) { log.error("数据源的获取 aop实现 出错:"+e.getMessage()); } } }
c、DataSourceHolder 数据源操作 获取数据源 帮助类
package com.ifengSearch.common.database; /** * 多数据源 * 数据源操作 获取数据源 * @author flm * @2017年9月12日 */ public class DataSourceHolder { //线程本地环境 private static final ThreadLocaldataSources = new ThreadLocal (); //设置数据源 public static void setDataSource(String customerType) { dataSources.set(customerType); } //获取数据源 public static String getDataSource() { return (String) dataSources.get(); } //清除数据源 public static void clearDataSource() { dataSources.remove(); } }
d、 我们还需要实现spring的抽象类AbstractRoutingDataSource,就是实现determineCurrentLookupKey方法:
package com.ifengSearch.common.database; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 多数据源 * 获取数据源(依赖于spring) * @author flm * @2017年9月12日 */ public class DynamicDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return DataSourceHolder.getDataSource(); } }
4、接下来就可以看结果了
我在dao层直接调用
public interface UserDao { /** * 登录判断 【数据源B】 */ @DataSource(value=DataSource.dataSourceB) public ListgetLoginUserList(@Param("loginName")String loginName,@Param("loginPwd")String loginPwd); /** * 查找上一级 服务商 【数据源A】 */ @DataSource(value=DataSource.dataSourceA) public UserBean getServerUser(@Param("u_last_id")Integer u_last_id); }