需求背景
由于最近公司新项目需求,可能会用到多数据源,所以我开始研究来一下,项目是基于SpringBoot2搭建的,springboot2默认使用HikariCP作为数据库连接池,这一点需要注意,为啥使用这个,请查看这个链接http://ju.outofmemory.cn/entry/353647来了解HikariCP连接池的性能,废话不多说,上代码。
代码实现
- 数据源配置属性
hikari.master.jdbc-url=jdbc:mysql://localhost:3306/bus_data?serverTimezone=UTC&useSSL=true
hikari.master.username=root
hikari.master.password=123456
hikari.master.maximum-pool-size=20
hikari.master.pool-name=master
hikari.master.connection-timeout=30000
hikari.master.idle-timeout=600000
hikari.master.max-lifetime=1765000
hikari.slave.jdbc-url=jdbc:mysql://localhost:3306/bus_data_read?serverTimezone=UTC&useSSL=true
hikari.slave.username=root
hikari.slave.password=123456
hikari.slave.maximum-pool-size=80
hikari.slave.pool-name=slave
hikari.slave.connection-timeout=30000
hikari.slave.idle-timeout=600000
hikari.slave.max-lifetime=1765000
hikari.slave.read-only=true
- 注入配置
/**
* TODO
*
* @author zhaoqing
* @Description
* @createTime 2018/7/13 23:57
*/
@Component
@ConfigurationProperties(prefix = "hikari")
public class DBProperties {
private HikariDataSource master;
private HikariDataSource slave;
public HikariDataSource getMaster() {
return master;
}
public void setMaster(HikariDataSource master) {
this.master = master;
}
public HikariDataSource getSlave() {
return slave;
}
public void setSlave(HikariDataSource slave) {
this.slave = slave;
}
}
- 动态切换数据源
@Slf4j
@Data
public class DataSourceContextHolder {
/**
* 默认数据源
*/
static final String DEFAULT_DS = "dataSourceFirst";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 设置数据源名
static void setDB(String dbType) {
log.debug("切换到{}数据源", dbType);
contextHolder.set(dbType);
}
// 获取数据源名
static String getDB() {
return contextHolder.get();
}
// 清除数据源名
static void clearDB() {
contextHolder.remove();
}
}
- 创建动态数据源
@Configuration
public class DataSourceConfig {
@Autowired
private DBProperties properties;
@Bean(name = "dynamicSource")
public DynamicDataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 添加数据源
Map<Object, Object> dsMap = new HashMap<>(5);
dsMap.put("dataSourceFirst", properties.getMaster());
dsMap.put("dataSourceSecond", properties.getSlave());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
}
- 定义注解
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface DBSource {
String value() default "dataSourceFirst";
}
- 用AOP实现切换数据源逻辑
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(com.zqrock.productservice.config.DBSource)")
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(DBSource.class)) {
DBSource annotation = method.getAnnotation(DBSource.class);
// 取出注解中的数据源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
// 切换数据源
DataSourceContextHolder.setDB(dataSource);
}
@After("@annotation(com.zqrock.productservice.config.DBSource)")
public void afterSwitchDS(JoinPoint point){
DataSourceContextHolder.clearDB();
}
}
- DAO配置
import com.zqrock.productservice.config.DBSource;
import com.zqrock.productservice.dao.mapper.UserMapper;
import com.zqrock.productservice.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
*
*
* @author zhaoqing
* @Description
* @createTime 2018/7/13 21:50
*/
@Repository
public class UserDao {
private final UserMapper userMapper;
@Autowired(required = false)
public UserDao(UserMapper userMapper) {
this.userMapper = userMapper;
}
@DBSource("dataSourceFirst")
public List<User> getAllUsers(){
return userMapper.getAllUsers();
}
@DBSource("dataSourceSecond")
public User getUserById(int id){
return userMapper.getUserById(id);
}
}
至此,全部核心代码已都贴出,有问题请及时留言,欢迎一起交流!
网友评论