应用一
主数据源和应用数据源(代码中手动切换数据源)
1.jdbc.properties(连接两个库)jdbc.user=root jdbc.password=123456 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/survey?rewriteBatchedStatements=true log.url=jdbc:mysql://localhost:3306/survey_log?rewriteBatchedStatements=true
2.Spring配置文件的配置
3.定义一个类继承AbstractRoutingDataSource实现determineCurrentLookupKey方法,该方法可以实现数据库的动态切换,如下(方法返回的数据源的key值 根据key值去配响应的数据源)public class SurveyRouterDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { //尝试从当前线程获取令牌 String token = RouterToken.getToken(); //检测令牌是否等于日志数据源对应的键 if(RouterToken.DATASOURCE_LOG.equals(token)){ //当前线程上的令牌,在使用过后需要移除 //避免影响当前线程内其他的数据库操作 RouterToken.removeToken(); //如果是日志数据源对应的键,将日志数据源的键返回 return RouterToken.DATASOURCE_LOG; } //如果不是日志数据源对应的键则返回null采用默认的数据源(主数据源) return null; } }
4.将路由器数据源的key值绑定到本地线程中/** * 连接数据源的令牌,返回字符串,根据返回的字符串名称判定连接那个数据源 * @author dongdong */ public class RouterToken { // 声明一个本地线程 private static ThreadLocal local = new ThreadLocal(); // 将返回的字符串声明为静态全局final形式的 public static final String DATASOURCE_LOG = "DATASOURCE_LOG"; // 将字符串绑定到线程上 public static void bindToken(String token) { local.set(token); } // 获取当前线程的字符串 public static String getToken() { return local.get(); } //将当前线程的字符串移除 public static void removeToken(){ local.remove(); } }
5.代码中的使用//将路由器数据源的key绑定到当前线程,必须在Service方法前绑定,因为Service有事物,事物也要连接数据源 RouterToken.bindToken(RouterToken.DATASOURCE_LOG); Page page = logService.getPage(pageNoStr, Page.PAGE_SIZE_SMALL);
应用二
主数据源和从数据源(AOP实现自动数据源的切换)
1.jdbc.propertiesssjdbc.driver=com.mysql.jdbc.Driver #主数据库 jdbc.master.url=jdbc:mysql://192.168.0.68:3306/master_lxg jdbc.master.username=root jdbc.master.password=root #从数据库 jdbc.slaver.url=jdbc:mysql://192.168.0.12:3306/slave_lxg jdbc.slaver.username=root jdbc.slaver.password=root
2.Spring配置文件的配置
3.定义数据源的AOP切面,通过该Service的方法名判断是应该走读库还是写库,并且设置数据源public class DataSourceAspect { /** * 在进入Service方法之前执行 */ public void before(JoinPoint point) { // 获取到当前执行的方法名 String methodName = point.getSignature().getName(); if (isSlave(methodName)) { // 标记为从库 应当先clear一下 DBContextHolder.clearDBType (); DBContextHolder.setDBType(DBContextHolder.DATA_SOURCE_SLAVER); } else { // 标记为主库 应当先clear一下 DBContextHolder.clearDBType (); DBContextHolder.setDBType(DBContextHolder.DATA_SOURCE_MASTER); } } /** * 判断是否为读库 */ private Boolean isSlave(String methodName) { // 方法名以query、find、get开头的方法名走从库 return StringUtils.startsWithAny(methodName, "query", "find", "get"); } }4.定义一个类继承AbstractRoutingDataSource实现determineCurrentLookupKey方法,该方法可以实现数据库的动态切换,如下(方法返回的数据源的key值 根据key值去配响应的数据源)
public class DynamicDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return DBContextHolder.getDBType(); } }5.将路由器数据源的key值绑定到本地线程中
public class DBContextHolder{ public static final String DATA_SOURCE_MASTER = "Master"; public static final String DATA_SOURCE_SLAVER = "Slaver"; private static final ThreadLocal THREAD_LOCAL = new ThreadLocal(); public static void setDBType(String dbType) { THREAD_LOCAL.set(dbType); } public static String getDBType() { return THREAD_LOCAL.get(); } public static void clearDBType() { THREAD_LOCAL.remove(); } }