登录
    Technology changes quickly but people's minds change slowly.

spring boot 动态多数据源配置(mybatis+jpa)

javaweb笔记 破玉 1555次浏览 0个评论

   因为系统里需要同时用到多个数据源,于是对mybatis以及jpa都做了多数据源的一些配置。原理呢就是利用切面的前置通知加注解的方式实现动态切换数据源。

创建一个注解

  创建该注解的目的是利用注解的value告诉程序我们需要切换的目标数据源名称是哪个。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface  DataSource {
    String value() default "";
}

创建DataSourceHolder

  该目的是用于持有当前线程中使用的数据源标识。

public class DataSourceHolder {
    private  static  final ThreadLocal contextHolder=new ThreadLocal();

    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static String getDataSourceType() {
        return contextHolder.get();
    }

    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

重写查找数据源标识的方法

  AbstractRoutingDataSource获取数据源之前会先调用determineCurrentLookupKey方法查找当前的lookupKey,这个lookupKey就是数据源标识。
因此通过重写查找数据源标识的方法就可以让spring切换到指定的数据源了。

public class RoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceHolder.getDataSourceType();
    }
}

配置基本的数据源bean

@Configuration
public class BaseDataSourceConfig {

    @Bean(name = "oracleDataSource")
    @Qualifier("oracleDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.oracle")
    public DataSource oracleDataSource(){
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "mysqlDataSource")
    @Qualifier("mysqlDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.mysql")
    public DataSource mysqlDataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name="routingDataSource")
    public RoutingDataSource dataSource(){
        RoutingDataSource dataSource=new RoutingDataSource();
        Map targetDataSource=new HashMap();
        targetDataSource.put("mysql",mysqlDataSource());
        targetDataSource.put("oracle",oracleDataSource());
        dataSource.setTargetDataSources(targetDataSource);
        dataSource.setDefaultTargetDataSource(oracleDataSource());
        return  dataSource;
    }

配置Jpa数据源


@Configuration
@EnableJpaRepositories(basePackages = "com.magicdu.e300pro.dataquery.dao.repository")
@EntityScan(basePackages = "com.magicdu.e300pro.dataquery.entity")
public class JpaDatasourceConfig {
    @Bean
    public JdbcTemplate jdbcTemplate(RoutingDataSource  dataSource){
        return new JdbcTemplate(dataSource);
    }

    @Bean("entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(RoutingDataSource dataSource, JpaVendorAdapter jpaVendorAdapter){
        LocalContainerEntityManagerFactoryBean entityManagerFactory=new LocalContainerEntityManagerFactoryBean();
        entityManagerFactory.setDataSource(dataSource);
        entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
        entityManagerFactory.setPackagesToScan("com.magicdu.e300pro.dataquery.*");
        return entityManagerFactory;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter(){
        HibernateJpaVendorAdapter jpaVendorAdapter=new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setDatabase(Database.ORACLE);
        jpaVendorAdapter.setShowSql(true);
        jpaVendorAdapter.setGenerateDdl(false);
        jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.Oracle10gDialect");
        return jpaVendorAdapter;
    }
    @Bean("transactionManager")
    public PlatformTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
        JpaTransactionManager transactionManager
                = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject());
        return transactionManager;
    }

配置mybatis数据源


@Configuration
@MapperScan(basePackages = "com.magicdu.e300pro.dataquery.dao.mapper")
@EnableTransactionManagement
public class MybatisDataSourceConfig {


    @Bean
    public SqlSessionFactory sqlSessionFactory(RoutingDataSource dataSource) throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager( RoutingDataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

最重要的一步,配置切面以及前置通知

  这一步的目的是根据注解通过切面自动识别数据源,并切换当前线程中的数据源


@Aspect
@Order(-1) //ensure execute the aop before @Transactional
@Component
public class DataSourceAspect {
    public DataSourceAspect(){
        System.err.println("execution(* com.bickcess.haji.dao..*.*(..))");
    }

   @Pointcut("execution(* com.magicdu.e300pro.dataquery.dao.mapper.*.*(..)) || execution(* com.magicdu.e300pro.dataquery.dao.repository.*.*(..))")
    private  void  anyMethod(){

    }
    @AfterReturning(value ="anyMethod()",returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result){
        DataSourceHolder.clearDataSourceType();
    }

    @Before(value="anyMethod()")
    public void before(JoinPoint joinPoint) throws Throwable {
        System.err.println("performing announce ");
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        //if method use DataSource annotation
        if (method.isAnnotationPresent(DataSource.class)) {
            //get annotation name of the method
            DataSource datasource = method.getAnnotation(DataSource.class);
            System.err.println(datasource.value());
            //assign  the value of annotation to the datasource holder class
            DataSourceHolder.setDataSourceType(datasource.value());
        }
    }

}

华裳绕指柔, 版权所有丨如未注明 , 均为原创|转载请注明spring boot 动态多数据源配置(mybatis+jpa)
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址