diff --git a/jpa-multi-data-source/.gitignore b/jpa-multi-data-source/.gitignore new file mode 100644 index 0000000..efb4aab --- /dev/null +++ b/jpa-multi-data-source/.gitignore @@ -0,0 +1,46 @@ +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen diff --git a/jpa-multi-data-source/pom.xml b/jpa-multi-data-source/pom.xml new file mode 100644 index 0000000..8c27236 --- /dev/null +++ b/jpa-multi-data-source/pom.xml @@ -0,0 +1,57 @@ + + + + sharding-demo + com.baiye + 1.0-SNAPSHOT + + 4.0.0 + + jpa-multi-data-source + + + 8 + 8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + mysql + mysql-connector-java + + + + org.projectlombok + lombok + + + + junit + junit + + + + org.springframework.boot + spring-boot-starter-test + + + + com.alibaba + druid + + + + \ No newline at end of file diff --git a/jpa-multi-data-source/src/main/java/com/baiye/JpaMultiDataSourceApplication.java b/jpa-multi-data-source/src/main/java/com/baiye/JpaMultiDataSourceApplication.java new file mode 100644 index 0000000..ec9f2a1 --- /dev/null +++ b/jpa-multi-data-source/src/main/java/com/baiye/JpaMultiDataSourceApplication.java @@ -0,0 +1,29 @@ +package com.baiye; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; + +@SpringBootApplication +public class JpaMultiDataSourceApplication { + public static void main(String[] args) { + SpringApplication.run(JpaMultiDataSourceApplication.class, args); + } + + /** + * 按照日志要求将 open-in-view=false。再次启动,如果在实体类中外键字段使用了懒加载模式,在视图层中调用数据时,则会出现 no session 异常。 + * + * 解决方法:手动注册OpenEntityManagerInViewFilter过滤器,改变session的生命周期,当web请求关闭时才结束session。 + */ + @Bean + public FilterRegistrationBean openEntityManagerInViewFilterFilterRegistrationBean(){ + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); + OpenEntityManagerInViewFilter filter = new OpenEntityManagerInViewFilter(); + filterRegistrationBean.setFilter(filter); + filterRegistrationBean.setOrder(5); + return filterRegistrationBean; + } +} diff --git a/jpa-multi-data-source/src/main/java/com/baiye/conf/DataSourceConfiguration.java b/jpa-multi-data-source/src/main/java/com/baiye/conf/DataSourceConfiguration.java new file mode 100644 index 0000000..7bf09d5 --- /dev/null +++ b/jpa-multi-data-source/src/main/java/com/baiye/conf/DataSourceConfiguration.java @@ -0,0 +1,36 @@ +package com.baiye.conf; + +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 DataSourceConfiguration { + + /** + * 第一个数据连接,默认优先级最高 + * @return + */ + @Bean(name = "dataSourceFirst") + @Primary + @ConfigurationProperties(prefix = "spring.datasource.first") + public DataSource dataSourceFirst() { + //这种方式的配置默认只满足spring的配置方式,如果使用其他数据连接(druid),需要自己独立获取配置 + return DataSourceBuilder.create().build(); + } + + /** + * 第二个数据源 + * @return + */ + @Bean(name = "dataSourceSecond") + @ConfigurationProperties(prefix = "spring.datasource.second") + public DataSource dataSourceSecond() { + return DataSourceBuilder.create().build(); + } +} diff --git a/jpa-multi-data-source/src/main/java/com/baiye/conf/JpaFirstConfiguration.java b/jpa-multi-data-source/src/main/java/com/baiye/conf/JpaFirstConfiguration.java new file mode 100644 index 0000000..11f2538 --- /dev/null +++ b/jpa-multi-data-source/src/main/java/com/baiye/conf/JpaFirstConfiguration.java @@ -0,0 +1,108 @@ +package com.baiye.conf; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.domain.EntityScan; +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.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManager; +import javax.sql.DataSource; +import java.util.Map; +import java.util.Objects; + +/** + * 第一个数据源,jpa的相关配置 + * + * 1、实体扫描 + * 2、实体管理ref + * 3、事务管理 + */ +@Configuration +@EntityScan(basePackages = "com.baiye.domain.first") + +@EnableJpaRepositories( + basePackages = "com.baiye.domain.first", + entityManagerFactoryRef = "firstEntityManagerFactoryBean", + transactionManagerRef = "firstTransactionManager") +@EnableTransactionManagement +public class JpaFirstConfiguration { + + @Autowired + private HibernateProperties hibernateProperties; + /** + * 第一个数据源,可以不加Qualifier + */ + @Autowired + @Qualifier("dataSourceFirst") + private DataSource dataSource; + + /** + * jpa其他参数配置 + */ + @Autowired + private JpaProperties jpaProperties; + + /** + * 实体管理工厂builder + */ + @Autowired + private EntityManagerFactoryBuilder factoryBuilder; + + /** + * 配置第一个实体管理工厂的bean + * + * @return + */ + @Bean(name = "firstEntityManagerFactoryBean") + @Primary + public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { + Map properties = hibernateProperties + .determineHibernateProperties( + jpaProperties.getProperties(), + new HibernateSettings() + ); + + return factoryBuilder.dataSource(dataSource) + //这一行的目的是加入jpa的其他配置参数比如(ddl-auto: update等) + //当然这个参数配置可以在事务配置的时候也可以 + .properties(properties) + .packages("com.baiye.domain.first") + .persistenceUnit("firstPersistenceUnit") + .build(); + } + + /** + * EntityManager不过解释,用过jpa的应该都了解 + * @return + */ + @Bean(name = "firstEntityManager") + @Primary + public EntityManager entityManager() { + return Objects.requireNonNull(entityManagerFactoryBean().getObject()).createEntityManager(); + } + + /** + * jpa事务管理 + * @return + */ + @Bean(name = "firstTransactionManager") + @Primary + public JpaTransactionManager transactionManager() { + JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); + jpaTransactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); + return jpaTransactionManager; + } + + +} diff --git a/jpa-multi-data-source/src/main/java/com/baiye/conf/JpaSecondConfiguration.java b/jpa-multi-data-source/src/main/java/com/baiye/conf/JpaSecondConfiguration.java new file mode 100644 index 0000000..4efdf0e --- /dev/null +++ b/jpa-multi-data-source/src/main/java/com/baiye/conf/JpaSecondConfiguration.java @@ -0,0 +1,100 @@ +package com.baiye.conf; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.domain.EntityScan; +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.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManager; +import javax.sql.DataSource; +import java.util.Map; +import java.util.Objects; + + +/** + * 第二个数据源,jpa的相关配置 + * + * 1、实体扫描 + * 2、实体管理ref + * 3、事务管理 + */ +@Configuration +@EntityScan(basePackages = "com.baiye.domain.second") +@EnableJpaRepositories( + basePackages = "com.baiye.domain.second", + entityManagerFactoryRef = "secondEntityManagerFactoryBean", + transactionManagerRef = "secondTransactionManager") +@EnableTransactionManagement +public class JpaSecondConfiguration { + @Autowired + private HibernateProperties hibernateProperties; + + /** + * 第二个数据源,必须加Qualifier + */ + @Autowired + @Qualifier("dataSourceSecond") + private DataSource dataSource; + + /** + * jpa其他参数配置 + */ + @Autowired + private JpaProperties jpaProperties; + + /** + * 实体管理工厂builder + */ + @Autowired + private EntityManagerFactoryBuilder factoryBuilder; + + /** + * 配置第二个实体管理工厂的bean + * + * @return + */ + @Bean(name = "secondEntityManagerFactoryBean") + public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { + Map properties = hibernateProperties.determineHibernateProperties( + jpaProperties.getProperties(), + new HibernateSettings() + ); + + return factoryBuilder.dataSource(dataSource) + .properties(properties) + .packages("com.baiye.domain.second") + .persistenceUnit("secondPersistenceUnit") + .build(); + } + + /** + * EntityManager不过解释,用过jpa的应该都了解 + * + * @return + */ + @Bean(name = "secondEntityManager") + public EntityManager entityManager() { + return Objects.requireNonNull(entityManagerFactoryBean().getObject()).createEntityManager(); + } + + /** + * jpa事务管理 + * + * @return + */ + @Bean(name = "secondTransactionManager") + public JpaTransactionManager transactionManager() { + JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); + jpaTransactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); + return jpaTransactionManager; + } +} diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/dao/PriceRepository.java b/jpa-multi-data-source/src/main/java/com/baiye/dao/PriceRepository.java similarity index 81% rename from sharding-multiple-data-sources/src/main/java/com/baiye/dao/PriceRepository.java rename to jpa-multi-data-source/src/main/java/com/baiye/dao/PriceRepository.java index 37cab7d..b815816 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/dao/PriceRepository.java +++ b/jpa-multi-data-source/src/main/java/com/baiye/dao/PriceRepository.java @@ -1,6 +1,6 @@ package com.baiye.dao; -import com.baiye.domain.Price; +import com.baiye.domain.first.Price; import org.springframework.data.jpa.repository.JpaRepository; public interface PriceRepository extends JpaRepository { diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/dao/UserRepository.java b/jpa-multi-data-source/src/main/java/com/baiye/dao/UserRepository.java similarity index 87% rename from sharding-multiple-data-sources/src/main/java/com/baiye/dao/UserRepository.java rename to jpa-multi-data-source/src/main/java/com/baiye/dao/UserRepository.java index 58a441b..239b624 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/dao/UserRepository.java +++ b/jpa-multi-data-source/src/main/java/com/baiye/dao/UserRepository.java @@ -1,6 +1,6 @@ package com.baiye.dao; -import com.baiye.domain.User; +import com.baiye.domain.second.User; import org.springframework.data.jpa.repository.JpaRepository; /** diff --git a/jpa-multi-data-source/src/main/java/com/baiye/domain/first/Price.java b/jpa-multi-data-source/src/main/java/com/baiye/domain/first/Price.java new file mode 100644 index 0000000..0128131 --- /dev/null +++ b/jpa-multi-data-source/src/main/java/com/baiye/domain/first/Price.java @@ -0,0 +1,22 @@ +package com.baiye.domain.first; + +import lombok.Data; + +import javax.persistence.*; +import java.math.BigDecimal; + +@Entity +@Data +@Table(name = "price") +public class Price { + + @Id + @GeneratedValue(strategy= GenerationType.AUTO) + private Integer id; + + @Column(name = "user_id") + private Integer userId; + + @Column(name = "cost") + private BigDecimal cost; +} diff --git a/jpa-multi-data-source/src/main/java/com/baiye/domain/second/User.java b/jpa-multi-data-source/src/main/java/com/baiye/domain/second/User.java new file mode 100644 index 0000000..629ad4a --- /dev/null +++ b/jpa-multi-data-source/src/main/java/com/baiye/domain/second/User.java @@ -0,0 +1,20 @@ +package com.baiye.domain.second; + + +import lombok.Data; + +import javax.persistence.*; + +@Entity +@Data +@Table(name = "user") +public class User { + + @Id + @GeneratedValue(strategy= GenerationType.AUTO) + private Integer id; + + private String name; + + private String city; +} diff --git a/jpa-multi-data-source/src/main/resources/application.yml b/jpa-multi-data-source/src/main/resources/application.yml new file mode 100644 index 0000000..6b771fe --- /dev/null +++ b/jpa-multi-data-source/src/main/resources/application.yml @@ -0,0 +1,23 @@ +server: + port: 8082 +spring: + datasource: + first: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/master-1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useTimezone=true + username: root + password: root + second: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/slave-1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useTimezone=true + username: root + password: root + jpa: + hibernate: + ddl-auto: update + naming: + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + show-sql: true + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + database: mysql \ No newline at end of file diff --git a/pom.xml b/pom.xml index cce0a01..d8806c2 100644 --- a/pom.xml +++ b/pom.xml @@ -9,6 +9,7 @@ 1.0-SNAPSHOT sharding-multiple-data-sources + jpa-multi-data-source diff --git a/sharding-multiple-data-sources/pom.xml b/sharding-multiple-data-sources/pom.xml index 0a9eddb..fe5eaba 100644 --- a/sharding-multiple-data-sources/pom.xml +++ b/sharding-multiple-data-sources/pom.xml @@ -49,10 +49,10 @@ mysql-connector-java - + org.projectlombok diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/ShardingMultipleDataSourceApplication.java b/sharding-multiple-data-sources/src/main/java/com/baiye/ShardingMultipleDataSourceApplication.java index 6a71ca4..0511801 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/ShardingMultipleDataSourceApplication.java +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/ShardingMultipleDataSourceApplication.java @@ -5,7 +5,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; -import org.springframework.transaction.annotation.EnableTransactionManagement; /** * @author q diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/config/DataSourceConfiguration.java b/sharding-multiple-data-sources/src/main/java/com/baiye/config/DataSourceConfiguration.java new file mode 100644 index 0000000..fa5c46e --- /dev/null +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/config/DataSourceConfiguration.java @@ -0,0 +1,120 @@ +package com.baiye.config; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider; +import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; +import org.apache.shardingsphere.shardingjdbc.jdbc.adapter.AbstractDataSourceAdapter; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Primary; + +import javax.annotation.Resource; +import javax.sql.DataSource; +import java.util.Map; + +/** + * 动态数据源配置: + * + * 使用{@link com.baomidou.dynamic.datasource.annotation.DS}注解,切换数据源 + * + * @DS(DataSourceConfiguration.SHARDING_DATA_SOURCE_NAME) + * + * @author q + */ +@Configurable +@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, + SpringBootConfiguration.class}) +public class DataSourceConfiguration { + + + /** + * 分表数据源名称 + */ + private static final String SHARDING_DATA_SOURCE_NAME = "sharding_ds"; + + + @Resource + private DynamicDataSourceProperties properties; + + + /** + * shardingjdbc 有四种数据源,需要根据业务注入不同的数据源 + * + *

1. 未使用分片, 脱敏的名称(默认): shardingDataSource; + *

2. 主从数据源: masterSlaveDataSource; + *

3. 脱敏数据源:encryptDataSource; + *

4. 影子数据源:shadowDataSource + * + * fixme 特别注意,有的spring版本不用加Lazy一样能注入,有的会空指针。 根据自己测试选择,但是如果加了lazy就没强转了,也就无法添加其内部的数据源了。 有办法请联系作者。 + * + */ + @Lazy + @Resource(name = "masterSlaveDataSource") + AbstractDataSourceAdapter shardingDataSource; + + + @Bean + public DynamicDataSourceProvider dynamicDataSourceProvider() { + Map datasourceMap = properties.getDatasource(); + return new AbstractDataSourceProvider() { + @Override + public Map loadDataSources() { + Map dataSourceMap = createDataSourceMap(datasourceMap); + // 将 shardingjdbc 管理的数据源也交给动态数据源管理 + dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingDataSource); + //打开下面的代码可以把 shardingJdbc 内部管理的子数据源也同时添加到动态数据源里 (根据自己需要选择开启) +// dataSourceMap.putAll(((MasterSlaveDataSource) masterSlaveDataSource).getDataSourceMap()); + return dataSourceMap; + } + }; + } + + + /** + * 将动态数据源设置为首选的 + * 当spring存在多个数据源时, 自动注入的是首选的对象 + * 设置为主要的数据源之后,就可以支持 shardingjdbc 原生的配置方式了 + * 3.4.0版本及以上使用以下方式注入,老版本请阅读文档 进阶-手动注入多数据源 + */ + @Primary + @Bean + public DataSource dataSource() { + DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); + dataSource.setPrimary(properties.getPrimary()); + dataSource.setStrict(properties.getStrict()); + dataSource.setStrategy(properties.getStrategy()); + dataSource.setP6spy(properties.getP6spy()); + dataSource.setSeata(properties.getSeata()); + return dataSource; + } + + /** + * 第一个数据连接,默认优先级最高 + * @return + */ + @Bean(name = "dataSourceFirst") + @ConfigurationProperties(prefix = "spring.datasource.first") + public DataSource dataSourceFirst() { + //这种方式的配置默认只满足spring的配置方式,如果使用其他数据连接(druid),需要自己独立获取配置 + return DataSourceBuilder.create().build(); + } + + /** + * 第二个数据源 + * @return + */ + @Bean(name = "dataSourceSecond") + @ConfigurationProperties(prefix = "spring.datasource.second") + public DataSource dataSourceSecond() { + return DataSourceBuilder.create().build(); + } + +} diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/config/JpaFirstConfiguration.java b/sharding-multiple-data-sources/src/main/java/com/baiye/config/JpaFirstConfiguration.java new file mode 100644 index 0000000..dfcfdc4 --- /dev/null +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/config/JpaFirstConfiguration.java @@ -0,0 +1,108 @@ +package com.baiye.config; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.domain.EntityScan; +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.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManager; +import javax.sql.DataSource; +import java.util.Map; +import java.util.Objects; + +/** + * 第一个数据源,jpa的相关配置 + * + * 1、实体扫描 + * 2、实体管理ref + * 3、事务管理 + */ +@Configuration +@EntityScan(basePackages = "com.baiye.domain.first") + +@EnableJpaRepositories( + basePackages = "com.baiye.domain.first", + entityManagerFactoryRef = "firstEntityManagerFactoryBean", + transactionManagerRef = "firstTransactionManager") +@EnableTransactionManagement +public class JpaFirstConfiguration { + + @Autowired + private HibernateProperties hibernateProperties; + /** + * 第一个数据源,可以不加Qualifier + */ + @Autowired + @Qualifier("dataSourceFirst") + private DataSource dataSource; + + /** + * jpa其他参数配置 + */ + @Autowired + private JpaProperties jpaProperties; + + /** + * 实体管理工厂builder + */ + @Autowired + private EntityManagerFactoryBuilder factoryBuilder; + + /** + * 配置第一个实体管理工厂的bean + * + * @return + */ + @Bean(name = "firstEntityManagerFactoryBean") + @Primary + public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { + Map properties = hibernateProperties + .determineHibernateProperties( + jpaProperties.getProperties(), + new HibernateSettings() + ); + + return factoryBuilder.dataSource(dataSource) + //这一行的目的是加入jpa的其他配置参数比如(ddl-auto: update等) + //当然这个参数配置可以在事务配置的时候也可以 + .properties(properties) + .packages("com.baiye.domain.first") + .persistenceUnit("firstPersistenceUnit") + .build(); + } + + /** + * EntityManager不过解释,用过jpa的应该都了解 + * @return + */ + @Bean(name = "firstEntityManager") + @Primary + public EntityManager entityManager() { + return Objects.requireNonNull(entityManagerFactoryBean().getObject()).createEntityManager(); + } + + /** + * jpa事务管理 + * @return + */ + @Bean(name = "firstTransactionManager") + @Primary + public JpaTransactionManager transactionManager() { + JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); + jpaTransactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); + return jpaTransactionManager; + } + + +} diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/config/JpaSecondConfiguration.java b/sharding-multiple-data-sources/src/main/java/com/baiye/config/JpaSecondConfiguration.java new file mode 100644 index 0000000..a8814bc --- /dev/null +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/config/JpaSecondConfiguration.java @@ -0,0 +1,100 @@ +package com.baiye.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.domain.EntityScan; +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.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManager; +import javax.sql.DataSource; +import java.util.Map; +import java.util.Objects; + + +/** + * 第二个数据源,jpa的相关配置 + * + * 1、实体扫描 + * 2、实体管理ref + * 3、事务管理 + */ +@Configuration +@EntityScan(basePackages = "com.baiye.domain.second") +@EnableJpaRepositories( + basePackages = "com.baiye.domain.second", + entityManagerFactoryRef = "secondEntityManagerFactoryBean", + transactionManagerRef = "secondTransactionManager") +@EnableTransactionManagement +public class JpaSecondConfiguration { + @Autowired + private HibernateProperties hibernateProperties; + + /** + * 第二个数据源,必须加Qualifier + */ + @Autowired + @Qualifier("dataSourceSecond") + private DataSource dataSource; + + /** + * jpa其他参数配置 + */ + @Autowired + private JpaProperties jpaProperties; + + /** + * 实体管理工厂builder + */ + @Autowired + private EntityManagerFactoryBuilder factoryBuilder; + + /** + * 配置第二个实体管理工厂的bean + * + * @return + */ + @Bean(name = "secondEntityManagerFactoryBean") + public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { + Map properties = hibernateProperties.determineHibernateProperties( + jpaProperties.getProperties(), + new HibernateSettings() + ); + + return factoryBuilder.dataSource(dataSource) + .properties(properties) + .packages("com.baiye.domain.second") + .persistenceUnit("secondPersistenceUnit") + .build(); + } + + /** + * EntityManager不过解释,用过jpa的应该都了解 + * + * @return + */ + @Bean(name = "secondEntityManager") + public EntityManager entityManager() { + return Objects.requireNonNull(entityManagerFactoryBean().getObject()).createEntityManager(); + } + + /** + * jpa事务管理 + * + * @return + */ + @Bean(name = "secondTransactionManager") + public JpaTransactionManager transactionManager() { + JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); + jpaTransactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); + return jpaTransactionManager; + } +} diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/dao/first/PriceRepository.java b/sharding-multiple-data-sources/src/main/java/com/baiye/dao/first/PriceRepository.java new file mode 100644 index 0000000..31c6582 --- /dev/null +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/dao/first/PriceRepository.java @@ -0,0 +1,7 @@ +package com.baiye.dao.first; + +import com.baiye.domain.first.Price; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PriceRepository extends JpaRepository { +} diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/dao/second/UserRepository.java b/sharding-multiple-data-sources/src/main/java/com/baiye/dao/second/UserRepository.java new file mode 100644 index 0000000..e9e4876 --- /dev/null +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/dao/second/UserRepository.java @@ -0,0 +1,14 @@ +package com.baiye.dao.second; + +import com.baiye.domain.second.User; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * 对应user表 -> 存储在库 test_sharding_1 + * + * 代表业务主库 + * + * @author q + */ +public interface UserRepository extends JpaRepository { +} diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/domain/Price.java b/sharding-multiple-data-sources/src/main/java/com/baiye/domain/first/Price.java similarity index 90% rename from sharding-multiple-data-sources/src/main/java/com/baiye/domain/Price.java rename to sharding-multiple-data-sources/src/main/java/com/baiye/domain/first/Price.java index 24a1812..ba8e17b 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/domain/Price.java +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/domain/first/Price.java @@ -1,4 +1,4 @@ -package com.baiye.domain; +package com.baiye.domain.first; import lombok.Data; diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/domain/User.java b/sharding-multiple-data-sources/src/main/java/com/baiye/domain/second/User.java similarity index 88% rename from sharding-multiple-data-sources/src/main/java/com/baiye/domain/User.java rename to sharding-multiple-data-sources/src/main/java/com/baiye/domain/second/User.java index 45981ec..7d57da0 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/domain/User.java +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/domain/second/User.java @@ -1,4 +1,4 @@ -package com.baiye.domain; +package com.baiye.domain.second; import lombok.Data; diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/service/ShardService.java b/sharding-multiple-data-sources/src/main/java/com/baiye/service/ShardService.java index 9cc69c7..934947a 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/service/ShardService.java +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/service/ShardService.java @@ -3,6 +3,7 @@ package com.baiye.service; import com.baiye.dao.OrderRepository; import com.baiye.domain.Order; +import com.baomidou.dynamic.datasource.annotation.DS; import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType; import org.apache.shardingsphere.transaction.core.TransactionType; import org.springframework.beans.factory.annotation.Autowired; @@ -16,6 +17,7 @@ import java.util.Optional; * @author q */ @Service +@DS("sharding_ds") public class ShardService { @Autowired @@ -24,6 +26,7 @@ public class ShardService { /** * 增 */ + @DS("sharding_ds") public Order insertOne(Order order) { return orderRepository.save(order); } @@ -31,10 +34,12 @@ public class ShardService { /** * 批量增加 */ + @DS("sharding_ds") public List batchInsert(List orders) { return orderRepository.saveAll(orders); } + @DS("sharding_ds") public Order queryOne(Long id) { Optional optional = orderRepository.findById(id); return optional.orElse(null); @@ -44,6 +49,7 @@ public class ShardService { /** * 批量查 */ + @DS("sharding_ds") public List queryByCondition(List ids) { return orderRepository.findAllById(ids); } @@ -55,6 +61,7 @@ public class ShardService { */ @Transactional(value = "transactionManager") @ShardingTransactionType(TransactionType.XA) + @DS("sharding_ds") public Order updateByCondition(Order order) { return orderRepository.save(order); } @@ -62,6 +69,7 @@ public class ShardService { /** * 删除 */ + @DS("sharding_ds") public void deleterByCondition(Order order) { orderRepository.delete(order); } diff --git a/sharding-multiple-data-sources/src/main/resources/application-sharddb.properties b/sharding-multiple-data-sources/src/main/resources/application-sharddb.properties index 0a8cd63..8d4b2d1 100644 --- a/sharding-multiple-data-sources/src/main/resources/application-sharddb.properties +++ b/sharding-multiple-data-sources/src/main/resources/application-sharddb.properties @@ -1,3 +1,4 @@ +# ?????? spring.shardingsphere.datasource.names=ds0,ds1 spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource @@ -20,4 +21,20 @@ spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-col spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{user_id % 2} spring.shardingsphere.sharding.tables.t_order.key-generator.column=id spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=13 + +# ?????? +spring.datasource.primary.key=ds-1 +spring.datasource.primary.type=com.alibaba.druid.pool.DruidDataSource +spring.datasource.primary.driverClassName=com.mysql.cj.jdbc.Driver +spring.datasource.primary.url=jdbc:mysql://127.0.0.1:3306/master-1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useTimezone=true +spring.datasource.primary.username=root +spring.datasource.primary.password=root + +spring.datasource.secondary.key=ds-2 +spring.datasource.secondary.type=com.alibaba.druid.pool.DruidDataSource +spring.datasource.secondary.driverClassName=com.mysql.cj.jdbc.Driver +spring.datasource.secondary.url=jdbc:mysql://127.0.0.1:3306/slave-2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useTimezone=true +spring.datasource.secondary.username=root +spring.datasource.secondary.password=root diff --git a/sharding-multiple-data-sources/src/main/resources/application.yml b/sharding-multiple-data-sources/src/main/resources/application.yml index 99243eb..3ede147 100644 --- a/sharding-multiple-data-sources/src/main/resources/application.yml +++ b/sharding-multiple-data-sources/src/main/resources/application.yml @@ -5,10 +5,29 @@ spring: name: sharding-multiple-data-sources profiles: active: sharddb +# jpa配置 jpa: properties: hibernate: show_sql: true + ddl-auto: update + naming: + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect database: mysql + open-in-view: false # true会让数据库连接绑定请求线程,jpa查询是只读事务,会造成主从不能切换! main: allow-bean-definition-overriding: true + # 多数据源配置 + datasource: + first: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/master-1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useTimezone=true + username: root + password: root + second: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/slave-1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useTimezone=true + username: root + password: root \ No newline at end of file