在用springboot开发项目时,随着业务量的扩大,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源,下面基于Spring-data-jpa配置多数据源,希望对大家有所帮助。
项目目录结构:
1、先在application.yml 中配置多个数据库:
spring:
datasource:
username: root
password: 123456
#或者写成database1也可以,因为这两个库中都为表tbl_user,表结构啥的都一样
url: jdbc:mysql://localhost:3306/database3?characterEncoding=UTF-8&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
filters: stat
database1:
url: jdbc:mysql://localhost:3306/database1?useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
# database2:
# url: jdbc:sqlserver://localhost:1433;DatabaseName=lf_jybtjcpg
# username: sa
# password: 123456
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
database2:
url: jdbc:mysql://localhost:3306/database2?useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
filters: stat
jpa:
database: mysql
show-sql: true
hibernate:
ddl-auto: update
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
database-platform: org.hibernate.dialect.MySQL5Dialect
这里配置了database1、database2、database3(database3为了对比学习用,不是很规范)三个数据库
2、配置数据库连接属性
在DataBase1Properties类中配置database1数据库连接的属性
package com.hui.demo.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "spring.datasource.database1")
@Component
@Data
public class DataBase1Properties {
private String url;
private String username;
private String password;
private String driverClassName;
public String getUrl() {
return url;
}
public void setUrl(String n) {
url=n;
}
public String getUsername() {
return username;
}
public void setUsername(String n) {
username=n;
}
public String getPassword() {
return password;
}
public void setPassword(String n) {
password=n;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String n) {
driverClassName=n;
}
}
在DataBase2Properties类中配置database2数据库连接的属性:
package com.hui.demo.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "spring.datasource.database2")
@Component
@Data
public class DataBase2Properties {
private String url;
private String username;
private String password;
private String driverClassName;
public String getUrl() {
return url;
}
public void setUrl(String n) {
url=n;
}
public String getUsername() {
return username;
}
public void setUsername(String n) {
username=n;
}
public String getPassword() {
return password;
}
public void setPassword(String n) {
password=n;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String n) {
driverClassName=n;
}
}
在DataBase3Properties类中配置database3数据库连接的属性:
package com.hui.demo.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "spring.datasource") //这行不能注释掉,否则druid的“数据源”界面只会展示两个数据源而不是三个
@Component
@Data
public class DataBase3Properties {
private String url;
private String username;
private String password;
private String driverClassName;
public String getUrl() {
return url;
}
public void setUrl(String n) {
url=n;
}
public String getUsername() {
return username;
}
public void setUsername(String n) {
username=n;
}
public String getPassword() {
return password;
}
public void setPassword(String n) {
password=n;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String n) {
driverClassName=n;
}
}
3、数据库字段设置
在DataSourceConfig类中设置两个数据库的连接数据,可以使用springboot2.0默认的Hikari连接,也可以使用alibaba的druid
package com.hui.demo.config;
import com.hui.demo.config.properties.DataBase1Properties;
import com.hui.demo.config.properties.DataBase2Properties;
import com.hui.demo.config.properties.DataBase3Properties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
@Configuration
@Slf4j
public class DataSourceConfig {
@Autowired
private DataBase1Properties dataBase1Properties;
@Autowired
private DataBase2Properties dataBase2Properties;
@Autowired
private DataBase3Properties dataBase3Properties;
@Bean(name = "dataBase1DataSource")
@Primary
public DataSource dataBase1DataSource(){
System.out.println("dataBase1DataSource初始化----111111");
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(dataBase1Properties.getUrl());
dataSource.setUsername(dataBase1Properties.getUsername());
dataSource.setPassword(dataBase1Properties.getPassword());
dataSource.setDriverClassName(dataBase1Properties.getDriverClassName());
return dataSource;
}
@Bean(name = "dataBase2DataSource")
public DataSource dataBase2DataSource(){
System.out.println("dataBase2DataSource初始化----222222");
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(dataBase2Properties.getUrl());
dataSource.setUsername(dataBase2Properties.getUsername());
dataSource.setPassword(dataBase2Properties.getPassword());
dataSource.setDriverClassName(dataBase2Properties.getDriverClassName());
return dataSource;
}
@Bean(name = "dataBase3DataSource")
public DataSource dataBase3DataSource(){
System.out.println("dataBase3DataSource初始化----333333");
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(dataBase3Properties.getUrl());
dataSource.setUsername(dataBase3Properties.getUsername());
dataSource.setPassword(dataBase3Properties.getPassword());
dataSource.setDriverClassName(dataBase3Properties.getDriverClassName());
return dataSource;
}
}
或者(二选一,也可以混着来,但是使用HikariDataSource的数据库不会出现在durid的“数据源”界面)
package com.hui.demo.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.hui.demo.config.properties.DataBase1Properties;
import com.hui.demo.config.properties.DataBase2Properties;
import com.hui.demo.config.properties.DataBase3Properties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
@Configuration
@Slf4j
public class DataSourceDruidConfig {
@Autowired
private DataBase1Properties dataBase1Properties;
@Autowired
private DataBase2Properties dataBase2Properties;
@Autowired
private DataBase3Properties dataBase3Properties;
@Bean(name = "dataBase1DataSource")
@Primary // 对应的controller中的/query中的select * FROM tbl_user
public DataSource dataBase1DataSource(){
System.out.println("dataBase1DataSource初始化----111111");
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(dataBase1Properties.getUrl());
dataSource.setUsername(dataBase1Properties.getUsername());
dataSource.setPassword(dataBase1Properties.getPassword());
dataSource.setDriverClassName(dataBase1Properties.getDriverClassName());
return dataSource;
}
@Bean(name = "dataBase2DataSource")
// 如果把dataBase1DataSource的@Primary放这里会报错,因为dataBase2中没有tbl_user表,导致select * FROM tbl_user报错
public DataSource dataBase2DataSource(){
System.out.println("dataBase2DataSource初始化----222222");
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(dataBase2Properties.getUrl());
dataSource.setUsername(dataBase2Properties.getUsername());
dataSource.setPassword(dataBase2Properties.getPassword());
dataSource.setDriverClassName(dataBase2Properties.getDriverClassName());
return dataSource;
}
@Bean(name = "dataBase3DataSource")
public DataSource dataBase3DataSource(){
System.out.println("dataBase3DataSource初始化----333333");
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(dataBase3Properties.getUrl());
dataSource.setUsername(dataBase3Properties.getUsername());
dataSource.setPassword(dataBase3Properties.getPassword());
dataSource.setDriverClassName(dataBase3Properties.getDriverClassName());
return dataSource;
}
}
4、配置数据源、连接工厂、事物管理器、dao目录
在DataBaseConfig1类中:
package com.hui.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
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.sql.DataSource;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryDataBase1", // 配置连接工厂
transactionManagerRef = "transactionManagerDatabase1", // 配置事物管理器
basePackages = {"com.hui.demo.dao.database1"} // 设置dao所在位置
)
public class DataBase1Config {
// 配置数据源
@Autowired
private DataSource dataBase1DataSource;
@Primary
@Bean(name = "entityManagerFactoryDataBase1")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryDataBase1(EntityManagerFactoryBuilder builder) {
return builder
// 设置数据源
.dataSource(dataBase1DataSource)
//设置实体类所在位置.扫描所有带有 @Entity 注解的类
.packages("com.hui.demo.entity.database1")
// Spring会将EntityManagerFactory注入到Repository之中.有了 EntityManagerFactory之后,
// Repository就能用它来创建 EntityManager 了,然后 EntityManager 就可以针对数据库执行操作
.persistenceUnit("database1PersistenceUnit")
.build();
}
/**
* 配置事物管理器
*
* @param builder
* @return
*/
@Bean(name = "transactionManagerDatabase1")
PlatformTransactionManager transactionManagerDatabase1(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryDataBase1(builder).getObject());
}
}
在DataBaseConfig2类中:
package com.hui.demo.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.sql.DataSource;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryDataBase2", // 配置连接工厂
transactionManagerRef = "transactionManagerDatabase2", // 配置事物管理器
basePackages = {"com.hui.demo.dao.database2"} // 设置dao所在位置
)
public class DataBase2Config {
// 配置数据源
@Autowired
@Qualifier("dataBase2DataSource")
private DataSource dataBase2DataSource;
@Bean(name = "entityManagerFactoryDataBase2")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryDataBase2(EntityManagerFactoryBuilder builder) {
return builder
// 设置数据源
.dataSource(dataBase2DataSource)
//设置实体类所在位置.扫描所有带有 @Entity 注解的类
.packages("com.hui.demo.entity.database2")
// Spring会将EntityManagerFactory注入到Repository之中.有了 EntityManagerFactory之后,
// Repository就能用它来创建 EntityManager 了,然后 EntityManager 就可以针对数据库执行操作
.persistenceUnit("database2PersistenceUnit")
.build();
}
/**
* 配置事物管理器
*
* @param builder
* @return
*/
@Bean(name = "transactionManagerDatabase2")
PlatformTransactionManager transactionManagerDatabase2(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryDataBase2(builder).getObject());
}
}
在DataBaseConfig3类中:
package com.hui.demo.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.sql.DataSource;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryDataBase3", // 配置连接工厂
transactionManagerRef = "transactionManagerDatabase3", // 配置事物管理器
basePackages = {"com.hui.demo.dao.database3"} // 设置dao所在位置
)
public class DataBase3Config {
// 配置数据源
@Autowired
@Qualifier("dataBase3DataSource")
private DataSource dataBase3DataSource;
@Bean(name = "entityManagerFactoryDataBase3")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryDataBase3(EntityManagerFactoryBuilder builder) {
return builder
// 设置数据源
.dataSource(dataBase3DataSource)
//设置实体类所在位置.扫描所有带有 @Entity 注解的类
.packages("com.hui.demo.entity.dataBase3")
// Spring会将EntityManagerFactory注入到Repository之中.有了 EntityManagerFactory之后,
// Repository就能用它来创建 EntityManager 了,然后 EntityManager 就可以针对数据库执行操作
.persistenceUnit("dataBase3PersistenceUnit")
.build();
}
/**
* 配置事物管理器
*
* @param builder
* @return
*/
@Bean(name = "transactionManagerDataBase3")
PlatformTransactionManager transactionManagerDataBase3(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryDataBase3(builder).getObject());
}
}
@Primary的意思是在众多相同的bean中,优先使用用@Primary注解的bean.而@Qualifier这个注解则指定某个bean有没有资格进行注入。
此时,多数据源的主要配置已经完成,下面是一些实体类、dao的常用配置
5、配置实体类,dao
在User、Student、User、UserDaoRepository、StudentDaoRepository、UsertDaoRepository六个类中分别配置如下:
package com.hui.demo.entity.database1;
import lombok.Data;
import javax.persistence.*;
@Entity
@Table(name = "tbl_user")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String password;
}
package com.hui.demo.dao.database1;
import com.hui.demo.entity.database1.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface UserDaoRepository extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
}
package com.hui.demo.entity.database2;
import lombok.Data;
import javax.persistence.*;
@Entity
@Table(name = "tbl_student")
@Data
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String grade;
}
package com.hui.demo.dao.database2;
import com.hui.demo.entity.database2.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentDaoRepository extends JpaRepository<Student, Integer>, JpaSpecificationExecutor<Student> {
}
package com.hui.demo.entity.database3;
import lombok.Data;
import javax.persistence.*;
@Entity
@Table(name = "tbl_user")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String password;
}
注意:虽然表结构表名都一样,但是不能和上面的UserDaoRepository名称一样,所以这里改成了UsertDaoRepository
package com.hui.demo.dao.database3;
import com.hui.demo.entity.database3.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
// 名称不能和UserDaoRepository重复,虽然是同库同表
public interface UsertDaoRepository extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
}
6、maven文件配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.guoxin</groupId>
<artifactId>SpringbootTest</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.microsoft.sqlserver</groupId>-->
<!-- <artifactId>sqljdbc4</artifactId>-->
<!-- <version>4.0</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
</dependencies>
<build>
<finalName>SpringBootTest</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
7、数据库配置
CREATE TABLE `tbl_user` (
`id` int(10),
`name` VARCHAR(255),
`password` VARCHAR(200)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT into tbl_user(id,name,password) VALUES("1","张三","123456");
INSERT into tbl_user(id,name,password) VALUES("2","王五","654321");
分别创建两个数据库database1、database2,database3,database1中创建tbl_user表,database2中创建tbl_student表,database3中创建tbl_user表,如下图:
8、接口实现
在TestController.java中添加接口访问:
package com.hui.demo.web;
import com.hui.demo.dao.database1.UserDaoRepository;
import com.hui.demo.dao.database2.StudentDaoRepository;
import com.hui.demo.entity.database2.Student;
import com.hui.demo.entity.database1.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
public class TestController {
@Autowired
private UserDaoRepository userDaoRepository;
@Autowired
private StudentDaoRepository studentDaoRepository;
@Autowired
JdbcTemplate jdbcTemplate;
@GetMapping(value = "/getuser")
public List<User> getuser(){
List<User> all = userDaoRepository.findAll();
return all;
}
@GetMapping(value = "/getstudent")
public List<Student> getstudent(){
List<Student> all = studentDaoRepository.findAll();
return all;
}
@ResponseBody
@GetMapping("/query")
public Map<String,Object> map(){
List<Map<String, Object>> list = jdbcTemplate.queryForList("select * FROM tbl_user");
return list.get(0);
}
}
启动类:
package com.lss;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
至此,所有的类都已经实现,启动项目,再浏览器输入url访问数据:
9、访问druid监控页面http://localhost:8080/druid/login.html
疑问:即使配置了“filters: stat”,“SQL监控”界面却监控不到SQL语句,目前不知道是什么原因