Java JPA 多数据源查询 支持动态sql动态查询

背景介绍
需要对两个mysql的数据库做数据对比,且两个mysql数据库来自不同的数据源;

一、配置信息
(一)依赖配置
文件:pom.xml

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

(二)数据源信息配置
文件:application.properties

单数据源的时候配置的是:spring.datasource.primary.url
多数据源的时候配置的是:spring.datasource.primary.jdbc-url

spring.datasource.primary.jdbc-url=jdbc:mysql://xx.xx.xx.xx:3306/database_name?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&sessionVariables=group_concat_max_len=999999&useSSL=false
spring.datasource.primary.username=username
spring.datasource.primary.password=password
spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.secondary.jdbc-url=jdbc:mysql://xx.xx.xx.xx:3306/database_name?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&sessionVariables=group_concat_max_len=999999&useSSL=false
spring.datasource.secondary.username=username
spring.datasource.secondary.password=password
spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver

(三)数据源配置

1、因为有的类在多个包中都有,所以特地将import的信息都展示出来了;
2、配置文件的位置:单独在应用同目录下建一个文件夹放就可以;
3、如下DataSourceConfig是个标准的配置类,都不需要改的,PrimaryConfig,SecondaryConfig需要改下指定下数据源指定的repository,entity 位置就可以了;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {
    @Bean(name = "primaryDataSource")
    @Qualifier("primaryDataSource")
    @ConfigurationProperties(prefix="spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

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

主数据源配置

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactoryPrimary",
        transactionManagerRef="transactionManagerPrimary",
        basePackages= { "com.example.xxx.xxx.repository" }) //设置查询语句所在的位置
public class PrimaryConfig {
    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;
    @Primary
    @Bean(name = "entityManagerPrimary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
    }
    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource)
                .properties(jpaProperties.getProperties())
                .properties(getVendorProperties())
                .packages("com.example.xxx.xxx.entity") //设置实体类所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }
    @Autowired
    private JpaProperties jpaProperties;

    @Autowired
    private HibernateProperties hibernateProperties;

    private Map getVendorProperties() {
        //return jpaProperties.getHibernateProperties(dataSource); 网上很多地方都是这样子写的,其实已经不好使了...
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }
    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }
}

辅数据源配置(基本和主数据源配置一样,主要是改下名称)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactorySecondary",
        transactionManagerRef="transactionManagerSecondary",
        basePackages= { "com.example.xxx.xxx.repository" }) //设置查询语句所在的位置
public class SecondaryConfig {
    @Autowired @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Bean(name = "entityManagerSecondary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactorySecondary(builder).getObject().createEntityManager();
    }
    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource)
                .properties(jpaProperties.getProperties())
                .properties(getVendorProperties())
                .packages("com.example.xxx.xxx.entity") //设置实体类所在位置
                .persistenceUnit("secondaryPersistenceUnit")
                .build();
    }
    @Autowired
    private JpaProperties jpaProperties;

    @Autowired
    private HibernateProperties hibernateProperties;

    private Map getVendorProperties() {
        //return jpaProperties.getHibernateProperties(dataSource); 
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }
    @Bean(name = "transactionManagerSecondary")
    PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
    }
}




以上完成配置信息,以下开始数据库查询操作:

二、查询操作

1、entity repository 就跟普通的一样就行;
2、动态sql 需要对entitymanager指明一下数据源;

reposity

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface ColumnRepo extends JpaRepository<ColumnInfo,Long>, JpaSpecificationExecutor<ColumnInfo> {

    /**
     * create by: admin
     * description: 获取表的所有字段
     * create time: 2021/5/26 下午5:35
     */
    @Query(value = "select COLUMN_NAME from information_schema.COLUMNS where table_name = :tablename and table_schema = :tableschema order by case when INSTR(column_name,'space') > 0 then REPLACE(column_name,'space','project') else column_name end ", nativeQuery = true)
    public List<ColumnInfo> getColumnsByTableName(@Param("tablename") String tablename, @Param("tableschema") String tableschema);
}

动态sql

import static com.example.xxx.xxx.common.GlobalVariableDefine.batch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.math.BigInteger;
import java.util.List;

@Slf4j
@Component
public class TableDataQuery {
    /*PersistenceContext 指明该处查询使用的数据源,该名称在PrimaryConfig 中存在定义*/
   @PersistenceContext(unitName="entityManagerFactoryPrimary")
    EntityManager entityManager;

    /**
     * create by: admin
     * description: 分批次有序获取数据内容
     * create time: 2021/5/26 下午6:04
     */
    public List<String> getTableData(String tablename, String tableschema, String colstr, String condition, int i){

        String querySQL = String.format("select convert(concat_ws(';', %s) using utf8) from %s.%s %s order by %s limit %d,%d",colstr,tableschema,tablename,condition,colstr,i*batch,batch);
        List<String> list = entityManager.createNativeQuery(querySQL).getResultList();
        return list;
    }
}

当前的解决方案不是很完美,觉得还是麻烦了一点点,相对于配置,我的实际操作内容反而不是很多,不划算,也不高级,后续有空尝试一下动态数据源写法 _

完结,撒花~~~

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个用于构建独立的、可执行的Spring应用程序的框架,简化了Spring应用程序的配置和部署。JPAJava Persistence API)是一种用于管理Java对象和关系数据库之间映射的规范。Druid是阿里巴巴开源的关系型数据库连接池。 在Spring Boot中配置多数据源需要以下几步: 1. 引入相关依赖:需要引入Spring Boot、Spring Data JPA和Druid的相关依赖。 2. 配置数据源:在application.properties或application.yml文件中配置多个数据源的连接信息,并指定每个数据源的名称和相关属性。 3. 配置数据源连接池:使用@ConfigurationProperties注解创建多个数据源的连接池对象,并指定数据源的名称以及相关属性。 4. 配置实体管理器工厂:为每个数据源配置对应的实体管理器工厂,用于处理JPA实体与数据库之间的映射关系。 5. 配置事务管理器:为每个数据源配置对应的事务管理器,用于处理事务操作。 6. 配置数据源路由:创建动态数据源,根据传入的数据源名称选择对应的数据源进行操作。 7. 配置JPA的Repository:创建接口继承JpaRepository,用于定义数据访问方法。 通过以上步骤配置好多数据源后,就可以在Spring Boot应用程序中使用多个数据源进行数据库的操作。可以根据需要在Service或Controller中使用@PersistenceContext注解指定具体的数据源,或者使用@Primary注解指定默认的数据源。 总结:通过Spring Boot的自动配置和Druid的连接池,可以很方便地实现多数据源的配置。使用JPA进行数据操作,能够有效地减少开发人员编写SQL语句的工作量,提高开发效率。通过合理的配置,可以根据需要选择不同的数据源进行操作,实现灵活的数据访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值