复制第八节的项目,重命名为quartz-mybatis-multi-dynamic
动态数据源,本项目通过AOP注解的方式实现动态数据源。两个数据源已经在上几节中建立。
1、pom文件省略和第八节相同
2、配置文件:
#datasource config
jdbc:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1/bpm?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
username: root
password: 123
#datasource config2
jdbc2:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1/goods?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
username: root
password: 123
#mybatis config
mybatis:
typeAliasesPackage: com.hotkidceo.springcloud.domain
mapperLocations: classpath:mapper/bpm/*.xml
3、增加两个工具类到util包下
第一个:DataSourceContextHolder 主要用于对访问线程设置数据源名称
public class DataSourceContextHolder {
public static final Logger log = LoggerFactory.getLogger(DataSourceContextHolder.class);
public static final String DEFAULT_DS = "bpmDS";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 设置数据源名
public static void setDB(String dbType) {
log.debug("切换到{}数据源", dbType);
contextHolder.set(dbType);
}
// 获取数据源名
public static String getDB() {
return (contextHolder.get());
}
// 清除数据源名
public static void clearDB() {
contextHolder.remove();
}
}
第二个:DynamicDataSource 继承 AbstractRoutingDataSource类
关于AbstractRoutingDataSource请参照https://blog.csdn.net/fangdengfu123/article/details/70139644
public class DynamicDataSource extends AbstractRoutingDataSource{
private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
log.debug("数据源为{}", DataSourceContextHolder.getDB());
return DataSourceContextHolder.getDB();
}
}
4、在config包下,修改DataSourceConfig类
增加如下代码:
/**
* 动态数据源: 通过AOP在不同数据源之间动态切换
* @return
*/
@Bean(name = "dynamicDS")
public DataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSourceBPM());
// 配置多数据源
Map<Object, Object> dsMap = new HashMap(5);
dsMap.put("bmpDS", dataSourceBPM());
dsMap.put("goodsDS", dataSourceGoods());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
5、在config包下,增加动态数据源配置类MybatisDBDynamicConfig(把同包下其他的配置类的注解@@Configuration注释掉,避免混淆)
@Configuration
@MapperScan(basePackages = {"com.hotkidceo.springcloud.dao.bpm"},sqlSessionFactoryRef="sqlSessionFactory")
public class MybatisDBDynamicConfig {
@Autowired
private Environment env;
@Autowired
@Qualifier("dynamicDS")
private DataSource dynamicDS;
@Bean
@Primary
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dynamicDS);
//下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加
factoryBean.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations")));
return factoryBean.getObject();
}
@Bean
@Primary
public SqlSessionTemplate sqlSessionTemplateBPM() throws Exception {
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory()); // 使用上面配置的Factory
return template;
}
}
6、新建切面类 DynamicDataSourceAspect,对注解DS进行切面,之前更新数据源的名称,之后将清空
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(DS)")
public void beforeSwitchDS(JoinPoint point){
// 获得当前访问的class
Class<?> className = point.getTarget().getClass();
// 获得访问的方法名
String methodName = point.getSignature().getName();
// 得到方法的参数的类型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DataSourceContextHolder.DEFAULT_DS;
try {
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass);
// 判断是否存在@DS注解
if(method.isAnnotationPresent(DS.class)){
DS annotaion = method.getAnnotation(DS.class);
// 取出注解中的数据源名
dataSource = annotaion.value();
}
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 切换数据源
DataSourceContextHolder.setDB(dataSource);
}
@After("@annotation(DS)")
public void afterSwitchDS(JoinPoint point){
DataSourceContextHolder.clearDB();
}
}
至此,配置完成,调用userController的不同方法会进入不同的数据库中操作。主要原因是注解,如下:
@Service
public class UserService {
@Autowired
private UserDao userDao;
@DS("bpmDS")
public int addUser(UserDO user){
return userDao.insert(user);
}
public UserDO getUserById(Long id){
return userDao.selectByPrimaryKey(id);
}
@DS("goodsDS")
public List<UserDO> getAllUsers(){
return userDao.getAllUsers();
}
}
请大家自行尝试
git地址:https://gitee.com/EricLoveMia/eureka-client-test-quartz-mybatis-muti-dynamic.git