当前位置: 首页 > 知识库问答 >
问题:

多线程中的准备语句

马沛
2023-03-14

我在准备好的语句中使用了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,thread count=5,执行后我将得到25条记录,而不是5条

共有1个答案

梁研
2023-03-14

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

 类似资料:
  • 我想知道是否可以使用一个准备好的语句插入多行。下面是我通常如何在DB中插入一行的示例: 我要插入的值将来自一个数组,例如:$values[0]['val1'];$values[0]["val2“];$values[0]['val3'];$values[1]['val1'];$values[2]['val2']; 等等。 这段代码可能需要一次插入几百行,我想过创建一个循环来创建数百个参数,然后为每一

  • 我正在使用我生成的一个准备好的语句,但在Java抛出的语句上出现了语法错误。然而,当我将PS的toString复制并粘贴到数据库的phpmyadmin中时,它的执行完美无缺。有什么想法会出错吗,我很难理解? 编辑:更改为PS.ExecuteUpdate(查询);还是不起作用。

  • 似乎在主线程中,我只需要编写一个扩展Handler并覆盖其handleMessage方法的类。然后我可以只创建Handler对象而无需准备looper。 在主线程中,以下代码起作用: 但是在worker线程中你确实需要先准备looper然后才能创建Handler对象,否则threadLocal.get()就不能为当前worker线程获取looper。我的问题是一定有地方为主线准备弯针,但我就是找不

  • 问题内容: 以下是我使用Prepared Statement 插入到Oracle数据库中的代码。 我目前的工作方式很好吗?还是可以使用某些方法来进一步改进? 我正在使用的更新的代码:- 问题答案: 您可以考虑一次性使用和执行语句背面。另外,正如@pst在您的问题中所述,请考虑使用。 您将执行以下操作: 这个想法是为批处理更新设置一个限制,并且仅在达到特定限制时才执行数据库更新。这样,您就可以将数据

  • 问题内容: 今天有人告诉我,我确实应该在应用程序中使用PDO和准备好的语句。在我了解好处的同时,我也在努力了解如何将其实现到我的工作流程中。除了它使代码更简洁外,我是否应该有一个特定的数据库类来容纳所有准备好的语句,还是应该在每次运行查询时都创建一个?我发现很难理解何时应使用标准PDO查询以及何时应使用准备好的语句。任何示例,技巧或教程链接将不胜感激。 问题答案: pdo :: prepare()