写在前面

SpringBoot创建项目非常方便,而且进行数据访问抛弃了很多繁琐的配置,我前面写的系列博文中,有教大家如何使用SpringBoot进行数据访问,里面谈到了整合JDBC、MyBatis以及JPA。我自己实际开发中,如果没有什么要求限制的话,比较习惯使用JPA进行数据访问,所以在这里,我专门编写一篇博文,来教如何使用SpringBoot整合JPA,进行多数据库的配置,如果有帮助,记得点个关注和点个赞哦

准备

开始之前呢,我们需要先创建项目啦,创建项目使用的是Idea的Spring Initializr进行创建,选择SpringBoot场景的时候,勾选Web、Spring Data JPA、MySQL Driver三个就可以了,如下,然后项目创建成功。
在这里插入图片描述
在这里插入图片描述

主配置文件

如果我们只是进行一个数据库的访问,我们只需要对数据库进行简单的配置,提供相应账号和密码就可以了,不过多个数据库也不是很麻烦,也就是相当于多一份配置内容出来而已,所有配置内容如下

application.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#数据库统一配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.format_sql=true

#主数据库
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost/ubiquity?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver

#副数据库
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost/ubiquity_vote?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver

配置类

我们都知道,我们在配置文件中写的配置,需要我们通过配置类的注入,覆盖掉默认的配置,这样才会生效,所以,我们能够想到,既然是需要使用多个数据库,对应的自然会有多个数据库的相关配置类(这篇博文的示例中,我使用两个数据库,所以有两个数据配置类)
在这里插入图片描述

我们知道,我们首先在只配置类中编写两个配置数据库的组件,然后分别其组件名,具体内容如下。

DataSourceConfig.java

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
package com.dbc.ubiquity.Config;

import org.springframework.beans.factory.annotation.Autowired;
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.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;
import java.util.Map;

@Configuration
public class DataSourceConfig {
@Autowired
private JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;

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

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

@Bean(name = "vendorProperties")
public Map<String, Object> getVendorProperties() {
return hibernateProperties.determineHibernateProperties(
jpaProperties.getProperties(), new HibernateSettings());
}
}

然后我们编写了针对两个数据库的配置类,里面的代码非常的相似,相信你敲了一遍之后,能够感悟到点什么。

PrimaryConfig.java

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
56
57
58
package com.dbc.ubiquity.Config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"com.dbc.ubiquity.Repository.Primary"}//Dao层的位置
)
public class PrimaryConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;

@Autowired
@Qualifier("vendorProperties")
private Map<String, Object> vendorProperties;

@Bean(name = "entityManagerFactoryPrimary")
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder){
return builder
.dataSource(primaryDataSource)
.properties(vendorProperties)
.packages("com.dbc.ubiquity.Model.Primary")//实体类的位置
.persistenceUnit("primaryPersistenceUnit")
.build();
}

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

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

SecondaryConfig.java

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
package com.dbc.ubiquity.Config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactorySecondary",
transactionManagerRef = "transactionManagerSecondary",
basePackages = {"com.dbc.ubiquity.Repository.Secondary"}
)
public class SecondaryConfig {
@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource;

@Autowired
@Qualifier("vendorProperties")
private Map<String, Object> vendorProperties;

@Bean(name = "entityManagerFactorySecondary")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder){
return builder
.dataSource(secondaryDataSource)
.properties(vendorProperties)
.packages("com.dbc.ubiquity.Model.Secondary")
.persistenceUnit("secondaryPersistenceUnit")
.build();
}

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

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

实体类

首先我先把实体类的目录结构放在这,方便后面编写,然后说道实体类的创建,这里可以使用Idea帮我们逆向生成实体类,也就是依照在数据库中已经创建好的数据库表,自动生成实体类,不过这种方式生成出来的实体类,不符合现在编写JPA的序列化格式,生成出来的还是要增改(当然啦,你可以直接去更改实体类生成的模板,没错是可以改的,具体怎么改我这里就不赘述了,自己百度就可以知道),我就来说手动创建,手动创建的好处就是能够对知识点进行更加深入的掌握,当然啦,敲起来比较费时间。
在这里插入图片描述

User.java

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.dbc.ubiquity.Entity.Primary;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "USER", schema = "ubiquity", catalog = "")
public class User implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(nullable = false, unique = true)
private String userName;
@Column(nullable = false)
private String passWord;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = true, unique = true)
private String nickName;
@Column(nullable = false)
private String regTime;

public User() {
}

public User(String userName, String passWord, String email, String nickName, String regTime) {
this.userName = userName;
this.passWord = passWord;
this.email = email;
this.nickName = nickName;
this.regTime = regTime;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getPassWord() {
return passWord;
}

public void setPassWord(String passWord) {
this.passWord = passWord;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getNickName() {
return nickName;
}

public void setNickName(String nickName) {
this.nickName = nickName;
}

public String getRegTime() {
return regTime;
}

public void setRegTime(String regTime) {
this.regTime = regTime;
}
}

Userq.java

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.dbc.ubiquity.Entity.Secondary;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "USERQ", schema = "ubiquity_vote", catalog = "")
public class Userq implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(nullable = false, unique = true)
private String userName;
@Column(nullable = false)
private String passWord;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = true, unique = true)
private String nickName;
@Column(nullable = false)
private String regTime;

public Userq() {
}

public Userq(String userName, String passWord, String email, String nickName, String regTime) {
this.userName = userName;
this.passWord = passWord;
this.email = email;
this.nickName = nickName;
this.regTime = regTime;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getPassWord() {
return passWord;
}

public void setPassWord(String passWord) {
this.passWord = passWord;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getNickName() {
return nickName;
}

public void setNickName(String nickName) {
this.nickName = nickName;
}

public String getRegTime() {
return regTime;
}

public void setRegTime(String regTime) {
this.regTime = regTime;
}
}

写到这里,就要说一下前面主配置文件里面的一些配置是什么了,如下
在这里插入图片描述
它还有其他属性,如下:

  • ddl-auto:create—-每次运行该程序,没有表格会新建表格,表内有数据会清空
  • ddl-auto:create-drop—-每次程序结束的时候会清空表
  • ddl-auto:update—-每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新
  • ddl-auto:validate—-运行程序会校验数据与数据库的字段类型是否相同,不同会报错

Dao层

在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
package com.dbc.ubiquity.Repository.Primary;

import com.dbc.ubiquity.Entity.Primary.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserPrimaryPository extends JpaRepository<User, Long> {
User findById(long id);
User findByUserName(String userName);
User findByUserNameOrEmail(String username, String email);
}

1
2
3
4
5
6
7
8
9
10
11
package com.dbc.ubiquity.Repository.Secondary;

import com.dbc.ubiquity.Entity.Secondary.Userq;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserSecondaryPository extends JpaRepository<Userq, Long> {
Userq findById(long id);
Userq findByUserName(String userName);
Userq findByUserNameOrEmail(String username, String email);
}

测试

到此,我们的多数据库配置流程到此结束,最后就是测试阶段了,我们来验证一下我们的配置是否有用。测试类的内容如下:

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
56
57
58
package com.dbc.ubiquity;

import com.dbc.ubiquity.Entity.Primary.User;
import com.dbc.ubiquity.Entity.Secondary.Userq;
import com.dbc.ubiquity.Repository.Primary.UserPrimaryPository;
import com.dbc.ubiquity.Repository.Secondary.UserSecondaryPository;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.text.DateFormat;
import java.util.Date;

@SpringBootTest
class UbiquityApplicationTests {
@Resource
private UserPrimaryPository userPrimaryPository;
@Resource
private UserSecondaryPository userSecondaryPository;

@Test
public void testSave() throws Exception{
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
String formattedDate = dateFormat.format(date);
userPrimaryPository.save(new User("aa", "aa123456","aa@126.com", "aa", formattedDate));
userPrimaryPository.save(new User("bb", "bb123456","bb@126.com", "bb", formattedDate));
userSecondaryPository.save(new Userq("cc", "cc123456","cc@126.com", "cc", formattedDate));
}

@Test
public void testDelete() throws Exception {
userPrimaryPository.deleteAll();
userSecondaryPository.deleteAll();
}

@Test
public void testBaseQuery() {
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
String formattedDate = dateFormat.format(date);
User user=new User("ff", "ff123456","ff@126.com", "ff", formattedDate);
Userq userq=new Userq("ff", "ff123456","ff@126.com", "ff", formattedDate);
userPrimaryPository.findAll();
userSecondaryPository.findById(3l);
userSecondaryPository.save(userq);
user.setId(2l);
userPrimaryPository.delete(user);
userPrimaryPository.count();
userSecondaryPository.findById(3l);
}

@Test
void contextLoads() {
}

}

在这里插入图片描述
在这里插入图片描述