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条

4

1 回答 1

0

如果没有约束(即 中emp_id列的主键或唯一键约束emp_bonus),则没有什么可以阻止数据库允许每个线程插入 5 行。emp_bonus由于每个数据库会话都看不到其他会话所做的未提交更改,因此每个线程都会看到线程正在查找的行中没有行emp_id(我假设employeeObj.getEmp_id()返回相同的 5emp_id每个线程中的值),因此每个线程将插入所有 5 行,如果有 5 个线程,则总共有 25 行。如果您有一个唯一约束来防止插入重复的行,Oracle 将允许其他 4 个线程阻塞,直到第一个线程提交允许后续线程执行更新而不是插入。当然,这将导致线程被序列化,从而破坏了从运行多个线程中获得的任何性能提升。

于 2012-10-24T12:02:22.023 回答