10020---SpringBoot2.0 jpa多数据源配置

https://blog.csdn.net/tianyaleixiaowu/article/details/78905149

随着Springboot升级到2.0,原来1.5.x的Jpa多数据源配置不能用了。现在总结一下Springboot2.0的jpa多数据源配置

连接池还是用druid,但是不能用druid的starter了,譬如在1.5.x时用的是

[html] view plain copy
  1. <dependency>  
  2.             <groupId>com.alibaba</groupId>  
  3.             <artifactId>druid-spring-boot-starter</artifactId>  
  4.             <version>1.1.6</version>  
  5.         </dependency>  
升级到2.0后,再用这个就会报错,因为一个AutoConfig的类缺失。那么要使用druid需要用下面的配置

[html] view plain copy
  1. <dependency>  
  2.             <groupId>com.alibaba</groupId>  
  3.             <artifactId>druid</artifactId>  
  4.             <version>1.1.6</version>  
  5.         </dependency>  
  6.         <dependency>  
  7.             <groupId>log4j</groupId>  
  8.             <artifactId>log4j</artifactId>  
  9.             <version>1.2.17</version>  
  10.         </dependency>  
  11.         <dependency>  
  12.             <groupId>org.springframework.boot</groupId>  
  13.             <artifactId>spring-boot-starter-web</artifactId>  
  14.         </dependency>  
注意log4j是druid强依赖的不能少,web是因为druid有web界面可以访问,也不能少。


application.yml也有变化

原来是这样的

[html] view plain copy
  1. spring:  
  2.   jpa:  
  3.     database: mysql  
  4.     show-sql: true  
  5.     hibernate:  
  6.       ddl-auto: update  
  7.       naming:  
  8.         strategy: org.hibernate.cfg.ImprovedNamingStrategy #命名策略,加分隔线"_"  
主要变化就是naming这里,原来的ImprovedNamingStrategy不让用了,改成了下面的类
[html] view plain copy
  1. spring:  
  2.   datasource:  
  3.     primary:  
  4.       url: jdbc:mysql://localhost:3306/company?autoReconnect=true&useUnicode=true  
  5.       username: root  
  6.       password: root  
  7.     secondary:  
  8.       url: jdbc:mysql://localhost:3306/com1?autoReconnect=true&useUnicode=true  
  9.       username: root  
  10.       password: root  
  11.   jpa:  
  12.     database: mysql  
  13.     generate-ddl: true  
  14.     show-sql: true  
  15.     hibernate:  
  16.       ddl-auto: update  
  17.       naming:  
  18.         physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy  


双数据源:

先来配置druid的DataSource,这个类在新老版本里都能用,不需要变化。

[java] view plain copy
  1. package com.example.demo.druid;  
  2.   
  3. import com.alibaba.druid.pool.DruidDataSource;  
  4. import org.slf4j.Logger;  
  5. import org.slf4j.LoggerFactory;  
  6. import org.springframework.beans.factory.annotation.Qualifier;  
  7. import org.springframework.beans.factory.annotation.Value;  
  8. import org.springframework.boot.web.servlet.ServletComponentScan;  
  9. import org.springframework.context.annotation.Bean;  
  10. import org.springframework.context.annotation.Configuration;  
  11. import org.springframework.context.annotation.Primary;  
  12.   
  13. import javax.sql.DataSource;  
  14. import java.sql.SQLException;  
  15.   
  16. /** 
  17.  * @author wuweifeng wrote on 2017/10/23. 
  18.  * 数据库连接属性配置 
  19.  */  
  20. @ServletComponentScan  
  21. @Configuration  
  22. public class DruidDBConfig {  
  23.     private Logger logger = LoggerFactory.getLogger(DruidDBConfig.class);  
  24.   
  25.     @Value("${spring.datasource.primary.url}")  
  26.     private String dbUrl1;  
  27.   
  28.     @Value("${spring.datasource.primary.username}")  
  29.     private String username1;  
  30.   
  31.     @Value("${spring.datasource.primary.password}")  
  32.     private String password1;  
  33.   
  34.     @Value("${spring.datasource.secondary.username}")  
  35.     private String username2;  
  36.   
  37.     @Value("${spring.datasource.secondary.password}")  
  38.     private String password2;  
  39.   
  40.     @Value("${spring.datasource.secondary.url}")  
  41.     private String dbUrl2;  
  42.   
  43.     @Value("com.mysql.jdbc.Driver")  
  44.     private String driverClassName;  
  45.   
  46.     @Value("5")  
  47.     private int initialSize;  
  48.   
  49.     @Value("5")  
  50.     private int minIdle;  
  51.   
  52.     @Value("20")  
  53.     private int maxActive;  
  54.   
  55.     @Value("60000")  
  56.     private int maxWait;  
  57.   
  58.     /** 
  59.      * 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 
  60.      */  
  61.     @Value("60000")  
  62.     private int timeBetweenEvictionRunsMillis;  
  63.     /** 
  64.      * 配置一个连接在池中最小生存的时间,单位是毫秒 
  65.      */  
  66.     @Value("300000")  
  67.     private int minEvictableIdleTimeMillis;  
  68.   
  69.     @Value("SELECT 1 FROM DUAL")  
  70.     private String validationQuery;  
  71.   
  72.     @Value("true")  
  73.     private boolean testWhileIdle;  
  74.   
  75.     @Value("false")  
  76.     private boolean testOnBorrow;  
  77.   
  78.     @Value("false")  
  79.     private boolean testOnReturn;  
  80.   
  81.     /** 
  82.      * 打开PSCache,并且指定每个连接上PSCache的大小 
  83.      */  
  84.     @Value("true")  
  85.     private boolean poolPreparedStatements;  
  86.   
  87.     @Value("20")  
  88.     private int maxPoolPreparedStatementPerConnectionSize;  
  89.     /** 
  90.      * 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 
  91.      */  
  92.     @Value("stat,wall,log4j")  
  93.     private String filters;  
  94.     /** 
  95.      * 通过connectProperties属性来打开mergeSql功能;慢SQL记录 
  96.      */  
  97.     @Value("druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500")  
  98.     private String connectionProperties;  
  99.   
  100.     @Bean(name = "primaryDataSource")  
  101.     @Qualifier("primaryDataSource")  
  102.     public DataSource dataSource() {  
  103.         return getDruidDataSource(username1, password1, dbUrl1);  
  104.     }  
  105.   
  106.     @Bean(name = "secondaryDataSource")  
  107.     @Qualifier("secondaryDataSource")  
  108.     @Primary  
  109.     public DataSource secondaryDataSource() {  
  110.         return getDruidDataSource(username2, password2, dbUrl2);  
  111.     }  
  112.   
  113.     private DruidDataSource getDruidDataSource(String username, String password, String url) {  
  114.         DruidDataSource datasource = new DruidDataSource();  
  115.   
  116.         datasource.setUrl(url);  
  117.         datasource.setUsername(username);  
  118.         datasource.setPassword(password);  
  119.         datasource.setDriverClassName(driverClassName);  
  120.   
  121.         //configuration  
  122.         datasource.setInitialSize(initialSize);  
  123.         datasource.setMinIdle(minIdle);  
  124.         datasource.setMaxActive(maxActive);  
  125.         datasource.setMaxWait(maxWait);  
  126.         datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);  
  127.         datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);  
  128.         datasource.setValidationQuery(validationQuery);  
  129.         datasource.setTestWhileIdle(testWhileIdle);  
  130.         datasource.setTestOnBorrow(testOnBorrow);  
  131.         datasource.setTestOnReturn(testOnReturn);  
  132.         datasource.setPoolPreparedStatements(poolPreparedStatements);  
  133.         datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);  
  134.         try {  
  135.             datasource.setFilters(filters);  
  136.         } catch (SQLException e) {  
  137.             logger.error("druid configuration initialization filter : {0}", e);  
  138.         }  
  139.         datasource.setConnectionProperties(connectionProperties);  
  140.   
  141.         return datasource;  
  142.     }  
  143. }  

第一数据源:

[java] view plain copy
  1. package com.example.demo.druid;  
  2.   
  3. import org.springframework.beans.factory.annotation.Qualifier;  
  4. import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;  
  5. import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;  
  6. import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;  
  7. import org.springframework.context.annotation.Bean;  
  8. import org.springframework.context.annotation.Configuration;  
  9. import org.springframework.context.annotation.Primary;  
  10. import org.springframework.data.jpa.repository.config.EnableJpaRepositories;  
  11. import org.springframework.orm.jpa.JpaTransactionManager;  
  12. import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;  
  13. import org.springframework.transaction.PlatformTransactionManager;  
  14. import org.springframework.transaction.annotation.EnableTransactionManagement;  
  15.   
  16. import javax.annotation.Resource;  
  17. import javax.persistence.EntityManager;  
  18. import javax.sql.DataSource;  
  19. import java.util.Map;  
  20.   
  21. /** 
  22.  * @author wuweifeng wrote on 2017/10/31. 
  23.  */  
  24. @Configuration  
  25. @EnableTransactionManagement  
  26. @EnableJpaRepositories(  
  27.         entityManagerFactoryRef = "entityManagerFactoryPrimary",  
  28.         transactionManagerRef = "transactionManagerPrimary",  
  29.         basePackages = {"com.example.demo.repository.primary"})  
  30. public class PrimaryConfig {  
  31.   
  32.     @Resource  
  33.     @Qualifier("primaryDataSource")  
  34.     private DataSource primaryDataSource;  
  35.   
  36.     @Primary  
  37.     @Bean(name = "entityManagerPrimary")  
  38.     public EntityManager entityManager(EntityManagerFactoryBuilder builder) {  
  39.         return entityManagerFactoryPrimary(builder).getObject().createEntityManager();  
  40.     }  
  41.   
  42.     @Resource  
  43.     private JpaProperties jpaProperties;  
  44.   
  45.     private Map<String, Object> getVendorProperties() {  
  46.         return jpaProperties.getHibernateProperties(new HibernateSettings());  
  47.     }  
  48.   
  49.     /** 
  50.      * 设置实体类所在位置 
  51.      */  
  52.     @Primary  
  53.     @Bean(name = "entityManagerFactoryPrimary")  
  54.     public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {  
  55.         return builder  
  56.                 .dataSource(primaryDataSource)  
  57.                 .packages("com.example.demo.model.primary")  
  58.                 .persistenceUnit("primaryPersistenceUnit")  
  59.                 .properties(getVendorProperties())  
  60.                 .build();  
  61.     }  
  62.   
  63.     @Primary  
  64.     @Bean(name = "transactionManagerPrimary")  
  65.     public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {  
  66.         return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());  
  67.     }  
  68.   
  69. }  
第二数据源:

[java] view plain copy
  1. package com.example.demo.druid;  
  2.   
  3. import org.springframework.beans.factory.annotation.Qualifier;  
  4. import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;  
  5. import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;  
  6. import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;  
  7. import org.springframework.context.annotation.Bean;  
  8. import org.springframework.context.annotation.Configuration;  
  9. import org.springframework.data.jpa.repository.config.EnableJpaRepositories;  
  10. import org.springframework.orm.jpa.JpaTransactionManager;  
  11. import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;  
  12. import org.springframework.transaction.PlatformTransactionManager;  
  13. import org.springframework.transaction.annotation.EnableTransactionManagement;  
  14.   
  15. import javax.annotation.Resource;  
  16. import javax.persistence.EntityManager;  
  17. import javax.sql.DataSource;  
  18. import java.util.Map;  
  19.   
  20. /** 
  21.  * @author by wuweifeng on 2017/10/10. 
  22.  */  
  23. @Configuration  
  24. @EnableTransactionManagement  
  25. @EnableJpaRepositories(  
  26.         entityManagerFactoryRef = "entityManagerFactorySecondary",  
  27.         transactionManagerRef = "transactionManagerSecondary",  
  28.         basePackages = {"com.example.demo.repository.secondary"})  
  29. public class SecondaryConfig {  
  30.   
  31.     @Resource  
  32.     @Qualifier("secondaryDataSource")  
  33.     private DataSource secondaryDataSource;  
  34.   
  35.     @Bean(name = "entityManagerSecondary")  
  36.     public EntityManager entityManager(EntityManagerFactoryBuilder builder) {  
  37.         return entityManagerFactorySecondary(builder).getObject().createEntityManager();  
  38.     }  
  39.   
  40.     @Resource  
  41.     private JpaProperties jpaProperties;  
  42.   
  43.     private Map<String, Object> getVendorProperties() {  
  44.         return jpaProperties.getHibernateProperties(new HibernateSettings());  
  45.     }  
  46.   
  47.     @Bean(name = "entityManagerFactorySecondary")  
  48.     public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {  
  49.         return builder  
  50.                 .dataSource(secondaryDataSource)  
  51.                 .packages("com.example.demo.model.secondary")  
  52.                 .persistenceUnit("secondaryPersistenceUnit")  
  53.                 .properties(getVendorProperties())  
  54.                 .build();  
  55.     }  
  56.   
  57.     @Bean(name = "transactionManagerSecondary")  
  58.     PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {  
  59.         return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());  
  60.     }  
  61.   
  62. }  

注意把里面的model包名和Repository包名替换为你自己的即可。

它与1.5.x版本的主要区别在于getVerdorProperties这个方法,原来的getHibernateProperties是传参数DataSource,现在是传参数HibernateSettings,
10020---SpringBoot2.0 jpa多数据源配置

HibernateSettings类其实就是配置列名生成策略的,我们已经在yml里配置过了,这里直接new 一个空类过去就行了。

这样我们就完成了Springboot 2.0.0.M7的多数据源Jpa配置了。

还有一个地方需要提一下,Springboot2.0依赖了Hibernate5.2版本,1.5.x依赖的是Hibernate5.0.12版本,这两个版本在处理Id自增方面是不一样的。

在老版本里,我们定义了

[java] view plain copy
  1. @Id  
  2.    @GeneratedValue(strategy = GenerationType.AUTO)  
  3.    @Column(name = "id")  
  4.    public Long getId() {  
  5.        return id;  
  6.    }  
Id生成策略为Auto,那么默认会被转出Id自增。

在新版本里,Auto是不行的,不会自增,而且Hibernate会额外创建出来一个表来专门维护Id。可以自行尝试一下,会多出来一个表。

我们如果需要自增的Id,需要显式指定

[java] view plain copy
  1. @Id  
  2.     @GeneratedValue(strategy = GenerationType.IDENTITY)  
  3.     @Column(name = "id")  
  4.     public Long getId() {  
  5.         return id;  
  6.     }