此方法是在需要使用的地方加上自定义注解@DataSource
根据注解下这个方法的传参 注意: (规定参数命名)
配置文件yml
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 5
maximum-pool-size: 15
auto-commit: true
idle-timeout: 30000
pool-name: HikariCP
max-lifetime: 1800000
connection-timeout: 30000
ds1:
jdbc-url: jdbc:mysql://localhost:3306/pubs?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
username: root
password: 1234
driver-class-name: com.mysql.jdbc.Driver
ds2:
jdbc-url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
username: root
password: 1234
driver-class-name: com.mysql.jdbc.Driver
config配置文件
/**
* 配置Druid 多个数据源和 Druid监控Servlet
*
* 所有的数据源配置都在这里 要添加多个的话
*
* */
@Configuration
public class DataSourceConfig {
private static final Logger log = LoggerFactory.getLogger(DataSourceConfig.class);
//数据源一
@Bean(name = "dataSource1" )
@ConfigurationProperties(prefix="spring.datasource.ds1")
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
//数据源二
@Bean(name = "dataSource2" )
@ConfigurationProperties(prefix="spring.datasource.ds2")
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
}
@Bean(name = "dataSource3" )
@ConfigurationProperties(prefix="spring.datasource.ds3")
public DataSource dataSource3() {
return DataSourceBuilder.create().build();
}
/**
* 记得添加完数据源后要在这里添加到dynamicDataSource中
* 动态数据源: 通过AOP在不同数据源之间动态切换
* */
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource(); //动态数据源配置类
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSource1());
// 配置多数据源
Map<Object, Object> dsMap = new HashMap();
dsMap.put("dataSource1", dataSource1());
dsMap.put("dataSource2", dataSource2());
dsMap.put("dataSource3", dataSource3());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
<!-------------------------------mybatis---------------->
/**
* 配置@Transactional注解事物
* @return
*/
@Bean(name = "dataSourceTransactionManager1")
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource1());
}
@Bean(name = "dataSourceTransactionManager2")
public PlatformTransactionManager transactionManager2() {
return new DataSourceTransactionManager(dataSource2());
}
@Bean(name = "dataSourceTransactionManager3")
public PlatformTransactionManager transactionManager2() {
return new DataSourceTransactionManager(dataSource2());
}
}
//jpa配置事务<!----------------------jpa------------------------->
@Configuration
public class TransactionManagerConfig implements TransactionManagementConfigurer {
@Resource(name="transactionManager")
private PlatformTransactionManager txManager;
// // 创建事务管理器1
// @Bean(name = "txManager1")
// public PlatformTransactionManager txManager(DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource);
// }
// 创建事务管理器
@Bean(name = "transactionManager")
public PlatformTransactionManager txManager(EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
//其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager;
}
/**
* 动态数据源
* 配置当前数据源源和默认数据源
* 设置清除数据源等操作
* */
public class DynamicDataSource extends AbstractRoutingDataSource {
public static final String DEFAULT_DS = "dataSource1";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 设置数据源名
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
//获取数据源
public static String getDataSource() {
return contextHolder.get();
}
//清除数据源
public static void clearDataSource() {
contextHolder.remove();
}
//当前数据源
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
//自定义接口
/**
* 多数据源注解默认pcv
*/
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
String value() default "dataSource1";
}
//动态数据源切面
@Aspect
@Component
public class DynamicDataSourceAspect {
@Autowired
HttpSession session;
@Before("@annotation(DataSource)")
public void beforeSwitchDS(JoinPoint point) {
//获得当前访问的class
Class<?> className = point.getTarget().getClass();
//获得访问的方法名
String methodName = point.getSignature().getName();
//得到方法的参数的类型
Class[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
String dataSource = DynamicDataSource.DEFAULT_DS;
try {
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass);
// 判断是否存在@DataSource注解
if (method.isAnnotationPresent(DataSource.class)) {
DataSource annotation = method.getAnnotation(DataSource.class);
//1.这里获取到所有的参数值的数组
Object[] args = point.getArgs();
Signature signature = point.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
//2.最关键的一步:通过这获取到方法的所有参数名称的字符串数组
String[] parameterNames = methodSignature.getParameterNames();
Map<String, Object> aopParams = getAopParams(args, parameterNames);//得到参数的键值对
dataSource = Optional.ofNullable(aopParams.get("dataSource"))
.flatMap(m->Optional.ofNullable(DataSourceEnum.getValueByCode(m.toString()))).orElse(dataSource);
//第二种
/*if (aopParams.containsKey("dataSource")) {
if (StringUtils.isEmpty(aopParams.get("dataSource"))) {
dataSource = annotation.value();
} else {
//枚举中是否有这个值
if (StringUtils.isEmpty(DataSourceEnum.getValueByCode(aopParams.get("dataSource").toString()))) {
dataSource = annotation.value();
} else {
dataSource = DataSourceEnum.getValueByCode(aopParams.get("dataSource").toString());
}
}
} else {
dataSource = annotation.value();
}*/
}
} catch (Exception e) {
e.printStackTrace();
}
// 切换数据源
DynamicDataSource.setDataSource(dataSource);
}
@After("@annotation(DataSource)")
public void afterSwitchDS(JoinPoint point) {
DynamicDataSource.clearDataSource();
}
/**
* @Description: 方法是aop拦截方法得到方法中的变量和值 返回一个map
* @param: args :所有的value集合 item 所有的key集合
* @return: Map<String, Object>
* @auther: 汪亚平
* @date: 2020/10/16 10:19
*/
public static Map<String, Object> getAopParams(Object[] args, String[] item) {
Map<String, Object> map = new HashMap<>();
for (int i = 0; i < item.length; i++) {
map.put(item[i], args[i]);
}
return map;
}
使用mybatisplus进行操作
如果使用了@Transactional 添加事物 记得添加是哪个事物
public class DemoServiceImpl extends ServiceImpl<Demo, Student> implements DemoService{
@DataSource
@Override
@Transactional(rollbackFor = Exception.class, transactionManager = "dataSourceTransactionManager2")
public void saveStudent(List<Student> student,String dataSource) {
//System.out.println(student.toString());
System.out.println(list().toString()+"-------"+dataSource);
saveBatch(student);
}
@DataSource
@Override
public List<Student> queryList(String dataSource) {
System.out.println(list().toString()+"----------"+dataSource);
return list();
}