查询语句已关闭,无法执行任何操作。

6

我在尝试向数据库插入值时,在我的Java代码中遇到了签名为No operations allowed after statement closed.的异常。这个错误签名表示我的Statement对象被关闭了,而我正在尝试再次使用它,但我很难理解为什么会发生这种情况,因为我没有在我的代码中关闭任何连接。

以下是Java代码:

public class DataBaseAccessUtils {

    private static String jdbcUrl = 
            AppConfig.findMap("BXRequestTracker").get("jdbcUrl").toString();
    private static Connection connection = null;
    private static Statement statement = null;

    public static void insertHostname(String hostname, String rid, String fleet, String locale)
    {
        locale.toUpperCase();
        String sql = "UPDATE " + locale + "REQUESTTRACKER SET " + fleet 
                + "='" + hostname + "' WHERE RID='" + rid + "'";
        try {
            statement.execute(sql);
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static Statement connectToDatabase() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection(DataBaseAccessUtils.jdbcUrl);
            statement = connection.createStatement();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return statement;
    }

我注意到发生错误时,不是在单线程执行时出现的,而是在多个线程同时尝试更新数据库时出现的。

当有人向类路径中添加第二个 Ibatis (v2.3) 但未删除先前的 v2.0 时,我遇到了这个问题。 - Fisk
3个回答

5

创建一个实用程序类来管理整个应用程序中的连接管理,以便在单个点上进行管理。

不要每次需要新连接时都加载 DataSource

示例代码:

public class ConnectionUtil {

    private DataSource dataSource;

    private static ConnectionUtil instance = new ConnectionUtil();

    private ConnectionUtil() {
        try {
            Context initContext = new InitialContext();
            dataSource = (DataSource) initContext.lookup("JNDI_LOOKUP_NAME");
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    public static ConnectionUtil getInstance() {
        return instance;
    }

    public Connection getConnection() throws SQLException {
        Connection connection = dataSource.getConnection();
        return connection;
    }

    public void close(Connection connection) throws SQLException {
        if (connection != null && !connection.isClosed()) {
            connection.close();
        }
        connection = null;
    }

}

始终关闭连接并在 try-catch-finally 中处理它

        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = ConnectionUtil.getInstance().getConnection();

            ...
        } finally {
            if (rs != null) {
                rs.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                ConnectionUtil.getInstance().close(conn);
            }
        }

2

statement 是静态的,因此它在实例(和线程)之间共享。一个线程可能会在另一个线程关闭它后尝试使用该对象。

在多线程中共享数据库连接和语句通常是不明智的,因为JDBC不要求连接具有线程安全性。


我已将Connection和Statement作为实例变量移除并将它们编码为传递给方法insertHostname()的本地变量,但仍然看到错误的痕迹。我应该将我的数据库方法标记为同步吗? - user2890683

1
可能是因为您在两个不同的方法中使用了相同的预处理语句,并且在一个方法中关闭了该语句(pst.close()),但仍然尝试在另一个方法中使用相同的语句。
为了解决这个问题,在您遇到此错误的代码块中获取一个新的连接,然后使用语句。
还有一件事,如果您在两个不同的方法中使用相同的语句,并且在任何一个方法中都没有关闭语句,则可能会出现此错误:

参数索引超出范围(2>参数数量,即1)。

因为相同的语句。因此,请尝试为代码块获取单独的连接和语句,然后关闭连接和语句。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接