1. 程式人生 > >spring+hibernate+mysql實現主從資料庫動態切換

spring+hibernate+mysql實現主從資料庫動態切換

註明:專案採用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。

到此就完成了主從庫的動態切換了。