如何在jdbc中为事务设置局部变量

Posted

技术标签:

【中文标题】如何在jdbc中为事务设置局部变量【英文标题】:how to set local variable for transaction in jdbc 【发布时间】:2018-11-02 11:17:39 【问题描述】:

我正在开发一个项目,我需要在其数据库中初始化会话变量。如果我直接使用sql,初始化是用SET语句完成的

set local app.user_id to "0000";

我尝试用Connection#setClientInfo() 初始化它,但失败了

try(Connection connection = getDataSource().getConnection()) 
    boolean isAutoCommit = connection.getAutoCommit();
    try 
        Properties properties = new Properties();
        properties.put("app.user_id", "0000");

        connection.setAutoCommit(false);
        connection.setClientInfo(properties);

        String query = "insert into positions (name, description) values (?, ?)";

        try(PreparedStatement statement = connection.prepareStatement(query)) 
            statement.setString(1, position.getName());
            statement.setString(2, position.getDescription());

            statement.executeUpdate();
        

        connection.commit();
    
    catch (SQLException e) 
        e.printStackTrace();
        connection.rollback();
    
    finally 
        connection.setAutoCommit(isAutoCommit);
    

我得到PSQLException(插入查询依赖于参数,它没有通过)

org.postgresql.util.PSQLException: ERROR: unrecognized configuration parameter "app.user_id"

如果我使用PreparedStatement,我会收到带有消息的PSQLException ERROR: syntax error at or near "$1"

try(Connection connection = getDataSource().getConnection()) 
    boolean isAutoCommit = connection.getAutoCommit();
    try 
        connection.setAutoCommit(false);
        try(PreparedStatement statement = connection.prepareStatement("set local app.user_id to ?")) 
            statement.setString(1, "0000");
            statement.execute();
        

        String query = "insert into positions (name, description) values (?, ?)";

        try(PreparedStatement statement = connection.prepareStatement(query)) 
            statement.setString(1, position.getName());
            statement.setString(2, position.getDescription());

            statement.executeUpdate();
        

        connection.commit();
    
    catch (SQLException e) 
        e.printStackTrace();
        connection.rollback();
    
    finally 
        connection.setAutoCommit(isAutoCommit);
    

唯一的方法是直接使用固定值执行查询。但在这样做时,我不得不使用连接来构建查询。而且我不想这样做。

try(Connection connection = getDataSource().getConnection()) 
    boolean isAutoCommit = connection.getAutoCommit();
    try 
        connection.setAutoCommit(false);
        try(Statement statement = connection.createStatement()) 
            statement.execute("set local app.user_id to 0000");
        

        String query = "insert into positions (name, description) values (?, ?)";

        try(PreparedStatement statement = connection.prepareStatement(query)) 
            statement.setString(1, position.getName());
            statement.setString(2, position.getDescription());

            statement.executeUpdate();
        

        connection.commit();
    
    catch (SQLException e) 
        e.printStackTrace();
        connection.rollback();
    
    finally 
        connection.setAutoCommit(isAutoCommit);
    

初始化这些参数的正确方法是什么? 我使用 PostgreSQL 11、JDBC 4.2(带有驱动程序 42.2.5)和 DBCP 2.5

编辑

我是通过致电set_config 做到的。

try(PreparedStatement statement = connection.prepareStatement("select set_config(?, ?, true)")) 
    statement.setString(1, "app.user_id");
    statement.setString(2, "0000");

    statement.execute();

但问题仍然存在。如何在JDBC中调用SET

【问题讨论】:

【参考方案1】:

我认为您需要在 DataSource 而不是 Connection 上执行此操作。

postgresql 我知道的唯一方法是下转换。比如:

DataSource myDS = getDataSource();
if (DataSource instanceof BaseDataSource.class) 
    BaseDataSource pgDS = (BaseDataSource) myDS;   // expose setProperty method
    pgDS.setProperty("app.user_id", "0000");

您将其放置在应用程序中的哪个位置显然取决于您的问题中未提供的许多细节。

【讨论】:

我用org.apache.commons.dbcp2.BasicDataSource

以上是关于如何在jdbc中为事务设置局部变量的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在子查询 SQL Server 中分配局部变量

Thymeleaf 在表中为 <tr> 使用局部变量

如何将函数中的短局部变量设置为公共

SQL 视图 局部变量 全局变量 条件语句 事务 触发器

Action Mailer NameError:未定义的局部变量或方法“smtp”

jmeter的全局变量和局部变量