2015-12-08 30 views
2

我正試圖處理Java中的多重引導。如何在Java線程中將記錄插入數據庫?

我已經閱讀了許多文章和問題(這裏在StackOverflow),但沒有找到任何明確的例子如何使用它。

我在HsqlDB數據庫中有Unique_Numbers表。有2列:NUMBER和QTY。 我的任務是檢查號碼是否存在,如果是,請增加號碼的數量,如果不是,則插入此號碼。

那麼,我得到了什麼。

這是我的數據庫配置

private final ComboPooledDataSource dataSource; 

public Database(String url, String userName, String password) throws PropertyVetoException { 
    dataSource = new ComboPooledDataSource(); 
    dataSource.setDriverClass("org.hsqldb.jdbcDriver"); 
    dataSource.setJdbcUrl(url); 
    dataSource.setUser(userName); 
    dataSource.setPassword(password); 
    dataSource.setMaxPoolSize(10); 
    dataSource.setMaxStatements(180); 
    dataSource.setMinPoolSize(5); 
    dataSource.setAcquireIncrement(5); 
} 

這是我的邏輯:在表格序號

public void insertRow(String number) throws SQLException { 
    int cnt = getCount(number); 
    if (cnt == 0) { 
     insert(number); 
    } else if (cnt > 0) { 
     update(number); 
    } 
} 

獲取計數

private int getCount(String number) { 
     int cnt = 0; 
     String sql = "select count(number) as cnt from \"PUBLIC\".UNIQUE_NUMBER where number='" + number + "'"; 
     try { 
      Statement sta; 
      try (Connection connection = dataSource.getConnection()) { 
       sta = connection.createStatement(); 
       ResultSet rs = sta.executeQuery(sql); 
       if (rs.next()) { 
        cnt = rs.getInt("cnt"); 
       } 
      } 
      sta.close(); 
     } catch (Exception e) { 
      LOGGER.error("error select cnt by number" + e.toString()); 
     } 

     return cnt; 
    } 

INSERT和UPDATE

private boolean insert(String number) throws SQLException { 
    String sql = "insert into \"PUBLIC\".UNIQUE_NUMBER (number, qty) values(?, ?)"; 
    try (Connection connection = dataSource.getConnection()) { 
     connection.setAutoCommit(false); 
     try (PreparedStatement ps = connection.prepareStatement(sql)) { 
      ps.setString(1, number); 
      ps.setInt(2, 0); 
      ps.addBatch(); 
      ps.executeBatch(); 
      try { 
       connection.commit(); 
      } catch (Exception e) { 
       connection.rollback(); 
       LOGGER.error(e.toString()); 
       return false; 
      } 
     } 
    } 
    return true; 
} 

private boolean update(String number) throws SQLException { 
    String sql = "update \"PUBLIC\".UNIQUE_NUMBER set (qty) = (?) where number = ?"; 
    int qty = selectQtyByNumber(number) + 1; 
    try (Connection connection = dataSource.getConnection()) { 
     connection.setAutoCommit(false); 
     try (PreparedStatement ps = connection.prepareStatement(sql)) { 
      ps.setInt(1, qty); 
      ps.setString(2, number); 
      ps.executeUpdate(); 
      try { 
       connection.commit(); 
      } catch (Exception e) { 
       connection.rollback(); 
       LOGGER.error(e.toString()); 
       return false; 
      } 
     } 
    } 
    return true; 
} 

當我閱讀時,我必須使用Pool Connection。給每個線程一個連接是很重要的。 當我開始我的應用程序時,我得到約束異常或異常與回滾:序列化失敗。

我在做什麼錯?

這裏是我的日誌

[INFO] [generate38] ERROR se.homework.hwbs.tasks.un.server.threads.InsertRowThread - exception while inserting numberintegrity constraint violation: check constraint; SYS_CT_10114 table: UNIQUE_NUMBER 

[INFO] [generate38] ERROR se.homework.hwbs.tasks.un.server.database.Database - error select cnt by number java.sql.SQLTransactionRollbackException: transaction rollback: serialization failure 
[INFO] [generate38] ERROR se.homework.hwbs.tasks.un.server.threads.InsertRowThread - exception while inserting numbertransaction rollback: serialization failure 

[INFO] [generate38] ERROR se.homework.hwbs.tasks.un.server.database.Database - error select cnt by number java.sql.SQLTransactionRollbackException: transactionrollback: serialization failure 
+0

由於您已經有一個異常,您只能進入回滾狀態 - 它是什麼?我想你需要在提交之前創建/開始一個事務。 –

+0

我只是猜測,如果查詢已引發異常,那麼事務必須回滾。我會嘗試交易並在此報告。 –

+0

您的getCount方法容易受到SQL注入的影響。 –

回答

3

非事務方式

執行增量第一

update UNIQUE_NUMBER set qty = qty + 1 where number = ? 

檢查,如果它沒有更新任何行,插入,如果它的數量沒有

int rowsMatched = ps.executeUpdate(); 
if(rowsMatched == 0) { 
    try { 
     insert into UNIQUE_NUMBER (number, qty) values(?, 0) 
    } catch(Exception e) { 
     // the insert will fail if another thread has already 
     // inserted the same number. check if that's the case 
     // and if so, increment instead. 
     if(isCauseUniqueConstraint(e)) { 
      update UNIQUE_NUMBER set qty = qty + 1 where number = ? 
     } else {throw e;} 
    } 
} 

沒有交易處理(setAutoCommit(false),commit()rollback())需要。

的交易方式

如果您仍然想這樣做在事務的方式,你需要做一個事務中的所有步驟,如@EJP建議:

connection.setAutoCommit(false); 
// check if number exists 
// increment if it does 
// insert if it doesn't 
// commit, rollback & repeat in case of error 
connection.setAutoCommit(true); 

集汽車如果此代碼與其他代碼共享連接池(因爲這是其他人希望連接所在的默認狀態),或者明確指出池中的連接始終處於事務模式,則將其重新設置爲true。

在你的代碼,getCount有時會得到自動連接提交模式(第一次使用),並有時會在交易模式下的連接(insert和/或update後重復使用) - 這就是爲什麼你在getCount看到回滾異常。

+0

謝謝!按我的預期工作! –

相關問題