需求背景
由于最近公司新項(xiàng)目需求,可能會(huì)用到多數(shù)據(jù)源懈凹,所以我開(kāi)始研究來(lái)一下,項(xiàng)目是基于SpringBoot2搭建的,springboot2默認(rèn)使用HikariCP作為數(shù)據(jù)庫(kù)連接池,這一點(diǎn)需要注意磨总,為啥使用這個(gè),請(qǐng)查看這個(gè)鏈接http://ju.outofmemory.cn/entry/353647來(lái)了解HikariCP連接池的性能笼沥,廢話不多說(shuō)蚪燕,上代碼。
代碼實(shí)現(xiàn)
- 數(shù)據(jù)源配置屬性
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;
}
}
- 動(dòng)態(tài)切換數(shù)據(jù)源
@Slf4j
@Data
public class DataSourceContextHolder {
/**
* 默認(rèn)數(shù)據(jù)源
*/
static final String DEFAULT_DS = "dataSourceFirst";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 設(shè)置數(shù)據(jù)源名
static void setDB(String dbType) {
log.debug("切換到{}數(shù)據(jù)源", dbType);
contextHolder.set(dbType);
}
// 獲取數(shù)據(jù)源名
static String getDB() {
return contextHolder.get();
}
// 清除數(shù)據(jù)源名
static void clearDB() {
contextHolder.remove();
}
}
- 創(chuàng)建動(dòng)態(tài)數(shù)據(jù)源
@Configuration
public class DataSourceConfig {
@Autowired
private DBProperties properties;
@Bean(name = "dynamicSource")
public DynamicDataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 添加數(shù)據(jù)源
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實(shí)現(xiàn)切換數(shù)據(jù)源邏輯
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(com.zqrock.productservice.config.DBSource)")
public void beforeSwitchDS(JoinPoint point){
//獲得當(dāng)前訪問(wèn)的class
Class<?> className = point.getTarget().getClass();
//獲得訪問(wèn)的方法名
String methodName = point.getSignature().getName();
//得到方法的參數(shù)的類型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DataSourceContextHolder.DEFAULT_DS;
try {
// 得到訪問(wèn)的方法對(duì)象
Method method = className.getMethod(methodName, argClass);
// 判斷是否存在@DS注解
if (method.isAnnotationPresent(DBSource.class)) {
DBSource annotation = method.getAnnotation(DBSource.class);
// 取出注解中的數(shù)據(jù)源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
// 切換數(shù)據(jù)源
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);
}
}
至此,全部核心代碼已都貼出,有問(wèn)題請(qǐng)及時(shí)留言,歡迎一起交流!