使用mybatis +spring 插件实现读写分离

     最近的项目中在数据库优化的时候需要用到读写分离,由于代码已经写好了,所以最优的方式就是在代码端不做任何修改,由于mybatis的灵活性,所以考虑用mybatis执行的时候通过插件的形式进行动态设置数据源。又由于spring支持数据源的懒加载和路由数据源的功能,所以最终解决方案是mybatis+spring数据源懒加载+spring动态数据源

   话不多说,直接上代码

   首先根据写一个动态数据源类去继承spring的AbstractRoutingDataSource类,重写他的determineCurrentLookupKey方法,从AbstractRoutingDataSource类中的

/**
	 * Retrieve the current target DataSource. Determines the
	 * {@link #determineCurrentLookupKey() current lookup key}, performs
	 * a lookup in the {@link #setTargetDataSources targetDataSources} map,
	 * falls back to the specified
	 * {@link #setDefaultTargetDataSource default target DataSource} if necessary.
	 * @see #determineCurrentLookupKey()
	 */
	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;
	}

这个方法主要用于通过key来获取对应的数据源

所以这个方法主要是获取数据源的key

public class DynamicDataSource extends AbstractRoutingDataSource {

	/*
	 * (non-Javadoc)
	 * @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()
	 */
	@Override
	protected Object determineCurrentLookupKey() {
		return DBContextHolder.getDbType();
	}
}

又由于多个线程可能都会使用到这个key所以为了避免各个线程之间相互干扰,所以借助一个DBContextHolder类来处理

public class DBContextHolder {

	private static Logger logger = Logger.getLogger(DBContextHolder.class);

	/**
	 * 线程ThreadLocal
	 */
	private static ThreadLocal contextHolder = new ThreadLocal<>();

	public static final String DB_TYPE_WR = "dbTypeWR";

	public static final String DB_TYPE_RD = "dbTypeRD";

	public static String getDbType() {
		String db = contextHolder.get();
		if(db == null) {
			db = DB_TYPE_WR;// 默认是读写库
		}
		return db;
	}

	/**
	 * @Title: setDbType
	 * @Description: 设置本线程的dbtype
	 * @author YiXiaoGang
	 * @date 2015年12月25日 下午3:04:49
	 * @param str
	 */
	public static void setDbType(String str) {
		logger.debug("所使用数据源为:" + str);
		contextHolder.set(str);
	}

	/**
	 * @Title: clearDBType
	 * @Description: 清理连接类型
	 * @author YiXiaoGang
	 * @date 2015年12月25日 下午3:05:00
	 */
	public static void clearDBType() {
		contextHolder.remove();
	}
}

到此,spring部分就做完了,最后,就是mybatis插件部分,对所有的update方法读取主数据源,对所有的query方法读取从数据源

@Intercepts({
		@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
		@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class,
				ResultHandler.class})}
		)
public class DatasouceInterceptor implements Interceptor {

		/**
	 * 插件方法更新
	 */
	private static final String UPDATE = "update";

	/**
	 * 插件方法查询
	 */
	private static final String QUERY = "query";

	Logger logger = Logger.getLogger(PagingInterceptor.class);

	/**
	 * SQL方言 可选MySql,Oracle
	 */
	private String diacect;

	/**
	 * mybatis插件拦截方法,用于分页,加解密
	 */
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		String methodName = invocation.getMethod().getName();
		MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
	
		if(QUERY.equals(methodName)) {
			DBContextHolder.setDbType(DBContextHolder.DB_TYPE_RD);
			return doQuery(invocation, fields, coditions);
		}else if(UPDATE.equals(methodName)) {
			DBContextHolder.setDbType(DBContextHolder.DB_TYPE_WR);
			return doUpdate(invocation, fields);
		}
		return null;
	}


   最后配置多数据源spring数据源部分如下

  


	
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
	
	
	
	
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
	

	
    
        
        
        
            
        
    
    
    
            
         
             
                 
                 
             
         
     
    
    
    
        
            
        
    


你可能感兴趣的:(java,笔记)