【问题标题】:Need Clarification on configuration of Oracle UCP需要澄清 Oracle UCP 的配置
【发布时间】:2020-10-17 18:46:49
【问题描述】:

要求:创建一个多租户应用程序,该应用程序应根据请求中的租户 ID 将每个租户数据插入各自的 PDB。换句话说,每个租户或客户将在 CDB 中拥有自己的 PDB,所有 PDB 将具有相同的架构,并根据请求中的租户 ID 选择数据源并将数据插入该 PDB。

堆栈 - spring boot 2.3.0.RELEASE,Oracle 18c,连接池 - Oracle 共享通用连接池

UCP 连接:

<ucp-properties>
    <connection-pool
        connection-pool-name="pool1"
        connection-factory-class-name="oracle.jdbc.pool.OracleDataSource"
        url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=orcl.accounts.intern)))"
        user="C##commonuser"
        password="commonuser"
        initial-pool-size="10"
        min-pool-size="5"
        max-pool-size="20"
        connection-repurpose-threshold="13"
        sql-for-validate-connection="select 1 from dual"
        shared="true"
    >
        <connection-property name="oracle.jdbc.ReadTimeout" value="2000"/>
        <connection-property name="oracle.net.OUTBOUND_CONNECT_TIMEOUT" value="2000"/>
 
        <data-source data-source-name="pdbcust1" service="pdbcust1.accounts.intern" user="cust1" password="password"/>
        <data-source data-source-name="pdbcust2" service="pdbcust2.accounts.intern" user="cust2" password="password"/>
    </connection-pool>
</ucp-properties>

Spring 数据源配置类:

@Bean
    public DataSource dataSource() throws SQLException {
        System.setProperty("oracle.ucp.jdbc.xmlConfigFile", "file:/" + dbConfigProperties.getUcpConfigFile());
        
        final AbstractRoutingDataSource dataSource = new MultitenantRoutingDataSource();

        targetDataSources = new ConcurrentHashMap<>();

        final PoolDataSource tenantDataSource1 = getTenantDataSource("pdbcust1", "cust1", "password");
        final PoolDataSource tenantDataSource2 = getTenantDataSource("pdbcust2", "cust2", "password");

        
        targetDataSources.put("pdbcust1", tenantDataSource1 );
        targetDataSources.put("pdbcust2", tenantDataSource2 );

        dataSource.setDefaultTargetDataSource(lTenantDataSource2);
    

        lDataSource.setTargetDataSources(lTargetDataSources);

        lDataSource.afterPropertiesSet();

        return lDataSource;
    }

    private static PoolDataSource getTenantDataSource(final String tenantId, String username, String password) {
        try {
            PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource(tenantId);
            
            Properties prop = new Properties();
//          prop.setProperty("user", username);
//          prop.setProperty("password", password);
            
            //pds.reconfigureDataSource(prop);
            
            return pds;

        } catch (final Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }

当我使用租户 ID 发出请求时,上述配置不起作用并引发以下错误:

java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist

    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:509) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:461) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1104) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:550) ~[ojdbc8-19.3.0.0.jar:19.3.0.

但是,如果我在上面的类中取消注释以下行并从 UCP 文件中删除用户名和密码,它会起作用:

prop.setProperty("user", username);
prop.setProperty("password", password);
pds.reconfigureDataSource(prop);

所以我的问题是:

  1. 为什么会这样?
  2. UCP config xmls xsd 有一个用户和密码字段,我们如何使用它?
  3. 此页面描述共享池https://docs.oracle.com/middleware/12213/wls/JDBCA/shared_pooling_ds.htm#JDBCA-GUID-4B7DA858-327E-4CEA-A68C-376792D4A466 这有一行:“这个普通用户必须存在于连接到共享数据源的所有 PDB 中” 这是什么意思?

【问题讨论】:

    标签: oracle spring-data-jpa oracle18c ucp


    【解决方案1】:

    为了使用 ucp 共享池功能,共享一个公共连接池的所有数据源的数据库用户必须相同。所以你不应该在数据源元素下使用用户名和密码。

    <data-source data-source-name="pdbcust1" service="pdbcust1.accounts.intern" />
    <data-source data-source-name="pdbcust2" service="pdbcust2.accounts.intern"/>
    

    如果您需要为每个 pdb 使用不同的用户,那么共享池不是一个选项。在这种情况下,您应该在 XML 中定义两个不同的池,一个用于每个 PDB,这意味着您不应该在 connection-pool 元素中设置 shared=true。另外,对于非共享池,不需要在池级别使用普通用户,您可以直接在池元素下使用 pdb 用户、密码和服务名称。

    <ucp-properties>
        <connection-pool
            connection-pool-name="pool1"
            connection-factory-class-name="oracle.jdbc.pool.OracleDataSource"
            url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=cust1.accounts.intern)))"
            user="cust1"
            password="cust1password"
            initial-pool-size="10"
            min-pool-size="5"
            max-pool-size="20"
            sql-for-validate-connection="select 1 from dual"
        >
            <connection-property name="oracle.jdbc.ReadTimeout" value="2000"/>
            <connection-property name="oracle.net.OUTBOUND_CONNECT_TIMEOUT" value="2000"/>
            <data-source data-source-name="pdbcust1" />
        </connection-pool>
        
        <connection-pool
            connection-pool-name="pool2"
            connection-factory-class-name="oracle.jdbc.pool.OracleDataSource"
            url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=pdbcust2.accounts.intern)))"
            user="cust2"
            password="cust2password"
            initial-pool-size="10"
            min-pool-size="5"
            max-pool-size="20"
            sql-for-validate-connection="select 1 from dual"
        >
            <connection-property name="oracle.jdbc.ReadTimeout" value="2000"/>
            <connection-property name="oracle.net.OUTBOUND_CONNECT_TIMEOUT" value="2000"/>
            
            <data-source data-source-name="pdbcust2" />
        </connection-pool>
    </ucp-properties>
    

    【讨论】:

    • 感谢您的回复。您的意思是我必须将 C##commonuser 添加到所有 PDB 中吗?顺便说一句,我可以使用 C##commonuser 连接到 pdb 数据库,这可能是因为我认为某些 container=ALL 权限就足够了。另外,当我在问题中提到以编程方式设置不同的 PDB 用户时,会有什么行为?
    • 普通用户可以访问所有的PDB,所以这不是问题。共享池的工作原理是可重用性,其中一个 PDB 的连接可以更改并重用于其他 PDB。当您尝试为共享池上的每个数据源设置不同的用户时,您不应该这样做,那么其中一个将生效,而另一个将被忽略。如果您有硬性要求为不同的 PDB 使用不同的用户,那么共享池不是一个选项。
    • 感谢您的回复。问题:普通用户应该只能访问 PDB,还是我们必须在所有 PDB 中创建相同的普通用户?
    • 普通用户可以访问所有 PDB,但您需要向普通用户授予一些额外的权限。 1. 普通用户应具有创建会话、更改会话和设置容器的权限。 2. 普通用户应该对'dbms_service_prvt'包有执行权限。 3. 普通用户的任何特定角色或密码也应在 UCP XML 配置文件中指定。
    猜你喜欢
    • 2017-01-26
    • 1970-01-01
    • 2015-11-19
    • 2012-06-20
    • 2011-11-09
    • 2012-07-18
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多