栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring + Mybatis 项目实现动态切换数据源实例详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring + Mybatis 项目实现动态切换数据源实例详解

项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库。

最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法。

参考了两篇文章如下:

https://www.jb51.net/article/111840.htm

https://www.jb51.net/article/111842.htm

这两篇文章都对原理进行了分析,下面只写自己的实现过程其他不再叙述。

实现思路是:

第一步,实现动态切换数据源:配置两个DataSource,配置两个SqlSessionFactory指向两个不同的DataSource,两个SqlSessionFactory都用一个SqlSessionTemplate,同时重写Mybatis提供的SqlSessionTemplate类,最后配置Mybatis自动扫描。

第二步,利用aop切面,拦截dao层所有方法,因为dao层方法命名的特点,比如所有查询sql都是select开头,或者get开头等等,拦截这些方法,并把当前数据源切换至从库。

spring中配置如下:

主库数据源配置:

 2 
 
 
 
 

从库数据源配置:

 
 
 
 
 
 

主库SqlSessionFactory配置:

 
 
  T selectOne(String statement) {
 return this.sqlSessionProxy. selectOne(statement);
 }
 
 public  T selectOne(String statement, Object parameter) {
 return this.sqlSessionProxy. selectOne(statement, parameter);
 }
 
 public  Map selectMap(String statement, String mapKey) {
 return this.sqlSessionProxy. selectMap(statement, mapKey);
 }
 
 public  Map selectMap(String statement, Object parameter, String mapKey) {
 return this.sqlSessionProxy. selectMap(statement, parameter, mapKey);
 }
 
 public  Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
 return this.sqlSessionProxy. selectMap(statement, parameter, mapKey, rowBounds);
 }
 
 public  List selectList(String statement) {
 return this.sqlSessionProxy. selectList(statement);
 }
 
 public  List selectList(String statement, Object parameter) {
 return this.sqlSessionProxy. selectList(statement, parameter);
 }
 
 public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
 return this.sqlSessionProxy. selectList(statement, parameter, rowBounds);
 }
 
 public void select(String statement, ResultHandler handler) {
 this.sqlSessionProxy.select(statement, handler);
 }
 
 public void select(String statement, Object parameter, ResultHandler handler) {
 this.sqlSessionProxy.select(statement, parameter, handler);
 }
 
 public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
 this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
 }
 
 public int insert(String statement) {
 return this.sqlSessionProxy.insert(statement);
 }
 
 public int insert(String statement, Object parameter) {
 return this.sqlSessionProxy.insert(statement, parameter);
 }
 
 public int update(String statement) {
 return this.sqlSessionProxy.update(statement);
 }
 
 public int update(String statement, Object parameter) {
 return this.sqlSessionProxy.update(statement, parameter);
 }
 
 public int delete(String statement) {
 return this.sqlSessionProxy.delete(statement);
 }
 
 public int delete(String statement, Object parameter) {
 return this.sqlSessionProxy.delete(statement, parameter);
 }
 
 public  T getMapper(Class type) {
 return getConfiguration().getMapper(type, this);
 }
 
 public void commit() {
 throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
 }
 
 public void commit(boolean force) {
 throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
 }
 
 public void rollback() {
 throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
 }
 
 public void rollback(boolean force) {
 throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
 }
 
 public void close() {
 throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");
 }
 
 public void clearCache() {
 this.sqlSessionProxy.clearCache();
 }
 
 public Connection getConnection() {
 return this.sqlSessionProxy.getConnection();
 }
 
 public List flushStatements() {
 return this.sqlSessionProxy.flushStatements();
 }
 
 private class SqlSessionInterceptor implements InvocationHandler {
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 final SqlSession sqlSession = getSqlSession(
  DynamicSqlSessionTemplate.this.getSqlSessionFactory(),
  DynamicSqlSessionTemplate.this.executorType, 
  DynamicSqlSessionTemplate.this.exceptionTranslator);
 try {
 Object result = method.invoke(sqlSession, args);
 if (!isSqlSessionTransactional(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory())) {
  // force commit even on non-dirty sessions because some databases require
  // a commit/rollback before calling close()
  sqlSession.commit(true);
 }
 return result;
 } catch (Throwable t) {
 Throwable unwrapped = unwrapThrowable(t);
 if (DynamicSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
  Throwable translated = DynamicSqlSessionTemplate.this.exceptionTranslator
  .translateExceptionIfPossible((PersistenceException) unwrapped);
  if (translated != null) {
  unwrapped = translated;
  }
 }
 throw unwrapped;
 } finally {
 closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory());
 }
 }
 }
}

SqlSessionContentHolder类代码如下:

package com.sincetimes.slg.framework.util;
public abstract class SqlSessionContentHolder {
 public final static String SESSION_FACTORY_MASTER = "master";
 public final static String SESSION_FACTORY_SLAVE = "slave";
 private static final ThreadLocal contextHolder = new ThreadLocal(); 
 public static void setContextType(String contextType) { 
 contextHolder.set(contextType); 
 } 
 public static String getContextType() { 
 return contextHolder.get(); 
 } 
 public static void clearContextType() { 
 contextHolder.remove(); 
 } 
}

最后就是写切面去对dao所有方法进行处理了,代码很简单如下:

package com.sincetimes.slg.framework.core;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import com.sincetimes.slg.framework.util.SqlSessionContentHolder;
@Aspect
public class DynamicDataSourceAspect {
 @Pointcut("execution( * com.sincetimes.slg.dao.*.*(..))")
 public void pointCut(){
 }
 @Before("pointCut()")
 public void before(JoinPoint jp){
 String methodName = jp.getSignature().getName(); 
 //dao方法查询走从库
 if(methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("count") || methodName.startsWith("list")){
 SqlSessionContentHolder.setContextType(SqlSessionContentHolder.SESSION_FACTORY_SLAVE);
 }else{
 SqlSessionContentHolder.setContextType(SqlSessionContentHolder.SESSION_FACTORY_MASTER);
 }
 }
}

以上所述是小编给大家介绍的Spring + Mybatis 项目实现动态切换数据源实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对考高分网网站的支持!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/146594.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号