import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey(){ return DynamicDataSourceHolder.getDbType(); } }
import org.slf4j.LoggerFactory; import org.slf4j.Logger; public class DynamicDataSourceHolder { private static Logger logger=LoggerFactory.getLogger(DynamicDataSourceHolder.class); private static ThreadLocal<String> contextHolder=new ThreadLocal<String>();//保证线程安全 public static final String DB_MASTER="master"; public static final String DB_SLAVE="slave"; public static String getDbType(){ String db=contextHolder.get(); if(db==null){ db=DB_MASTER; } return db; } public static void setDbType(String str){ logger.debug("所使用的数据源为:"+str); contextHolder.set(str); } //清理连接类型 public static void clearDBType(){ contextHolder.remove(); } }
import java.util.Locale; import java.util.Properties; import java.util.concurrent.Executor; import org.apache.ibatis.executor.keygen.SelectKeyGenerator; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.support.TransactionSynchronizationManager; /** * @author wls * */
@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 DynamicDataSourceInterceptor implements Interceptor{ private static Logger logger=LoggerFactory.getLogger(DynamicDataSourceInterceptor.class); private static final String REGEX= ".*insert\u0020.*|.*delete\u0020.*|.8update\u0020.*"; @Override public Object intercept(Invocation invocation) throws Throwable { //判断当前是不是事物 boolean synchronizatioinActive=TransactionSynchronizationManager. isActualTransactionActive(); Object[] objects= invocation.getArgs(); MappedStatement ms=(MappedStatement)objects[0]; String lookupKey=DynamicDataSourceHolder.DB_MASTER; if(synchronizatioinActive!=true){ //读方法 if(ms.getSqlCommandType().equals(SqlCommandType.SELECT)){ //SELECT_KEY为自增id查询主键SELECT LAST_INSERT_ID(),使用主库 if(ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)){ lookupKey=DynamicDataSourceHolder.DB_MASTER; }else{ BoundSql boundSql=ms.getSqlSource().getBoundSql(objects[1]); String sql=boundSql.getSql().toLowerCase(Locale.CHINA). replaceAll("[\t\n\r]", " "); if(sql.matches(REGEX)){ lookupKey=DynamicDataSourceHolder.DB_MASTER; //增删改 }else{ lookupKey=DynamicDataSourceHolder.DB_SLAVE; //查,从库 } } } } else{ lookupKey=DynamicDataSourceHolder.DB_MASTER; } logger.debug("设置方法[{}] use[{}]Strategy,SqlCommanType[{}]" ,ms.getId(),lookupKey, ms.getSqlCommandType().name());; DynamicDataSourceHolder.setDbType(lookupKey); return invocation.proceed(); } @Override //返回封装好的对象 public Object plugin(Object target) { // TODO Auto-generated method stub if(target instanceof Executor){ return Plugin.wrap(target, this); }else{ return target; } } @Override public void setProperties(Properties arg0) { // TODO Auto-generated method stub } }
配置:
mybatis配置:
<plugins> <plugin interceptor="split.DynamicDataSourceInterceptor"></plugin> </plugins>