【问题标题】:How to reset a session in a sql connection pool?如何在 sql 连接池中重置会话?
【发布时间】:2021-01-22 07:13:58
【问题描述】:

我有一个使用 javax.sql.DataSource 和 PostgreSQL JDBC 的连接池。这个过程很简单,我从连接池中取出一个虚拟连接,处理它,然后关闭虚拟连接(释放连接到连接池)。一切正常。

但是当我第二次获得相同的虚拟连接时,会话具有与上次执行相同的数据。主要是在上一次执行中创建的临时表。每次执行后如何重置会话?或者,如果不存在查询语法,您能否建议任何解决该问题的方法,而不使用创建临时表。

示例代码

   import java.sql.Connection;
   import javax.naming.Context;
   import javax.naming.InitialContext;
   import javax.naming.NamingException;
   import javax.sql.DataSource;
    
    public class Base {
    
 
      public  Connection getConnection() {
        Context ctx = (Context) new InitialContext().lookup("java:/comp/env");
         DataSource ds = (DataSource) ctx.lookup("database");
        Connection con = ds.getConnection();
        return con;
      }

       public Connection closeConnection( Connection con){
         if (con != null || !con.isClosed()) {
                con.close();
            }
   

    }

context.xml =>

   <Resource 
          accessToUnderlyingConnectionAllowed="true" 
        auth="Container" 
        closeMethod="close" 
        driverClassName="org.postgresql.Driver" 
        maxTotal="50"
        maxWaitMillis="60000" 
        removeAbandonedOnBorrow="true"
        maxIdle="20" 
        name="Database" 
        password="p*******" 
        type="javax.sql.DataSource" 
        url="jdbc:postgresql://dbUrl/dbName" 
        username="dbUser" 
        validationQuery="select version();"
       validationQueryTimeout="60"
    />

//用例

con = getconnection()
CallableStatement st = con.prepareCall("{ doSomething()}");
st.execute()
//processing
st.close()
con.close()

在 doSomething() plpgsql 函数中,我创建了一个临时表(名称为 t_table)、数据处理和数组输出。当我从 java 中反复调用它时,第一次执行是成功的。但是从第二条执行消息中说 t_table 已经存在被抛出。我认为在使用连接池时,池中的连接是独立于会话的 IE。池中的每个新连接都会有一个新会话。 PostgreSQL 解决方案是删除那个特定的临时表。但是从tomcat方面没有其他解决方案吗?

【问题讨论】:

  • @ a_horse_with_no_name 我有一个创建临时表的函数,还有一个带有提交的内部函数。然后表将被删除。所以我正在寻找 JDBC 端本身的解决方案
  • 那么您需要一些手动删除临时表的代码。或者完全摆脱它们。通常情况下,它们的使用并不是真正需要的。
  • @a_horse_with_no_name 没有其他解决方案可以在 JDBC 端处理它。我的意思是java端
  • 请提供minimal reproducible example 并指定您使用的连接池库。此外,如果您使用全局临时表,则无需删除这些表:定义可以保留并可供重用。
  • 这不能回答问题。 javax.sql.DataSource是一个接口,你用的是具体的实现,是哪个? Tomcat内置、Apache DBCP、HikariCP等?

标签: java sql postgresql jdbc connection-pooling


【解决方案1】:

discard temporary 命令可用于清理会话。 您可以将其配置为在连接返回到池时运行的验证查询。

使用 Tomcat JDBC 池,这将是这样的:

validationQuery="discard temporary"
testWhileIdle="false"
testOnBorrow="false"
testOnReturn="true"

如果您想进一步清理会话,可以考虑改用discard all,但这需要启用自动提交,不确定这是否适合您。

如果不允许这样的语句,你可以把它包装成一个函数:

create function session_cleanup()
  returns boolean
as
$$
  discard temporary;
  select true;
$$
language sql;
validationQuery="select session_cleanup()"
testWhileIdle="false"
testOnBorrow="false"
testOnReturn="true"

【讨论】:

  • 发生错误。因为丢弃临时不返回任何东西 java.sql.SQLException: 无法创建 PoolableConnectionFactory (查询未返回任何结果。)
  • 将其放入函数中并在配置中使用select my_cleanup()
  • 我正在寻找tomcat配置本身的解决方案select my_cleanup()可能需要一些时间。
  • 如果你不能使用discard temporary这个函数是你唯一的选择。调用函数的开销非常小,并且会被删除表的实际工作所掩盖。
  • 我的应用程序使用 REST API,因此每次调用 db 我都必须花费大量时间。至少我必须为一次通话牺牲 20 毫秒。所以如果我有 1000 个 API 请求,那么这将成为我的应用程序的瓶颈
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-03
  • 2015-01-03
  • 2017-07-17
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多