一个项目中数据源(连接不同库 JDBC)的个数,是由内存大小决定的。
整合数据源的方式可分为:包名(业务)、注解方式。
包名:类似于多个不同 jar,不同业务需求。多个不同的业务需求,存放同一个项目中。
注解:在service实现类的方法上或者mapper上加注解
项目结构:(因为我的项目引入了 tk.mapper、日志切面、lombok 所以有些在引入包扫描的时候会不一样,大家可以根据需要做处理)
启动类: 需要在启动类注解上加 (exclude = DataSourceAutoConfiguration.class) 否则会报循环依赖错误
import com.hcg.multiplydatasourceofanno.common.business.CommonMapper;
import lombok.extern.slf4j.Slf4j;
//import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@Slf4j
@MapperScan(basePackages = "com.hcg.multiplydatasourceofanno.mapper",markerInterface = CommonMapper.class)
public class MultiplydatasourceofannoApplication {
public static void main(String[] args) {
log.info("*********项目启动开始***********");
SpringApplication.run(MultiplydatasourceofannoApplication.class, args);
log.info("*********项目启动完成***********");
}
}
AnnoDynamicDataSource 类
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
public class AnnoDynamicDataSource extends AbstractRoutingDataSource {
//用来保存数据源与获取数据源
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public AnnoDynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(new HashMap<>(targetDataSources));
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
DataSourceAspect :
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 多数据源,切面处理类 处理带有注解的方法类
*/
@Aspect
@Component
@Slf4j
public class DataSourceAspect implements Ordered {
//注意:这里的xxxx代表的是上面public @interface DataSource这个注解DataSource的包名
@Pointcut("@annotation(com.hcg.multiplydatasourceofanno.config.datasource.MultiDataSource)")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
MultiDataSource ds = method.getAnnotation(MultiDataSource.class);
if (ds == null) {
AnnoDynamicDataSource.setDataSource(DataSourceNames.HCG);
log.info("set datasource is " + DataSourceNames.HCG);
} else {
AnnoDynamicDataSource.setDataSource(ds.name());
log.debug("set datasource is " + ds.name());
}
try {
return point.proceed();
} finally {
AnnoDynamicDataSource.clearDataSource();
log.debug("clean datasource");
}
}
@Override
public int getOrder() {
return 1;
}
}
DataSourceNames :
public interface DataSourceNames {
String HCG = "hcg";
String CM = "cm";
}
DynamicDataSourceConfig:
//import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import tk.mybatis.spring.annotation.MapperScan;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* 配置多数据源
*/
@Configuration
@MapperScan(basePackages = "com.hcg.multiplydatasourceofanno.mapper")
public class DynamicDataSourceConfig {
@Bean
@Qualifier("cmDataSource")
@ConfigurationProperties(prefix = "spring.datasource.cm") // 扫描application 配置文件时的前缀
public DataSource cmDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "hcgDataSource")
@Qualifier("hcgDataSource") // 依赖注入时候的名字
@ConfigurationProperties(prefix = "spring.datasource.hcg") // 扫描application 配置文件时的前缀
// @Primary
public DataSource hcgDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
public AnnoDynamicDataSource dataSource(DataSource hcgDataSource, DataSource cmDataSource) {
Map<String, DataSource> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceNames.HCG, hcgDataSource);
targetDataSources.put(DataSourceNames.CM, cmDataSource);
return new AnnoDynamicDataSource(hcgDataSource, targetDataSources);
}
@Bean(name = "transactionManager")
public DataSourceTransactionManager TransactionManager(DataSource dataSource) throws Exception{
return new DataSourceTransactionManager(dataSource);
}
/* @Bean(name = "cmTransactionManager")
public DataSourceTransactionManager cmTransactionManager(DataSource cmDataSource) throws Exception{
return new DataSourceTransactionManager(cmDataSource);
}
@Bean(name = "hcgTransactionManager")
public DataSourceTransactionManager hcgTransactionManager(DataSource hcgDataSource) throws Exception{
return new DataSourceTransactionManager(hcgDataSource);
}*/
}
MultiDataSource :
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MultiDataSource {
String name() default "";
}
service接口实现类:
import com.hcg.multiplydatasourceofanno.config.datasource.MultiDataSource;
import com.hcg.multiplydatasourceofanno.domain.User;
import com.hcg.multiplydatasourceofanno.mapper.CmUserMapper;
import com.hcg.multiplydatasourceofanno.service.CmUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("cmUserService")
public class CmUserServiceImpl implements CmUserService {
@Autowired
private CmUserMapper cmUserMapper;
@Override
/*
* @Transactional(transactionManager = "cmTransactionManager")
* 如果这样配置的话 config 需要根据 service 写 n 个不同的 manager
*/
/*@Transactional(transactionManager = "transactionManager")*/ // 只需要一个
@Transactional // 不用指定 transactionManager
@MultiDataSource(name = "cm")
public void saveUser(User user) {
cmUserMapper.insert(user);
int i = 1/0;
// cmUserMapper.addUser(user.getUid(),user.getNickname(),user.getName(),user.getPassword(),user.getSalt(), user.getMobile());
}
}
application 配置文件和分包的一样
————————————————
版权声明:本文为CSDN博主「依着风睡_hcg」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/haochaoguo1988/article/details/86747005