当前位置: 首页 > 知识库问答 >
问题:

Spring Boot 2.2.0中的两个数据源和两个存储库

贾越
2023-03-14

我查看了博客帖子、教程、人们的知识库,但没有任何帮助。以下是我所拥有的:

有两个带有MySQL数据库的Docker容器:ebooksec。两个容器都已启动,数据库可见,我可以查询表。

我想在我的项目中有两个数据源:一个用于电子书,另一个用于Spring Security表。

我编写了一个简单的命令行运行程序,其中我只是自动连接两个存储库并检查它们的大小。

运行应用程序时,我得到:

Caused by: java.sql.SQLSyntaxErrorException: Table 'ebooks.Book' doesn't exist

但是,如果我在没有第二个数据源并使用常规Spring的自动配置的情况下运行它,表BOOKS是“可见的”,我可以查询它。

所以这是我的application.properties

book.datasource.url=jdbc:mysql://172.17.0.2:3306/ebooks
book.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
book.datasource.username=someuser
book.datasource.password=somepass

security.datasource.url=jdbc:mysql://172.17.0.3:3306/sec
security.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
security.datasource.username=someuser
security.datasource.password=somepass

我的实体类很小:

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String title;

    private String author;

    private int locations;


    public Book() {
    }

    public Book(String title, String author, int locations) {
        this.title = title;
        this.author = author;
        this.locations = locations;
    }

    public Book(int id, String title, String author, int locations) {
        this(title, author, locations);
        this.id = id;
    }

// ... getters setters and so on
}

@Entity
public class Role {

    @Id
    @GeneratedValue
    private int id;

    private String roleName;


    public Role() {
    }

    public Role(int id, String roleName) {
        this.id = id;
        this.roleName = roleName;
    }

// ... getters and setters
}

这些类位于不同的包中。

再说一次,没什么特别的:


@Repository
public interface RoleRepository extends JpaRepository<Role, Integer> {
}

书籍也是如此,所以我不会粘贴它。

以下是配置类:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = "rnd.mate00.twodatasources.model1",
        entityManagerFactoryRef = "bookEntityManagerFactory",
        transactionManagerRef = "bookTransactionManager")
public class BookDatasourceConfiguration {

    @Value("${book.datasource.driver-class-name}")
    private String driver;

    @Value("${book.datasource.url}")
    private String url;

    @Value("${book.datasource.username}")
    private String user;

    @Value("${book.datasource.password}")
    private String pass;

    @Bean
    @Primary
    public DataSource bookDataSource() {
        System.out.println("Configuring book.datasources");
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(pass);

        return dataSource;
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean bookEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(bookDataSource())
                .packages("rnd.mate00.twodatasources.model1")
                .persistenceUnit("booksPU")
                .build();
    }

    @Bean
    @Primary
    public TransactionManager bookTransactionManager(EntityManagerFactoryBuilder builder) {
        JpaTransactionManager manager = new JpaTransactionManager();
        manager.setDataSource(bookDataSource());
        manager.setEntityManagerFactory(bookEntityManagerFactory(builder).getObject());

        return manager;
    }
}

第二个在单独的班级:

@Configuration
@EnableJpaRepositories(
        basePackageClasses = { Role.class },
        entityManagerFactoryRef = "securityEntityManagerFactory",
        transactionManagerRef = "securityTransactionManager"
)
public class SecurityDatasourceConfiguration {

    @Value("${security.datasource.driver-class-name}")
    private String driver;

    @Value("${security.datasource.url}")
    private String url;

    @Value("${security.datasource.username}")
    private String user;

    @Value("${security.datasource.password}")
    private String pass;

    @Bean
    public DataSource securityDataSource() {
        System.out.println("Configuring security.datasources");
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(pass);

        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean securityEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(securityDataSource())
                .packages(Role.class)
                .persistenceUnit("securityPU")
                .build();
    }

    @Bean
    public TransactionManager securityTransactionManager(EntityManagerFactoryBuilder builder) {
        JpaTransactionManager manager = new JpaTransactionManager();
        manager.setDataSource(securityDataSource());
        manager.setEntityManagerFactory(securityEntityManagerFactory(builder).getObject());

        return manager;
    }

}

Entrypoint类除了SpringBootApplication之外没有注释。

这里是build.gradle

plugins {
    id 'org.springframework.boot' version '2.2.0.M4'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'rnd.mate00'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
}

dependencies {
    runtime('com.h2database:h2')
    compile('mysql:mysql-connector-java')
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
        exclude group: 'junit', module: 'junit'
    }
}

test {
    useJUnitPlatform()
}

共有2个答案

况谦
2023-03-14

当有多个相同类型的bean时,@Qualifier注释用于解决自动装配冲突。

        @Bean
        @Primary
        @Qualifier("bookBean")
         public DataSource bookDataSource() {
            System.out.println("Configuring book.datasources");
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName(driver);
            dataSource.setUrl(url);
            dataSource.setUsername(user);
            dataSource.setPassword(pass);

            return dataSource;
        }

与其他数据源相同。注意:如果使用字段或setter注入,则必须在字段或setter函数的顶部放置@Autowired和@Qualifier

@Autowired 
@Qualifier("bookBean")
 private final BookRepository repo;
毛弘博
2023-03-14

哦,我的。。。缺少的是一个带有表名的实体注释。因此:

@Entity(name = "book")

// ... and

@Entity(name = "role")

加上带有相关列名的正确注释。我在我的小型回购上附加了一个链接,我在其中放置了一个工作示例:https://github.com/mate0021/two_datasources.git

 类似资料:
  • 我正在开发一个基于SAAS的站点,我必须将两个DBs中的两个表连接起来,比如说DB1中的table1和DB2中的table2。我必须使用cakephp中的join从表1和表2获取匹配记录,但它会抛出如下错误: 错误:SQLSTATE[42000]:语法错误或访问冲突:1142 SELECT命令拒绝用户'dbname'@'localhost'访问表'table_name'。 有谁能解释一下如何使用c

  • 我使用的是Sprind JPA、Spring 3.1.2(将来是3.2.3)、Hibernate 4.1 final。我是Sprind Data JPA的新手。我有两个表Release_date_type和Cache_media,它们的实体如下: releaseAirdate.java 我不知道如何映射实体。我尝试了很多事情,但没有运气。任何帮助都很感激。

  • 我需要帮助设置一个应用程序,该应用程序将内部(主)MS SQL数据库DB1中的数据子集复制到另一个MySQL数据库DB2中,该数据库在Web服务器上运行,供Web应用程序使用(即,我想同步这两个数据库)。这两个数据库上的表具有相同的名称,尽管DB2上只定义了属性/列的子集。我想使用(xml配置的)spring、spring data jpa(即JpaRepository接口)和hibernate作

  • 我有一个Java4和Spring Boot2.4.0快照应用程序。 然后在DAO中定义JDBCTemplate。 CompanyContactDAOIMPL.java ApprovalRequestDAOImpl.java unsatisfiedDependencyException:创建名为“Approval RequestDaoImpl”的bean时出错:通过字段“JDBC Template”

  • 问题内容: 我是Spring和Spring Boot的新手。如何配置和使用两个数据源? 例如,这是我对第一个数据源的需求: 应用类别 如何修改以添加另一个数据源?如何将其自动布线以供其他存储库使用? 问题答案:

  • 如何配置和使用两个数据源? 例如,下面是第一个数据源: 应用程序.属性 应用程序类 如何修改以添加另一个数据源?我如何自动将其用于不同的存储库?