spring+hibernate+mysql實現主從資料庫動態切換
阿新 • • 發佈:2019-02-13
註明:專案採用spring+springMVC+hibernate框架,mysql資料庫,配置採用javaConfig
本文實現的是mysql的一主一從配置,僅僅限於學習,用於專案中還需要很多處理。
版本:spring:4.2.5,springMVC:4.2.5,hibernate:5.2.4,AspectJ:1.8.9
一、配置mysql主從庫
這個就不多說了,網上一搜一大堆,也不是本文的重點。
二、hibernate配置
@Configuration
@EnableTransactionManagement
@ComponentScan(value = {"com.service" , "com.dao"})
@PropertySources(value = {@PropertySource("classpath:database.properties")})
public class HibernateConfig {
@Autowired
private Environment env;
@Bean
public DataSource masterDatasource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("master.jdbc.driverClassName" ));
dataSource.setUrl(env.getProperty("master.jdbc.url"));
dataSource.setUsername(env.getProperty("master.jdbc.username"));
dataSource.setPassword(env.getProperty("master.jdbc.password"));
//省去繁瑣的配置
return dataSource;
}
@Bean
public DataSource slaveDatasource () {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("slave.jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("slave.jdbc.url"));
dataSource.setUsername(env.getProperty("slave.jdbc.username"));
dataSource.setPassword(env.getProperty("slave.jdbc.password"));
//...
return dataSource;
}
@Bean
public DataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
//預設設定為從庫,因為查詢需求比增刪改要多;這裡可以根據專案需求更改(多從或多主結構)
dynamicDataSource.setDefaultTargetDataSource(slaveDatasource());
Map<Object, Object> targetDataSources = new HashMap();
targetDataSources.put("master", masterDatasource());
//接下來設定主庫,注意:master這個名字要和contextHolder的set的名字一樣
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
@Bean
public LocalSessionFactoryBean SessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
//...
return sessionFactory;
}
@Bean
public PlatformTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(SessionFactory().getObject());
return transactionManager;
}
}
註明:配置好master和slave;至於slave下面的datasource這是一個總的資料來源,hibernate的sessionFactory只和這個datasource關聯,具體呼叫哪個資料來源有datasource來決定。
DynamicDataSource:
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getType();
}
}
AbstractRoutingDataSource是spring管理多資料來源的一個抽象類。
DataSourceContextHolder:
public class DataSourceContextHolder {
//當前執行緒繫結的資料來源
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void master() {
contextHolder.set("master");
}
public static String getType() {
return contextHolder.get();
}
public static void remove() {
contextHolder.remove();
}
}
三、aop切面
@Aspect
public class DynamicChangeDataSourceAop {
@Pointcut("execution(* com.dao.impl.*.save*(..)) " +
"|| execution(* com.dao.impl.*.add*(..)) " +
"|| execution(* com.dao.impl.*.update*(..)) " +
"|| execution(* com.dao.impl.*.change*(..)) " +
"|| execution(* com.dao.impl.*.delete*(..)) " +
"|| execution(* com.dao.impl.*.del*(..))")
public void masterPointCut() {
}
@Around("masterPointCut()")
public void matserDataSource(ProceedingJoinPoint joinPoint) {
try {
DataSourceContextHolder.master();
System.out.println("----切換到主庫----");
joinPoint.proceed();
DataSourceContextHolder.remove();
} catch (Throwable throwable) {
throwable.printStackTrace(); //出錯了
}
}
}
首先是masterPointCut方法,定義的切點為:返回值不限,com.dao.impl下所有類以save/add/update/change/delete/del開頭的方法都要進入該切面,引數不限。
然後在呼叫proceed()之前切換到了主庫。
四、配置Aop
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"com.aop"})
public class AopConfig {
@Bean
public DynamicChangeDataSourceAop dynamicChangeDataSourceAop() {
return new DynamicChangeDataSourceAop();
}
}
在spring中建立aop切面的bean。
到此就完成了主從庫的動態切換了。