jpa多数据源时Hibernate配置自动生成表不生效的解决
作者:天涯泪小武
这篇文章主要介绍了jpa多数据源时Hibernate配置自动生成表不生效的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
jpa配置多数据源教程很多,在Springboot2之后有一些变化,来看一下。
application.yml如下
spring: application: name: t3cc datasource: primary: jdbc-url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${DB_NAME:anbang}?useUnicode=true&characterEncoding=UTF8&serverTimezone=Hongkong username: root password: root secondary: jdbc-url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${DB_NAME:anbang1}?useUnicode=true&characterEncoding=UTF8&serverTimezone=Hongkong username: root password: root jpa: database: mysql database-platform: org.hibernate.dialect.MySQL5InnoDBDialect #不加这句则默认为myisam引擎 hibernate: ddl-auto: update naming: physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy open-in-view: true properties: enable_lazy_load_no_trans: true show-sql: true cloud: nacos: discovery: server-addr: ${NACOS_SERVER:localhost:8848} ###############################---log---############################## logging: file: ./logback.log
yml里配置了两个数据源,和一些jpa和Hibernate的配置。
下面是DataSource的配置
/** * @author wuweifeng wrote on 2019/3/5. */ @Configuration public class DataSourceConfig { @Primary @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource dataSourceOrder() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource dataSourceAuth() { return DataSourceBuilder.create().build(); } }
下面是第一个数据源的配置
package com.mm.dmp.t3cc.config; 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.annotation.Resource; import javax.persistence.EntityManager; import javax.sql.DataSource; /** * @author wuweifeng wrote on 2019/3/5. */ @Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef = "entityManagerFactoryPrimary", transactionManagerRef = "transactionManagerPrimary", basePackages = {"com.mm.dmp.t3cc.core.repository.one"}) public class OneConfig { @Resource @Qualifier("primaryDataSource") private DataSource primaryDataSource; @Primary @Bean(name = "entityManagerPrimary") public EntityManager entityManager(EntityManagerFactoryBuilder builder) { return entityManagerFactoryPrimary(builder).getObject().createEntityManager(); } @Resource private JpaProperties jpaProperties; @Resource private HibernateProperties properties; /** * 设置实体类所在位置 */ @Primary @Bean(name = "entityManagerFactoryPrimary") public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) { LocalContainerEntityManagerFactoryBean entityManagerFactory = builder .dataSource(primaryDataSource) //.packages(classes) //设置实体类所在位置 .packages("com.mm.dmp.t3cc.core.entity.one") .persistenceUnit("primaryPersistenceUnit") //.properties(jpaProperties.getProperties()) .properties(properties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings())) .build(); return entityManagerFactory; } @Primary @Bean(name = "transactionManagerPrimary") public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject()); } }
这里会和别人的配置不一样,主要区别在于HibernateProperties。别人的在第61行,我注释掉的那行,会直接使用jpaProperties.getProperties()。当你这样写之后,会发现yml里配置的Hibernate的update自动生成表,和命名方式并没有生效。
原因我们可以看一下。
这里就是jpaProperties.getProperties()的地方,如果打断点可以看到,只有箭头这一个配置被加载进去了。上面的Hibernate的ddl和naming并没有进去。
来看一下HibernateProperties
这里才是真正让自动建表生效的地方,然而并没有加载进去。那么就需要我们手工来添加了。
这里面有个determineHibernateProperties方法,就是来组合jpaProperties和HibernateProperties的地方。我们应该使用这个方法来组合整个配置的map对象。
也就是在OneConfig类中,把两个Properties都定义出来,然后组合一下,就是箭头的地方。在debug时,就可以看到Hibernate的配置也都加载进来了。
OK,以上就是动态数据源配置Hibernate自动建表不生效的原因。
下面是第二个数据源的配置
package com.mm.dmp.t3cc.config; 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.annotation.Resource; import javax.persistence.EntityManager; import javax.sql.DataSource; /** * @author wuweifeng wrote on 2019/3/5. */ @Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef = "entityManagerFactorySecondary", transactionManagerRef = "transactionManagerSecondary", basePackages = {"com.mm.dmp.t3cc.core.repository.two"}) //设置Repository所在位置 public class TwoConfig { @Resource @Qualifier("secondaryDataSource") private DataSource secondaryDataSource; @Resource private JpaProperties jpaProperties; @Resource private HibernateProperties properties; @Bean(name = "entityManagerSecondary") public EntityManager entityManager(EntityManagerFactoryBuilder builder) { return entityManagerFactorySecondary(builder).getObject().createEntityManager(); } @Bean(name = "entityManagerFactorySecondary") public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) { LocalContainerEntityManagerFactoryBean entityManagerFactory = builder .dataSource(secondaryDataSource) //.packages(classes) //设置实体类所在位置 .packages("com.mm.dmp.t3cc.core.entity.two") .persistenceUnit("secondaryPersistenceUnit") .properties(properties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings())) .build(); return entityManagerFactory; } @Bean(name = "transactionManagerSecondary") public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject()); } }
如果你觉得这样比较麻烦,并且还有分库分表的需求,那么可以使用sharding jdbc来操作,移步这一篇文章
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。