2013-03-20 462 views
4

我试图实现一个简单的GUI应用程序来处理数据库记录。它将包含记录视图和编辑它们的可能性。下面是我的代码的样子:在使用JDBC中的CachedRowSet时获取“无法提交自动提交时启用自动提交”异常

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的一切。我该如何解决这个问题?

回答

2

只需添加

crs.getConnection().setAutoCommit (false);

+2

我的crs没有方法getConnection()...我也不会在任何地方创建Connection对象。我直接在CachedRowSet上工作。 – user2191938 2013-03-21 06:33:11

+0

您正在创建一个具有getConnection方法的CachedRowSetImpl - 请参见[here](http://docs.oracle.com/cd/E17824_01/dsc_docs/docs/jscreator/apis/rowset/com/sun/rowset/CachedRowSetImpl html的#的getConnection%28%29)。 – Eran 2013-03-21 11:20:50

+2

你是对的,我改变了类型,并看到getConnection()方法。但是当我调用crs.getConnection()时,我得到空值。为什么会发生? – user2191938 2013-03-21 13:07:23

0

我有同样的issue-- 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可能会在未来的版本中被删除。

1

以下内容添加到您的URL结束:

"?relaxAutoCommit=true" 
0

我有类似的问题与CachedRowSet的工作时。我正在使用MySQL数据库。尝试许多解决方案时尝试使用 。我终于想出了两个解决方法,这对我来说很有效。我想在这里提到它们:

  1. 使用Connection对象,并将其传递给execute(con)acceptChanges(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 
    

注意:您不需要设置在这种情况下象setURL()setUser()setPassword()的CachedRowSet的性能。因为CachedRowSet对象使用连接对象连接到数据库,该数据库已经被手动创建,并与autocommit=false

  • 添加?relaxAutoCommit=trueURL通过bobby-paulose

    Example: 
    String url = "jdbc:mysql://localhost:3306/DatabaseName?relaxAutoCommit=true"; 
    
  • 提到