Write before
SpringBoot is easy to create projects, and data access throws away a lot of tedious configuration. In the previous series of blogs, I've taught you how to use SpringBoot for data access. It talks about integrating JDBC, MyBatis, and JPA.In my own actual development, I am more used to using JPA for data access if there are no restrictions, so here I am writing a blog post to teach you how to use SpringBoot to integrate JPA and configure multiple databases. If it is helpful, remember to pay attention and praise.
Get ready
Before we start, we need to create a project. The project was created using Idea's Spring Initializr. When you select the SpringBoot scenario, check the Web, Spring Data JPA, MySQL Driver three, and then the project is created successfully.
Main Profile
If we only have access to one database, we only need to configure the database simply and provide the appropriate account and password. However, it is not a problem to have multiple databases, which is equivalent to one more configuration. All the configuration is as follows
application.properties
#Database Unified Configuration 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 #Master database 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 #Subdatabase 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
Configuration Class
We all know that the configurations we write in the configuration file require us to override the default configuration by injecting the configuration classes in order to take effect, so we can think that since you need to use multiple databases, there will naturally be multiple database-related configuration classes (in this blog post example, I use two databases, so there are two data pairs)Set Class)
We know that we first write the components of two configuration databases in a configuration-only class, and then separate their component names as follows.
DataSourceConfig.java
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()); } }
We then wrote a configuration class for both databases, which has very similar code, and I'm sure you can understand something after you hit it once.
PrimaryConfig.java
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"}//Location of Dao Layer ) 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")//Location of entity classes .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
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()); } }
Entity Class
First I'll put the catalog structure of the entity class here to make it easier to write later. Then I'll talk about the creation of the entity class. Idea can be used here to help us reverse the generation of the entity class, that is, to automatically generate the entity class according to the database tables that have been created in the database. However, the entity class generated in this way does not conform to the serialization format that JPA is now written in.Of course, you can directly change the template generated by the entity class, which is correct and can be changed. I will not repeat how to change it here, Baidu can know it), so I will create it manually. The advantage of manual creation is to have a deeper understanding of the knowledge points, of course, it takes more time to tap.
User.java
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
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; } }
When I write here, I'll tell you what some of the configurations in the main configuration file are, as follows
It has other properties as follows:
- ddl-auto:create - Every time you run the program, no tables will create new tables, and any data in the tables will be emptied
- ddl-auto:create-drop--empties the table every time the program ends
- ddl-auto:update - Every time you run the program, no table will create a new table, no data will be emptied, only updated
- ddl-auto:validate - Run the program to verify that the data has the same field type as the database and that differences will cause errors
Dao Layer
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); }
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); }
test
This concludes our multi-database configuration process, and finally comes the testing phase. Let's verify that our configuration is useful.The contents of the test class are as follows:
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() { } }