2013-03-20 458 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"; 
    
  • 提到