配置多数据源

  • SpringBoot v2.0.5.RELEASE
  • SpringDataJPA 2.0.10RELEASE
  • Hibernate-Core:5.2.17
  • JPA参数详解
  • 问题
  • 1.Spring Data Jpa 自定义 Repository EntityManager is null
  • yml配置
  • JPA
  • 初始化数据源
  • master 和slave各自的JPA详细配置
  • @EnableJpaRepositories

SpringBoot v2.0.5.RELEASE

SpringDataJPA 2.0.10RELEASE

Hibernate-Core:5.2.17

JPA参数详解

问题

1.Spring Data Jpa 自定义 Repository EntityManager is null

这个问题是啊我在查询资料过程中搜到,本身我并未遇到,在此记录以下

新版本中去除了 @PersistenceContext 注解, 无法自动进行注入, 应该是新版本为了支持微服务, 表分库策略,
可以使用多个数据源, 多个EntityManager, 故移除自动注入, 改为手动注入:

@Autowired
 public CustomerRepositoryImpl(JpaContext context){
 super(Customer.class);
 setEntityManager(context.getEntityManagerByManagedType(Follow.class));
 }

yml配置

spring:
  datasource:
    # 第一个数据源
    primary:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbcUrl: jdbc:mysql://localhost:3306/primary?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2b8
      username: root
      password: 123456
    # 第二数据源
    secondary:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbcUrl: jdbc:mysql://localhost:3306/secondary?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2b8
      username: root
      password: 123456

JPA

初始化数据源

@Configuration
@Slf4j
public class DataSourceConfig {


    @Primary
    @Bean(name = "masterDataSourceProperties")
    @Qualifier(value = "masterDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSourceProperties masterDataSourceProperties(){
        return new DataSourceProperties();
    }

    @Primary
    @Bean(name = "masterDataSource")
    @Qualifier(value = "masterDataSource")
    public DataSource masterDataSource(){
        log.info("创建master数据源");
        return masterDataSourceProperties().initializeDataSourceBuilder().build();
    }

    @Bean(name = "salveDataSourceProperties")
    @Qualifier(value = "salveDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.salve")
    public DataSourceProperties salveDataSourceProperties(){
        return new DataSourceProperties();
    }

    @Bean(name = "salveDataSource")
    @Qualifier(value = "salveDataSource")
    public DataSource salveDataSource(){
        log.info("创建slave数据源");
        return salveDataSourceProperties().initializeDataSourceBuilder().build();
    }

}

master 和slave各自的JPA详细配置

@Configuration
@Component
@ComponentScan({"com.test.config"})
@EnableTransactionManagement
@EnableJpaRepositories(
        //默认关闭事务,启动类上的注释掉了,在这里补充上
        enableDefaultTransactions = false,
        entityManagerFactoryRef = "masterEntityManagerFactoryBean",  //配置实体管理器连接工厂
        transactionManagerRef = "masterTransactionManager", //配置事务管理器
        basePackages = {"com.test.repository"
        }, //repository位置
        //排除使用salve库的接口
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {
                        slaveTestRepository.class
                })
        }
        ) 
public class MasterDataSourceConfig {


    @Autowired
    @Qualifier(value = "masterDataSource")
    private DataSource masterDataSource;

    @Autowired
    private JpaProperties jpaProperties;


    //配置entityManager实体
    @Primary
    @Bean(name = "masterEntityManager")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return Objects.requireNonNull(entityManagerFactoryBeanMaster(builder).getObject()).createEntityManager();
    }

    @Primary
    @Bean(name = "masterEntityManagerFactoryBean")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBeanMaster(EntityManagerFactoryBuilder builder) {
        return builder.dataSource(masterDataSource)  //设置数据源
                .properties(getVendorProperties())  // hibernate配置
                .properties(jpaProperties.getProperties())//jpa配置
                .persistenceUnit("masterPersistenceUnit")   //设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源
                .packages("com.test.entity",
                )   //设置实体类所在位置
                .build();

    }

    @Primary
    @Bean(name = "masterTransactionManager")
    public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(Objects.requireNonNull(entityManagerFactoryBeanMaster(builder).getObject()));
    }

    //jpa配置信息
    public Map<String, String> getProperties() {
        HashMap<String, String> map = Maps.newHashMap();
        map.put("show-sql", "true");
        map.put("hibernate.ddl-auto", "none");
        map.put("hibernate.naming-strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
        map.put("hibernate.dialect", "org.hibernate.dialect.MySQL55Dialect");
        return map;
    }


    private Map<String,Object> getVendorProperties() {
        //return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
        return jpaProperties.getHibernateProperties(new HibernateSettings());
    }

/**getVendorProperties() 函数的调试信息
 *  {hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy,
 *  hibernate.format_sql=true,
 *  hibernate.hbm2ddl.auto=update,
 *  hibernate.id.new_generator_mappings=true,
 *  hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy,
 *  hibernate.dialect=org.hibernate.dialect.MySQL55Dialect}
 */

}

主数据源设置如此,从数据源相同

  1. 配置实体管理器连接工厂时指定了持久化单元名,用于
  2. @PersistenceContext注解获取EntityManager时指定数据源
  3. 在我使用过程中,当类中注入了EntityManager entityManager自定义查询方法时,必须用@PersistenceContext来注入,不能用@Autowired;
    如果@PersistenceContext()未指定参数,那么这个实体管理器默认使用master数据源,指定后才会使用指定的实体管理器;
  4. 如果直接使用SpringDataJPA已经封装好的查询方法,比如findbyId()这是候会根据配置JPA配置类的扫描包配置信息使用指定数据源
  5. 启动类上不要再使用@EnableJpaRepositories,在数据源JPA配置类上使用此注解
    必须使用@Primary指定主数据源

@EnableJpaRepositories

1 @EnableJpaRepositories(
 2     basePackages = {},
 3     basePackageClasses = {},
 4     includeFilters = {},
 5     excludeFilters = {},
 6     repositoryImplementationPostfix = "Impl",
 7     namedQueriesLocation = "",//META-INF/jpa-named-queries.properties
 8     queryLookupStrategy=QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND, //QueryLookupStrategy.Key.x
 9     repositoryFactoryBeanClass=JpaRepositoryFactoryBean.class, //class
10     entityManagerFactoryRef="entityManagerFactory",
11     transactionManagerRef="transactionManager",
12     considerNestedRepositories=false, 
13     enableDefaultTransactions=true
14 )

属性

缺省值

描述

value

basePackages的别名,简化basePackages

basePackages

用于配置扫描Repositories所在的包。填写字符串(或字符串数组)形式的包名.

basePackageClasses

basePackages的安全替代选选项。指定一个要扫描包中的一个类或接口,将扫描所在包中的所有repository,可以考虑在每个要扫描的包中创建一个类或接口,它除了被这个属性引用外,没有其他用途。

includeFilters

指定哪些类型的组件被扫描。过滤器,该过滤区采用ComponentScan的过滤器类

excludeFilters

指定哪些类型的组件不被扫描。

repositoryImplementationPostfix

impl

查找自定义存储库实现时要使用的后缀。默认为Impl。对于名为PersonRepository的存储库,将通过扫描PersonRepositoryImpl来查找相应的实现类。

namedQueriesLocation

META-INF/jpa-named-queries.properties

配置Spring-Data的named queries 属性文件的位置,默认META-INF/jpa-named-queries.properties。

queryLookupStrategy

QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND

查询方法的查询策略。构建条件查询的策略,包含三种方式CREATE USE_DECLARED_QUERY,CREATE_IF_NOT_FOUND CREATE:按照接口名称自动构建查询 USE_DECLARED_QUERY:用户声明查询CREATE_IF_NOT_FOUND:先搜索用户声明的,不存在则自动构建

repositoryFactoryBeanClass

JpaRepositoryFactoryBean

用于每个存储库实例的FactoryBean类。默认为JpaRepositoryFactoryBean。

repositoryBaseClass

配置存储库基类,以用于为该特定配置创建存储库代理。

entityManagerFactoryRef

entityManagerFactory

配置EntityManagerFactory bean定义的名称。默认为entityManagerFactory。

transactionManagerRef

transactionManager

配置PlatformTransactionManager bean定义的名称。默认为transactionManager。

considerNestedRepositories

false

配置是否发现嵌套的Repository接口(如定义为内部类)。默认为false

enableDefaultTransactions

true

配置Spring-Data-Jpa 的Repositories是否启用默认事务,默认为true。如果禁用,则必须在外层使用。

bootstrapMode

BootstrapMode.DEFAULT

配置在引导生命周期中何时初始化Repository。默认为BootstrapMode.DEFAULT,除了添加了BootstrapMode.LAZY的接口外,其他接口立即初始化。1. BootstrapMode.LAZY,Repository的bean定义被认为是懒加载注入,并且只在首次使用时初始化,即应用程序可能在没有初始化Repository的情况下完全启动 2. BootstrapMode.DEFERRED,Repository的bean定义被认为是懒加载注入,但存储库初始化在应用程序上下文引导完成时触发。

escapeCharacter

配置在包含contains、startsWith或endsWith子句的派生查询中用于转义 _ 或 % 的通配符字符。

参考资料:

SpringBoot 多数据源的动态切换,你学会了吗?SpringBoot多数据源配置详细教程