【问题标题】:Two datasources, two repositories in Spring Boot 2.2.0Spring Boot 2.2.0 中的两个数据源,两个存储库
【发布时间】:2019-12-10 17:03:27
【问题描述】:

我查看了博客文章、教程、人们的存储库,但没有任何帮助。这是我所拥有的:

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

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

我写了一个简单的CommandLineRunner,在其中我只是自动连接两个存储库并检查它们的大小。

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

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;
    }

}

入口点类除了@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()
}

【问题讨论】:

    标签: java spring-boot spring-data-jpa


    【解决方案1】:

    哦,我的...缺少的是带有表名的@Entity 注释。所以:

    @Entity(name = "book")
    
    // ... and
    
    @Entity(name = "role")
    

    加上适当的@Column 注释以及相关的列名。我附上了一个链接到我的小仓库,我在其中放置了一个工作示例: https://github.com/mate0021/two_datasources.git

    【讨论】:

      【解决方案2】:

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

              @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 注入,则必须将 @Autowired 和 @Qualifier 放在字段或 setter 函数的顶部

      @Autowired 
      @Qualifier("bookBean")
       private final BookRepository repo;
      

      【讨论】:

      • 谢谢芒杜,你的回答是正确的,我给你一票(希望你也给我)。但这并不能解决我的问题。我没有自动装配问题,我的存储库对象已绑定,Spring 上下文启动。是别的东西有问题,但我不知道是什么。 :)
      猜你喜欢
      • 2019-01-17
      • 2020-10-12
      • 1970-01-01
      • 1970-01-01
      • 2017-03-30
      • 1970-01-01
      • 1970-01-01
      • 2019-10-28
      • 2021-06-22
      相关资源
      最近更新 更多