2012-10-24 51 views
0

我在我準備好的語句中使用了MERGE命令,當我在單線程環境中執行它時,它的工作正常,但是在多線程環境中,它會導致一些問題。即數據被複制,也就是說如果我有5個線程,每條記錄都會重複5次。我認爲db中沒有鎖定來幫助線程。 我的代碼:多線程編寫語句

//db:oracle 
sb.append("MERGE INTO EMP_BONUS EB USING (SELECT 1 FROM DUAL) on (EB.EMP_id = ?) WHEN MATCHED THEN UPDATE SET TA =?,DA=?,TOTAL=?,MOTH=? WHEN NOT MATCHED THEN "+ "INSERT (EMP_ID, TA, DA, TOTAL, MOTH, NAME)VALUES(?,?,?,?,?,?) "); 

//sql operation,calling from run() method 
public void executeMerge(String threadName) throws Exception {    
     ConnectionPro cPro = new ConnectionPro(); 
     Connection connE = cPro.getConection(); 
     connE.setAutoCommit(false); 
     System.out.println(sb.toString()); 
     System.out.println("Threadname="+threadName); 
     PreparedStatement pStmt= connE.prepareStatement(sb.toString()); 
     try { 
      count = count + 1; 

      for (Employee employeeObj : employee) {//datalist of employee 

       pStmt.setInt(1, employeeObj.getEmp_id()); 
       pStmt.setDouble(2, employeeObj.getSalary() * .10); 
       pStmt.setDouble(3, employeeObj.getSalary() * .05); 
       pStmt.setDouble(4, employeeObj.getSalary() 
         + (employeeObj.getSalary() * .05) 
         + (employeeObj.getSalary() * .10)); 
       pStmt.setInt(5, count); 
       pStmt.setDouble(6, employeeObj.getEmp_id()); 
       pStmt.setDouble(7, employeeObj.getSalary() * .10); 
       pStmt.setDouble(8, employeeObj.getSalary() * .05); 
       pStmt.setDouble(9, employeeObj.getSalary() 
         + (employeeObj.getSalary() * .05) 
         + (employeeObj.getSalary() * .10)); 
       pStmt.setInt(10, count); 
       pStmt.setString(11, threadName); 
       // pStmt.executeUpdate(); 

       pStmt.addBatch(); 
      } 

      pStmt.executeBatch(); 
      connE.commit(); 
     } catch (Exception e) { 
      connE.rollback(); 
      throw e; 

     } finally { 

      pStmt.close(); 
      connE.close(); 

     } 
    } 

如果employee.size = 5,線程數= 5,執行後,我會得到25條記錄,而不是5

回答

0

如果沒有約束(即一個主鍵或唯一在emp_bonus中的emp_id列的關鍵約束),將不會阻止數據庫允許每個線程插入5行。由於每個數據庫會話都看不到其他會話所做的未提交更改,因此每個線程都會看到emp_bonus中沒有行,並且線程正在查找emp_id(我假設employeeObj.getEmp_id()在每個線程中返回相同的值)如果有5個線程,每個線程將插入所有5行,並留下總共25行。如果你有一個唯一的約束來防止重複的行被插入,Oracle將允許其他4個線程阻塞,直到第一個線程提交,允許後續線程執行更新而不是插入。當然,這會導致線程序列化,從而導致您從運行多個線程中獲得的性能提升。

+0

當我添加一個唯一的約束到我的表..它會導致錯誤,違反唯一的常量,所以我強制要壓制異常(只需趕上並繼續我的工作) – Anoop