赞
踩
上一节讲解了jdbcTemplate配置多数据源,但其实实际中使用jdbcTemplate的情况还是比较少的,这一节我们来看看JPA的数据源怎么配置。
该章节是在JPA的使用基础上讲解的,并不会过多讲解JPA的使用,如果不熟悉JPA的使用的话,可以看看之前的JPA讲解:Spring Boot集成Spring Data JPA。
首先是依赖,除了JPA及数据库的相关依赖外,多数据源并不会增加额外依赖。
<!--mysql连接--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--druid连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!--jpa依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa </artifactId> </dependency>
在配置文件中,声明使用jpa,并指明数据库方言,这里使用的是mysql,然后数据源部分,配置master及slave两个数据库,此处根据实际情况进行配置即可。
server: port: 10900 spring: datasource: master: # 新版驱动从com.mysql.jdbc.Driver变更为com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver # 数据源需要添加时间标准和指定编码格式解决乱码 You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support. url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: 1234 slave: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: 1234 jpa: show-sql: true # 配置jpa数据库类型 database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
配置好数据源后,我们创建DataSourceConfig配置类加载数据源,这个配置类非常简单,就是加载了spring.datasource节点下配置的master与slave,生成对应的masterDataSource与slaveDataSource数据源。需要注意的事,如果启动类上没有额外排除数据源的话,需要在其中一个数据源上注解@Primary以表示该数据源为默认数据源,否则启动会出现无法加载数据源的错误。
@Configuration public class DataSourceConfig { @Bean @Primary // 表示默认的数据源 @ConfigurationProperties(prefix = "spring.datasource.master") DataSource masterDataSource(){ // DataSourceBuilder.create().build(); return DruidDataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.slave") DataSource slaveDataSource(){ return DruidDataSourceBuilder.create().build(); } }
然后创建MasterJpaConfig的配置类,主要对masterDataSource进行属性配置。@EnableTransactionManagement用于声明式事务的开启,而@EnableJpaRepositories用于指定事物管理器及指定实体管理器工厂entityManagerFactory和重要的basePackages。因为JPA是Entry实体与数据库映射的,多数据源的操作本质是通过不同Dao将实体映射到不同的数据源上,basePackages用来声明该JPA数据源配置生效的包,也即com.yanger.jpa.dao下的JPA操作会作用到master数据库。
因为masterDataSource为默认数据源,所以同样的,在注入masterEntityManagerFactory、masterEntityManager以及masterTransactionManager时,我们同样使用了@Primary注解。
@Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef = "masterEntityManagerFactory", //配置连接工厂 entityManagerFactory transactionManagerRef = "masterTransactionManager", //配置事物管理器 transactionManager basePackages = {"com.yanger.jpa.dao"} ) public class MasterJpaConfig { @Autowired @Qualifier("masterDataSource") private DataSource masterDataSource; @Autowired private JpaProperties jpaProperties; @Bean("masterEntityManagerFactory") @Primary public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) { return builder.dataSource(masterDataSource) .properties(jpaProperties.getProperties()) .packages("com.yanger.jpa") //持久化单元名称,当存在多个EntityManagerFactory时,需要制定此名称 .persistenceUnit("masterPersistenceUnit") .build(); } @Bean("masterEntityManager") @Primary public EntityManager entityManager(EntityManagerFactoryBuilder builder) { return entityManagerFactoryBean(builder).getObject().createEntityManager(); } @Bean("masterTransactionManager") @Primary public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactoryBean(builder).getObject()); } }
配置好了masterDataSource数据源的JPA属性,接下来就是slaveDataSource的了。slave相关配置和master差不多,使用了不同的数据源,不需要@Primary修饰,当然作用的包basePackages需要不一样。
@Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef = "slaveEntityManagerFactory", //配置连接工厂 entityManagerFactory transactionManagerRef = "slaveTransactionManager", //配置事物管理器 transactionManager basePackages = {"com.yanger.jpa.sdao"} ) public class SlaveJpaConfig { @Autowired @Qualifier("slaveDataSource") private DataSource slaveDataSource; @Autowired private JpaProperties jpaProperties; @Bean("slaveEntityManagerFactory") public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) { return builder.dataSource(slaveDataSource) .properties(jpaProperties.getProperties()) .packages("com.yanger.jpa") //持久化单元名称,当存在多个EntityManagerFactory时,需要制定此名称 .persistenceUnit("slavePersistenceUnit") .build(); } @Bean("slaveEntityManager") public EntityManager entityManager(EntityManagerFactoryBuilder builder) { return entityManagerFactoryBean(builder).getObject().createEntityManager(); } @Bean("slaveTransactionManager") public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactoryBean(builder).getObject()); } }
这样接下来就可以使用JPA进行不用的数据源操作了,因为对应不同包下的dao会采用不同的数据源及JPA配置。在该演示项目中,master作用的包为com.yanger.jpa.dao,有IUserDao,而slave作用的则是com.yanger.jpa.sdao,创建ISlaveUserDao。
package com.yanger.jpa.dao; import com.yanger.jpa.po.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; public interface IUserDao extends JpaRepository<User, Integer> { /** * 根据用户名和密码查询,根据方法名来生成实体类 * @param username * @param password * @return */ User findByUsernameAndPassword(String username, String password); /** * 根据用户名和密码查询 * @param username * @param password * @return */ @Query(nativeQuery = true, value = "select * from user where username = :username and password = :password") User find(@Param("username") String username, @Param("password") String password); }
package com.yanger.jpa.sdao;
import com.yanger.jpa.po.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ISlaveUserDao extends JpaRepository<User, Integer> {
}
在UserService里,我们分别注入IUserDao和ISlaveUserDao,addUser方法和addUserSlave使用了不同的Dao对象,则可以将数据存储到不同的数据源。
@Service public class UserService { @Autowired private IUserDao userDao; @Autowired private ISlaveUserDao iSlaveUserDao; /** * 添加用户 * @param user */ // 需要指明value属性,否则会使用默认的事务管理,即@Primary声明的那一个 @Transactional(value = "masterTransactionManager") public void addUser(User user){ userDao.save(user); // 除零异常,测试事务 int a =1/0; } /** * 添加用户 * @param user */ // 需要指明value属性,否则会使用默认的事务管理,即@Primary声明的那一个 @Transactional(value = "slaveTransactionManager") public void addUserSlave(User user){ iSlaveUserDao.save(user); // 除零异常,测试事务 int a =1/0; } }
源码地址:https://github.com/imyanger/springboot-project/tree/master/p13-springboot-muti-jpa
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。