4

我正在尝试实现一个简单的 GUI 应用程序来处理数据库记录。它将包含记录视图和编辑它们的可能性。这是我的代码的样子:

class MainPanel extends JPanel {

    private CachedRowSet crs;
    private List<JTextField> fields = new LinkedList<>();

    MainPanel() {
        try {
            //Fill result set with data
            crs = new CachedRowSetImpl();
            crs.setUrl("jdbc:postgresql:testdb");
            crs.setUsername("username");
            crs.setPassword("password");
            crs.setCommand("SELECT * FROM products");
            crs.execute();

            //Create text fields with labels
            ResultSetMetaData meta = crs.getMetaData();
            for (int a = 1; a <= meta.getColumnCount(); a++) {
                JTextField field = new JTextField(10);
                add(new JLabel(meta.getColumnLabel(a)));
                fields.add(field);
                add(field);
            }

            //Fill fields on startup
            crs.next();
            updateFields();

            //Buttons
            JButton nextButton = new JButton("Next");
            nextButton.addActionListener(...);
            add(nextButton);

            JButton prevButton = new JButton("Previous");
            prevButton.addActionListener(...);
            add(prevButton);

            JButton saveButton = new JButton("Save changes");
            saveButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent event) {
                    try {
                        for (int a=0; a<fields.size(); a++) {
                            crs.updateString(a+1, fields.get(a).getText());
                        }
                        crs.acceptChanges();
                    } catch (SQLException ex) {
                        ex.printStackTrace();
                    }
                }
            });
            add(saveButton);
        }
        catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    private void updateFields() throws SQLException {
        for (int a = 0; a < fields.size(); a++) {
            fields.get(a).setText(crs.getString(a + 1).trim());
        }
    }
}

走下一个和上一个工作正常。但是在尝试保存记录时出现异常。堆栈跟踪如下:

org.postgresql.util.PSQLException: Cannot commit when autoCommit is enabled.
    at org.postgresql.jdbc2.AbstractJdbc2Connection.commit(AbstractJdbc2Connection.java:705)
    at com.sun.rowset.internal.CachedRowSetWriter.commit(CachedRowSetWriter.java:1396)
    at com.sun.rowset.CachedRowSetImpl.acceptChanges(CachedRowSetImpl.java:893)
    at test.MainPanel$3.actionPerformed(MainPanel.java:85)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
    ...

如何防止此异常?什么是自动提交?我知道 Connection 类可以选择将其设置为 false,但我不想使用 Connection 类。我想使用 CachedResultSet 完成所有事情。我该如何解决这个问题?

4

4 回答 4

1

只需添加

crs.getConnection ().setAutoCommit (false);

于 2013-03-20T17:31:17.453 回答
1

将以下内容添加到URL的末尾:

"?relaxAutoCommit=true"
于 2014-01-03T18:31:28.107 回答
0

我在使用 CachedRowset 时遇到了类似的问题。我正在使用MySQL数据库。同时尝试许多解决方案。我终于想出了两个对我有用的解决方法。我想在这里提到它们:

  1. 使用 Connection 对象并将它们传递给execute(con)andacceptChanges(con)方法。也设置setAutoCommit(false)。例子:

    Connection conn = DriverManager.getConnection(databaseUrl, username, password);
    conn.setAutoCommit(false);
    CachedRowSet rowSet=new CachedRowSetImpl();
    rowSet.setCommand("SELECT * FROM tableName");
    int [] keys = {1};  // Set column 1 as the key column in the RowSet
    rowSet.setKeyColumns(keys);
    rowSet.execute(conn);  // Execute on connection
    rowSet.moveToInsertRow();
    rowSet.updateInt(1, 89);  // Use column number
    rowSet.updateString(2, "Programming");
    rowSet.updateInt(3, 77);
    rowSet.insertRow();
    // Need to move away from insert row before apply changes
    rowSet.moveToCurrentRow();
    // Reconnect to data source to apply change in the RowSet.
    rowSet.acceptChanges(conn);  // On non-autocommit Connection
    

注意:在这种情况下,您不需要设置 CachedRowset 的属性,例如 setURL(),setUser()setPassword(). 因为 CachedRowset 对象使用 Connection 对象连接到手动创建的数据库 autocommit=false

  1. 添加?relaxAutoCommit=truebobby-paulose提到的URL

    Example:
    String url = "jdbc:mysql://localhost:3306/DatabaseName?relaxAutoCommit=true";
    
于 2014-07-07T14:30:37.987 回答
0

我遇到了同样的问题——CachedRowSetImpl.acceptChanges() 未能关闭自动提交,当它提交更改时会抛出异常,因为它们已经单独提交。

这可能是因为 PostgreSQL 对自动提交有点挑剔。PostgreSQL 不允许通过 SQL 语句关闭自动提交(尽管它在早期是这样做的)。相反,任何必须作为一个组提交的 SQL 语句都必须夹在 SQL 语句 BEGIN 和 COMMIT 之间。PostgreSQL 的 JDBC 驱动程序确实支持 Connection.setAutoCommit(false),但我敢打赌这只会提示驱动程序在幕后创建一个 BEGIN-COMMIT 三明治。我的猜测是 CachedRowSetImpl.acceptChanges() 试图使用 SQL 语句来关闭自动提交而不是使用 setAutoCommit(false) ,这就是它失败的原因。

我发现解决此问题的唯一方法是创建一个临时连接,关闭自动提交,并将连接传递给acceptChanges 的一个参数版本。所以代替这个:

crs.acceptChanges()

你会有这样的事情:

try (Connection con 
        = DriverManager.getConnection(url, username, password)) {
    con.setAutoCommit(false);
    crs.acceptChanges(con);
}

这确实需要使用您试图避免的 Connection 类,但可能没有其他选择(除了不使用 JDBC)。您不能使用 CachedRowSetImpl.getConnection() 因为它只检索在外部创建然后传入的连接。您不能通过 url 指定您希望自动提交关闭,因为 PostgreSQL 不允许这样做。如果可以更新 CachedRowSetImpl.acceptChanges() 以便它成功地自行关闭自动提交,那就太好了。但是,这似乎不太可能,因为我的编译器警告说 CachedRowSetImpl 可能会在未来的版本中被删除。

于 2013-06-18T01:03:20.280 回答