多数据源整合springdatJPA问题

多数据源整合springdatJPA问题

JavaConfig方式的多数据源(教程中多是这种解决方式)

​ 这种方式的整体思路就是通过javaconfig读配置文件加载两个数据源,然后springdataJPA扫描不同的包,加载不同的数据源达到两种JPA配置。

pom文件

<!--       引入 持久层框架Spring Data Jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
<!--        引入mysql的jdbc驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>
<!--        引入lombok,使用一些注解如@Data,可实现Bean的getter和setter方法-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
<!--        引入单元测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

配置文件

server:
  port: 10088

spring:
  datasource:
      db1:
        jdbc-url: jdbc:mysql://IP:3306/datasource01?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&useSSL=false
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
      db2:
        jdbc-url: jdbc:mysql://IP:3306/datasource02?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&useSSL=false
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect

配置两个数据源

package com.config;

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;

@Configuration
public class datasourceConfig {


    @Primary
    @Bean(value = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource dataSourceOne(){
        return DataSourceBuilder.create().build();
    }

    @Bean(value = "secondDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource dataSourceTwo(){
        return DataSourceBuilder.create().build();
    }
}

配置JPAPrimaryConfig

package com.config;


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

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = {"com.datasourceOnce.dao"},
        entityManagerFactoryRef = "entityManagerFactoryPrimary",
        transactionManagerRef = "transactionManagerPrimary"
        )
public class JPAPrimaryConfig {

    @Resource
    private JpaProperties jpaProperties;

    @Resource
    private HibernateProperties hibernateProperties;

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

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

    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder){
        Map<String , Object> properties =
                hibernateProperties.determineHibernateProperties(
                        jpaProperties.getProperties(),
                        new HibernateSettings()
                );
        return builder.dataSource(primaryDataSource)
                .properties(properties)
                .packages("com.datasourceOnce.entity")    // 第一个数据源的 domain实体类包 所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }
    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder){
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }

}

配置JPASecondaryConfig

package com.config;

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


@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactorySecondary",
        transactionManagerRef = "transactionManagerSecondary",
        basePackages = {"com.datasourceTwo.dao"}      // 第二个数据源的 repository包 所在位置
)
public class JPASecondaryConfig {

    @Resource
    private JpaProperties jpaProperties;
    @Resource
    private HibernateProperties hibernateProperties;

    @Resource
    @Qualifier("secondDataSource")
    private DataSource secondaryDataSource;


    @Bean(name = "entityManagerSecondary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder){
        return entityManagerFactorySecondary(builder).getObject().createEntityManager();
    }
    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder){
        Map<String , Object> properties =
                hibernateProperties.determineHibernateProperties(
                        jpaProperties.getProperties(),
                        new HibernateSettings()
                );
        return builder.dataSource(secondaryDataSource)
                .properties(properties)
                .packages("com.datasourceTwo.entity")    // 第二个数据源的 domain实体类包 所在位置
                .persistenceUnit("secondaryPersistenceUnit")
                .build();
    }
    @Bean(name = "transactionManagerSecondary")
    public PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder){
        return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
    }
}

UserEntity

package com.datasourceOnce.entity;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;

@Data
@Entity(name = "User")
public class User {

    @Id
    private String id;

    private String name;
}

UserDao

package com.datasourceOnce.dao;

import com.datasourceOnce.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserDao extends JpaRepository<User,String>{
    User findByName(String name);
}

另一个TeacherEntity和TeacherDao和User的基本相同这里就不加了

测试

package com;

import com.datasourceOnce.dao.*;
import com.datasourceOnce.entity.User;
import com.datasourceTwo.dao.TeacherDao;
import com.datasourceTwo.entity.Teacher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.xml.transform.Source;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class TestTheApi {

    @Autowired
    private TeacherDao teacherDao;

    @Autowired
    private UserDao userDao;

    @Test
    public void getUserAndTeacher(){
        User user = userDao.findByName("123");
        System.out.println(user);
        Teacher teacher = new Teacher();
        teacher.setPassword("123");
        teacher.setId("1");
        teacherDao.saveAndFlush(teacher);
        Teacher teacher1 = teacherDao.findByPassword("123");
        System.out.println(teacher1);
    }

}

项目整体结构如图所示

image-20211028191051438

dynamic-datasource-spring-boot-starter

​ 是一个基于 springboot 的快速集成多数据源的启动器。使用mybatis-plus是同一个开发者,可以通过@DS注解切换不同的数据库,同时多数据源还可以有很多组合方式,数据源还可以分组,调配的时候会根据负载均衡自动选择数据库处理。

​ dynamic作为一种非常方便的多数据源的方式,可以在配置不同的JPA的时候根据DynamicRoutingDataSource这个类拿到不同的数据源,等同于第一种方式。

POM文件

只需要在原来的基础上加上

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>

配置文件

server:
  port: 10088

spring:
  datasource:
    dynamic:
      primary: db1 #设置默认的数据源或者数据源组,默认值即为master
      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源。
      datasource:
        db1:
       	 jdbc-url: jdbc:mysql://IP:3306/datasource01?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&useSSL=false
         username: root
         password: root
         driver-class-name: com.mysql.jdbc.Driver
      	db2:
         jdbc-url: jdbc:mysql://IP:3306/datasource02?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&useSSL=false
         username: root
         password: root
         driver-class-name: com.mysql.jdbc.Driver
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect

JPAPrimaryConfig

package com.config;


import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
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.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.ApplicationContext;
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.annotation.Resource;
import javax.persistence.EntityManager;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = {"com.datasourceOnce.dao"},
        entityManagerFactoryRef = "entityManagerFactoryPrimary",
        transactionManagerRef = "transactionManagerPrimary"
        )
public class JPAPrimaryConfig {

    @Resource
    private JpaProperties jpaProperties;

    @Resource
    private HibernateProperties hibernateProperties;


    @Autowired
    private ApplicationContext applicationContext;

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

    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder){
        Map<String , Object> properties =
                hibernateProperties.determineHibernateProperties(
                        jpaProperties.getProperties(),
                        new HibernateSettings()
                );
        DynamicRoutingDataSource routingDataSource = applicationContext.getBean(DynamicRoutingDataSource.class);
        return builder.dataSource(routingDataSource.getDataSource("db1"))
                .properties(properties)
                .packages("com.datasourceOnce.entity")    // 第一个数据源的 domain实体类包 所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }
    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder){
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }

}

JPASecondaryConfig

package com.config;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
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.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.ApplicationContext;
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.annotation.Resource;
import javax.persistence.EntityManager;
import java.util.Map;


@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactorySecondary",
        transactionManagerRef = "transactionManagerSecondary",
        basePackages = {"com.datasourceTwo.dao"}      // 第二个数据源的 repository包 所在位置
)
public class JPASecondaryConfig {

    @Resource
    private JpaProperties jpaProperties;
    @Resource
    private HibernateProperties hibernateProperties;

    @Autowired
    private ApplicationContext applicationContext;


    @Bean(name = "entityManagerSecondary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder){
        return entityManagerFactorySecondary(builder).getObject().createEntityManager();
    }
    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder){
        Map<String , Object> properties =
                hibernateProperties.determineHibernateProperties(
                        jpaProperties.getProperties(),
                        new HibernateSettings()
                );
        DynamicRoutingDataSource routingDataSource = applicationContext.getBean(DynamicRoutingDataSource.class);
        return builder.dataSource(routingDataSource.getDataSource("db2"))
                .properties(properties)
                .packages("com.datasourceTwo.entity")    // 第二个数据源的 domain实体类包 所在位置
                .persistenceUnit("secondaryPersistenceUnit")
                .build();
    }
    @Bean(name = "transactionManagerSecondary")
    public PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder){
        return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
    }
}

整体项目结构

image-20211028191245568

其他相同

OAQ:

jdbcUrl is required with driverClassName问题

spring.datasource.primary.url=jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf-8&useSSL=true

改为

spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf-8&useSSL=true

'hibernate.dialect' not set

Hibernate SQL方言没有设置导致的,在properties文件中增加对应方言,我这里是mysqlInnoDB:

spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
posted @ 2021-10-28 19:14  云子墨  阅读(170)  评论(0编辑  收藏  举报