SpringBoot+Jpa多数据源配置

关于

有时候,随着业务的发展,项目关联的数据来源会变得越来越复杂,使用的数据库会比较分散,这个时候就会采用多数据源的方式来获取数据。另外,多数据源也有其他好处,例如分布式数据库的读写分离,集成多种数据库等等。下面分享我在实际项目中配置多数据源的案例。

步骤

1.application.yml文件中,配置数据库源。这里primary是主库,secondary是从库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
server:
port: 8089

# 多数据源配置
#primary
spring:
primary:
datasource:
url: jdbc:mysql://127.0.0.1:3306/database1?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
username: root
password: ******
driver-class-name: com.mysql.jdbc.Driver

#secondary
secondary:
datasource:
url: jdbc:mysql://127.0.0.1:3306/database1?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
username: root
password: ******
driver-class-name: com.mysql.jdbc.Driver

jpa:
hibernate:
primary-dialect: org.hibernate.dialect.MySQL5Dialect
secondary-dialect: org.hibernate.dialect.MySQL5Dialect
open-in-view: true
show-sql: true

2.创建一个Spring配置类,其中spring.primary.datasource的路径参考yml文件的配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
public class DataSourceConfig {

@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
@ConfigurationProperties(prefix="spring.primary.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}

@Bean(name = "secondaryDataSource")
@Qualifier("secondaryDataSource")
@Primary
@ConfigurationProperties(prefix="spring.secondary.datasource")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}

}

3.分别创建主库、从库的配置类。
注意:entity包和dao包的配置,以及@Primary注解指定主库。

主库配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"com.xxx.xxx.dao.primary"}) //设置Repository所在位置
public class PrimaryConfig {
@Autowired
private JpaProperties jpaProperties;

@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;

@Primary
@Bean(name = "entityManagerPrimary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
}

@Primary
@Bean(name = "entityManagerFactoryPrimary")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(primaryDataSource)
.properties(getVendorProperties(primaryDataSource))
.packages("com.infinitus.yunxiao_data.entity.primary") //设置实体类所在位置
.persistenceUnit("primaryPersistenceUnit")
.build();
}


private Map getVendorProperties(DataSource dataSource) {
return jpaProperties.getHibernateProperties(dataSource);
}

@Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
}

从库的配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactorySecondary",
transactionManagerRef = "transactionManagerSecondary",
basePackages = {"com.infinitus.yunxiao_data.dao.secondary"}) //设置Repository所在位置
public class SecondaryConfig {
@Autowired
private JpaProperties jpaProperties;

@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource;

@Bean(name = "entityManagerSecondary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactorySecondary(builder).getObject().createEntityManager();
}

@Bean(name = "entityManagerFactorySecondary")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(secondaryDataSource)
.properties(getVendorProperties(secondaryDataSource))
.packages("com.xxx.xxx.entity.secondary") //设置实体类所在位置
.persistenceUnit("primaryPersistenceUnit")
.build();
}


private Map getVendorProperties(DataSource dataSource) {
return jpaProperties.getHibernateProperties(dataSource);
}

@Bean(name = "transactionManagerSecondary")
PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
}

}

4.分别创建主、从库dao类。
主dao:

1
2
3
4
5
6
7
@Repository
public interface PrimaryRepository extends JpaRepository<PrimaryEntity, Long> {

@Query(value = "SELECT p FROM PrimaryEntity p")
List<PrimaryEntity> queryList();

}

从dao:

1
2
3
4
5
6
7
@Repository
public interface SecondaryRepository extends JpaRepository<SecondaryEntity, Long> {

@Query(value = "SELECT p FROM SecondaryEntity p")
List<SecondaryEntity> queryList();

}

5.分别创建主、从库entity类。
主entity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@Entity
@Table(name = "holiday_scheme")
@EntityListeners(AuditingEntityListener.class)
public class PrimaryEntity extends AbstractPersistable<Long> {
@Column(name = "date")
public String date;
@Column(name = "hour")
public String hour;
@Column(name = "holiday")
public String holiday;
@Column(name = "holiday_explain")
public String holiday_explain;

public String getDate() {
return date;
}

public void setDate(String date) {
this.date = date;
}

public String getHour() {
return hour;
}

public void setHour(String hour) {
this.hour = hour;
}

public String getHoliday() {
return holiday;
}

public void setHoliday(String holiday) {
this.holiday = holiday;
}

public String getHoliday_explain() {
return holiday_explain;
}

public void setHoliday_explain(String holiday_explain) {
this.holiday_explain = holiday_explain;
}

@Override
public String toString() {
return "PrimaryEntity{" +
"date='" + date + '\'' +
", hour='" + hour + '\'' +
", holiday='" + holiday + '\'' +
", holiday_explain='" + holiday_explain + '\'' +
'}';
}
}

从entity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Entity
@Table(name = "active_dashboards")
@EntityListeners(AuditingEntityListener.class)
public class SecondaryEntity extends AbstractPersistable<Long> {

@Column(name = "dashboard_id")
public String dashboard_id;
@Column(name = "user_id")
public String user_id;
@Column(name = "order_index")
public String order_index;

public String getDashboard_id() {
return dashboard_id;
}

public void setDashboard_id(String dashboard_id) {
this.dashboard_id = dashboard_id;
}

public String getUser_id() {
return user_id;
}

public void setUser_id(String user_id) {
this.user_id = user_id;
}

public String getOrder_index() {
return order_index;
}

public void setOrder_index(String order_index) {
this.order_index = order_index;
}

@Override
public String toString() {
return "SecondaryEntity{" +
"dashboard_id='" + dashboard_id + '\'' +
", user_id='" + user_id + '\'' +
", order_index='" + order_index + '\'' +
'}';
}
}

6.controller请求获取不同数据库的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RestController
@RequestMapping("/database")
public class MailController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
PrimaryRepository primaryRepository;
@Autowired
SecondaryRepository secondaryRepository;

@RequestMapping("/primary")
@ResponseBody
public String primary() {
return primaryRepository.queryList().toString();
}

@RequestMapping("/secondary")
@ResponseBody
public String secondary() {
return secondaryRepository.queryList().toString();
}

}

注意

下面提两个在配置多数据源时遇到的坑点,一不注意就掉坑了。
1.Application类不需要配置@EnableJpaRepositories注解,会报如下错误。

1
A component required a bean named 'entityManagerFactory' that could not be f

2.注意检查dao类,获取数据的方法上格式是否正确,有没有某个字段是表中不存在的,避免启动异常。如下,SecondaryEntity表中是不存在job_name字段的,所以注释掉才能启动成功等。

1
2
//@Query(value = "SELECT p FROM SecondaryEntity p where p.job_name = ?1")
//List<SecondaryEntity> queryOdcRecord(String job_name);

坚持原创,您的支持是继续创作的动力!
0%