Postgres 9.6.17和JDBC 42.2.1如何将连接模式切换为“扩展”

问题描述 投票:1回答:1

我有一个Postgres 9.6.17 DBMS和一个简单的Java独立程序(没有Spring),该程序连接到DBMS并发出查询。根据Postgres文档,可以在“简单模式”或“扩展模式”(其中解析和查询重写一次完成)中执行查询,但是绑定重复发生。

我有一个简单的表customer(cust_id integer, first_name varchar(100), last_name varchar(100))。我正在执行的代码如下:

Properties props = new Properties();
....//typical properties such as user, password, database etc
props.setProperty("preferQueryMode", "extendedForPrepared");
Connection con = DriverManager.getConnection(url, props);
PreparedStatement st = con.prepareStatement("select * from ecommerce.customer where cust_id = ?");
st.setInt(1, 22);
ResultSet rs = st.executeQuery();    

我希望这会在JDBC客户端和DBMS后端之间产生“扩展查询模式”协议。但是,它始终产生“简单查询模式”交互。我通过为PostgreSQL驱动程序启用JDBC日志记录来验证了这一点。我还查看了JDBC驱动程序中Query接口的实现,我只能找到3种实现,如下所示:

  1. BatchedQuery
  2. CompositeQuery
  3. SimpleQuery

尽管名称为CompositeQuery,但所做的只是将涉及多个语句的查询拆分为SimpleQuery对象的列表。

所以,我的问题是如何使我的扩展模式连接使用的协议?

postgresql jdbc
1个回答
1
投票

默认情况下,在使用准备好的语句5次之后,Postgres JDBC驱动程序只会开始使用服务器端语句。从JDBC driver property documentation

prepareThreshold = int

确定在切换为使用服务器端准备好的语句之前所需的PreparedStatement执行次数。默认值为5,这意味着在同一PreparedStatement对象的第五次执行时开始使用服务器端的预处理语句。有关服务器端预备语句的更多信息,请参见“服务器预备语句”一节。

但是该属性可以更改。

这是我测试过的程序:

Properties props = new Properties();
props.setProperty("user", "test");
props.setProperty("password", "test");
props.setProperty("loggerLevel", "TRACE");
props.setProperty("prepareThreshold", "1");
try (Connection con = DriverManager.getConnection("jdbc:postgresql:test", props);
     PreparedStatement stat = con.prepareStatement("select * from app_user where username = ?"))
{
    for (String username : List.of("user1", "user2", "user3"))
    {
        stat.setString(1, username);
        try (ResultSet rs = stat.executeQuery())
        {
            if (rs.next())
                System.out.println("User " + username + " has ID: " + rs.getString(1));
        }
    }
}

[prepareThreshold设置为1时,日志显示:

Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@33065d67, maxRows=0, fetchSize=0, flags=16
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST:  FE=> Parse(stmt=S_1,query="select * from app_user where username = $1",oids={1043})
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=S_1,portal=null,$1=<'user1'>)
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST:  FE=> Describe(portal=null)
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)
...
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@35dab4eb, maxRows=0, fetchSize=0, flags=16
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=S_1,portal=null,$1=<'user2'>)
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)
...
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@2d901eb0, maxRows=0, fetchSize=0, flags=16
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=S_1,portal=null,$1=<'user3'>)
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)

这表明查询解析发生一次,然后有重复的绑定。


与未设置prepareThreshold时比较:

Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@33065d67, maxRows=0, fetchSize=0, flags=17
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST:  FE=> Parse(stmt=null,query="select * from app_user where username = $1",oids={1043})
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=null,portal=null,$1=<'user1'>)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST:  FE=> Describe(portal=null)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)
...
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@8519cb4, maxRows=0, fetchSize=0, flags=17
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST:  FE=> Parse(stmt=null,query="select * from app_user where username = $1",oids={1043})
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=null,portal=null,$1=<'user2'>)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST:  FE=> Describe(portal=null)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)
...
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@35dab4eb, maxRows=0, fetchSize=0, flags=17
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST:  FE=> Parse(stmt=null,query="select * from app_user where username = $1",oids={1043})
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=null,portal=null,$1=<'user3'>)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST:  FE=> Describe(portal=null)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)

其中有3个单独的语句进行解析和绑定。在查询5次之后,它们应该开始重新使用。


关于查询模式是'simple'还是'extended',无论日志看起来总是打印'simple execute',但是区别在于真正的简单模式,参数不会绑定在准备好的语句中,而是整个查询将以文本形式发送。在此示例中,如果preferQueryMode属性设置为simple,则日志显示:

Feb 18, 2020 2:06:19 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@33065d67, maxRows=0, fetchSize=0, flags=1,041
Feb 18, 2020 2:06:19 PM org.postgresql.core.v3.QueryExecutorImpl sendSimpleQuery
FINEST:  FE=> SimpleQuery(query="select * from app_user where username = 'user1'")
...
Feb 18, 2020 2:06:20 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@28261e8e, maxRows=0, fetchSize=0, flags=1,041
Feb 18, 2020 2:06:20 PM org.postgresql.core.v3.QueryExecutorImpl sendSimpleQuery
FINEST:  FE=> SimpleQuery(query="select * from app_user where username = 'user2'")
...
Feb 18, 2020 2:06:20 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@d737b89, maxRows=0, fetchSize=0, flags=1,041
Feb 18, 2020 2:06:20 PM org.postgresql.core.v3.QueryExecutorImpl sendSimpleQuery
FINEST:  FE=> SimpleQuery(query="select * from app_user where username = 'user3'")

注意此值与默认值之间的区别-没有参数,并且'user1','user2'和'user3'值将随每个查询内联发送。


我认为您真正要寻找的是立即重用服务器端语句并重新绑定参数。在这种情况下,将prepareThreshold设置为1将完成此工作。

© www.soinside.com 2019 - 2024. All rights reserved.