当使用多个数据源时,休眠环境不起作用

Posted

技术标签:

【中文标题】当使用多个数据源时,休眠环境不起作用【英文标题】:when using miltiple datasource hibernate envers are not working 【发布时间】:2018-07-22 11:21:01 【问题描述】:

当我只使用一个数据源时,休眠环境运行良好(不使用任何 config.java。只需设置 application.properties)。但是使用多个数据源(使用 config.java,相同的数据库,不同的用户),envers 无法正常工作并记录 oracle 错误消息 ORA-00942。 审计表在 DB#1 中。我该怎么办?

弹簧靴 1.5.6

application.properties

#################################
#   DataBase #1 (Default)
#################################
spring.datasource.initialize=true
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:orcl
spring.datasource.username=id_1
spring.datasource.password=pw_1
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver

#################################
#   DataBase #2(Additional)
#################################
db2.datasource.initialize=true
db2.datasource.url=jdbc:oracle:thin:@localhost:1521:orcl
db2.datasource.username=db_2
db2.datasource.password=pw_2
db2.datasource.driverClassName=oracle.jdbc.driver.OracleDriver

config.java

package com.dev;

import javax.sql.DataSource;

import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;

@Configuration
public class DataBaseConfig 

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource defaultDataSource() 
        return DataSourceBuilder.create().build();
    

    @Primary
    @Bean(name = "defaultEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) 


        return builder.dataSource(defaultDataSource())
                .packages("com.dev.core.**", "com.dev.ext.**")
                .build();
    

    @Primary
    @Bean(name = "defaultTransactionManager")
    PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) 
        return new JpaTransactionManager(entityManagerFactory(builder).getObject());
    

    @Configuration
    @EnableJpaRepositories(basePackages= "com.dev.core.**", "com.dev.ext.**",
            entityManagerFactoryRef = "defaultEntityManagerFactory", transactionManagerRef = "defaultTransactionManager")
    static class DefaultJpaRepositoriesConfig 
    

    /*Additional Data Source - NCRM*/
    @Bean
    @ConfigurationProperties(prefix = "db2.datasource")
    public DataSource ncrmDataSource() 
        return DataSourceBuilder.create().build();
    

    @Bean(name = "ncrmEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean ncrmEntityManagerFactory(EntityManagerFactoryBuilder builder) 

        return builder.dataSource(ncrmDataSource())
                .packages("com.dev.ext.ncrm.*.domain")
                .build();
    

    @Bean(name = "ncrmTtransactionManager")
    PlatformTransactionManager ncrmTransactionManagerMain(EntityManagerFactoryBuilder builder) 
        return new JpaTransactionManager(ncrmEntityManagerFactory(builder).getObject());
    

    @Configuration
    @EnableJpaRepositories(
            basePackages="com.dev.ext.ncrm.*.repo",
            entityManagerFactoryRef = "ncrmEntityManagerFactory",
            transactionManagerRef = "ncrmTtransactionManager")
    static class ncrmJpaRepositoriesConfig 
    

defaultDO.java

package com.dev.core.domain;

import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.Table;

import org.hibernate.annotations.NamedNativeQuery;
import org.hibernate.envers.AuditTable;
import org.hibernate.envers.Audited;

import lombok.Data;

@Data
@Entity
@Table(name = "tb_category")
@Audited
@AuditTable("tx_category_audit")
public class CategoryDO 

    //codes 


【问题讨论】:

【参考方案1】:

用户db_2 / pw_2 是否具有访问数据库所需的权限?

【讨论】:

我认为他们有。因为 db_1 & db_2 是相同的数据库但不同的用户。我可以读取 db_1 和 db_2 的数据。但是只有 db_1 中的审计表数据没有被加载。(400 错误 + ORA-00942)。检查/设置所需权限的方法是什么? 您正尝试使用不同的凭据(id_1 / pw_1 和 db_2 / pw_2)登录到同一个数据库。例如,尝试使用 SQL Developer 客户端登录,同时使用两个帐户并尝试从其中一个审计表中进行选择。 我尝试连接两个用户并选择审计表。(db_1 : select * from db_2.table/db_2 : select * from db_1.audit_table) 在 SQL Developer 中,该查询有效。我可以考虑哪些其他设置? 你没有从同一个表中选择:select * from db_2.table / select * from db_1.audit_table [db_1 : audit_tbl // db_2 : tbl] [登录 db_1] - select * from db_1.audit_tbl / select * from db_2.tbl [logging in db_2] - select * from db_1.audit_tbl / select * from db_2.tbl 我测试过并且都可以工作......【参考方案2】:

首先在 application.properties 文件中为两个数据源添加休眠方言,如下所示:

spring.datasource.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
spring.secondDatasource.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect

那么请改写如下配置

package com.multisource.poc.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.LocalContainerEntityManagerFactoryBean;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
public class ApplicationConfiguration 

    @Value("$spring.datasource.hibernate.dialect")
    private String oracleDialect;

    @Value("$spring.secondDatasource.hibernate.dialect")
    private String postgresDialect;

    @Primary
    @Bean(name = "oracleDB")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource oracleDataSource() 
        return  DataSourceBuilder.create().build();
    

    @Primary
    @Bean(name = "oracleEM")
    public LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory(
            EntityManagerFactoryBuilder builder) 

        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", oracleDialect);

        LocalContainerEntityManagerFactoryBean emf = builder
                .dataSource(oracleDataSource())
                .packages("entitypackageOne")
                .persistenceUnit("oraclePU")
                .build();

        emf.setJpaProperties(properties);

        return emf;

    


    @Bean(name = "postgresDB")
    @ConfigurationProperties(prefix = "spring.secondDatasource")
    public DataSource postgresDataSource() 
        return  DataSourceBuilder.create().build();
    

    @Bean(name = "postgresEM")
    public LocalContainerEntityManagerFactoryBean postgresEntityManagerFactory(
            EntityManagerFactoryBuilder builder) 
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", postgresDialect);

        LocalContainerEntityManagerFactoryBean emf = builder
                .dataSource(postgresDataSource())
                .packages("entitypackageTwo")
                .persistenceUnit("postgresPU")
                .build();

        emf.setJpaProperties(properties);

        return emf;
    



现在您可以使用两个不同的 EntityManager。样本就像

@Repository
public class OracleDao implements InterOracle 

    private EntityManager entityManager;

    @Autowired
    public OracleDao(@Qualifier("oracleEM") EntityManager entityManager) 
        this.entityManager = entityManager;
    




@Repository
public class PostgresDao implements InterPostGres
    private static final Logger LOG
            = LoggerFactory.getLogger(PostgresDao.class);


    private EntityManager entityManager;

    @Autowired
    public PostgresDao(@Qualifier("postgresEM") EntityManager entityManager) 
        this.entityManager = entityManager;
    


这就是我的应用程序使用两个不同数据源的工作方式。

【讨论】:

感谢您的回答!但它也不起作用。首先,当我删除 config.java 中的 DefaultJpaRepositoriesConfig() 和 ncrmJpaRepositoriesConfig() 方法时,会出现类似 [Duplicate '@ConfigurationProperties` definition for prefix 'db2.datasource' 的错误。] 其次,像第一个一样删除,会出现类似 [Field com.dev.ext.audits.repo.CatAuditRepo 中的 catRepo 需要一个名为“entityManagerFactory”的 bean,但无法找到。]. 这似乎没有回答问题。

以上是关于当使用多个数据源时,休眠环境不起作用的主要内容,如果未能解决你的问题,请参考以下文章

具有多个条件但 @WhereJoinTable 不起作用的休眠连接表

当 RHS 有多个字符串或字符时,C++11 += 运算符不起作用

休眠教程不起作用

休眠映射不起作用

流利的休眠 HasOne WithForeignKey 不起作用

春季启动中的休眠统计信息不起作用?