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

需要澄清Oracle UCP的配置

司宏伯
2023-03-14

需求:创建一个多租户应用程序,该应用程序应该根据请求中的租户id将每个租户的数据插入到各自的PDB中。换句话说,每个租户或客户在CDB中都有自己的PDB,所有PDB都有相同的模式,然后根据请求中的租户Id选择一个数据源,并将数据插入到该PDB中。

Stack-Spring boot 2.3.0.发行版,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配置xmls xsd有一个用户和密码字段,我们如何使用它?
  3. 此页描述共享池https://docs.oracle.com/middleware/12213/wls/jdbca/shared_pooling_ds.htm#jdbca-guid-4b7da858-327e-4cea-a68c-376792d4a466这一行:“此公共用户必须存在于所有连接到共享数据源的PDB中”这是什么意思?

共有1个答案

章安易
2023-03-14

为了使用ucp共享池特性,对于共享一个公共连接池的所有数据源,数据库用户必须是相同的。因此,不应在datasource元素下使用user和password。

<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。另外,对于非共享池,不需要在池级别使用公共用户,您可以直接在pool元素下使用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>
 类似资料:
  • 我认为用A*算法应该是SAEFG,但答案是SBEFG。现在我的教授是一个无所事事的人。有人能解释为什么是SBEFG吗?

  • 来自 https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-blob#poison 当 Blob 触发器函数失败时... “失败”是什么意思?编译失败?引发未处理的异常? 如果有一些不起作用的示例代码,那就太好了。所有示例代码都显示了工作状态,因此无法演示 Azure 函数中的故障模式。

  • 我们有申报单 其中backlog被标识为传入连接的最大队列长度。如果连接指示在队列已满时到达,则会拒绝连接。 假设积压设置为10。 这是否意味着服务器套接字将接受不超过10个客户端? 然后: 只有当时,积压数才会下降。这是正确的吗? 有没有办法知道一个套接字当前正在处理多少个打开的连接(换句话说,它离放弃并开始拒绝新连接有多近)

  • 问题内容: 在如何使用JMS资源以及在注释上使用适当的设置方面似乎存在一些不一致之处。 首先,这是我的资源配置( glassfish-resources.xml ,但可以翻译为其他部署描述符)。这与ActiveMQ资源适配器一起应用于Glassfish(): 这是我的消息提供程序bean。您会注意到找到了JNDI名称,并且使用了ActiveMQ资源而没有错误,该消息已发送到适当的队列: 当定义一个

  • 我需要一些帮助来澄清写关注的概念,我使用MongoDb 4.0.2(带副本集)和java-mongo驱动程序3.8.1 我已经在mongo配置中添加了关于 在代码端,何时可以使用数据库的ack响应?我发现,当使用delete或update时,库返回一个Result对象(作为deletesult),其中包含一个函数,用于获取集合中多数副本的delete/update结果。 但是我找不到一个类似的所有

  • 现在,编辑器在使用注释方法的地方显示警告。然后显示使用的建议。当我接受它的更改时,它会将代码转换为此,警告消失。 使用有意义吗? 实现是 所以如果为空,我的代码仍然会崩溃。 我们应该对此进行空检查。 我认为比好,你说呢?如果是,则编辑器不应建议在此处使用。 因为在具有状态(如)的字段中使用要求NonNull是不安全的。我是否错过了的一些好处?