【问题标题】:Concurrency Issue (race condition)并发问题(竞争条件)
【发布时间】:2013-12-31 03:32:43
【问题描述】:

我什至不知道如何为这个问题命名

我有以下方法可以正常工作,但这里存在竞争条件,问题如下:

MSISDN 表中的 mobile_number 存在唯一约束。

如果提交了包含相同手机号码的多个(两个或更多)上传,并且它不存在于 MSISDN 表中,并且上传工作人员在同一时间提取了提交,则以下 MERGE 将在最后一次失败一个试图承诺的人。

我的问题是如何解决上述问题?

如果失败一次,我可以选择重试或删除对 mobile_number 的唯一约束。但我正在寻找更好的解决方案。代码如下:

protected static void batchInsertIntoMSISDN(DBAccessor dba, String tablename) throws Exception {

        logger.log(Level.INFO, String.format("batch insert into MSISDN STARTED for tableName %s", tablename));

        String sql = "MERGE INTO MSISDN M\n"+
                "      USING  "+tablename +" s\n " +
                " ON (m.mobile_number = s.mobile_number) \n"+
                " WHEN NOT MATCHED \n"+
                "   THEN \n"+
                "       INSERT ( m.id, m.mobile_number,m.state,m.created_date,m.state_updated_date,m.carrier_id ) \n"+
                "       VALUES (MSISDN_ID_SEQ.NEXTVAL,s.mobile_number,'ACTIVE',SYSDATE,SYSDATE,s.carrier_id) where s.mobile_number is not null \n";

        Connection connection = dba.getConnection();
        PreparedStatement stmt = connection.prepareStatement(sql);
        try {
            logger.info("SQL :: "+sql);
            int resultCount = stmt. executeUpdate();

            logger.log(Level.INFO, String.format("Merge into MSISDN SUCCEEDED (%d rows) for tableName %s", resultCount, tablename));
        }
        catch (Exception ex) {
            logger.log(Level.SEVERE, String.format("Merge into MSISDN FAILED for tableName %s", tablename), ex);
            throw ex;
        }
        finally {
            if (stmt != null){
                stmt.close();
            }
        }
    }

在此先感谢

【问题讨论】:

  • 隔离级别是多少?阅读提交?为什么尝试插入已经插入的行或进入死锁状态或表被锁定失败?
  • 它正在抛出 java.sql.SQLIntegrityConstraintViolationException: ORA-00001: 唯一约束。这就是它不知道 mobile_number 已经存在的事情,因为通常在他们尝试退出方法时会发生提交

标签: java sql oracle merge prepared-statement


【解决方案1】:

解决问题的最佳方法是使用如下代码:

String sql = "MERGE INTO MSISDN M\n"+
            "      USING  (SELECT mobile_number, carrier_id FROM "+ tablename +" GROUP BY mobile_number, carrier_id) s\n " +
            " ON (m.mobile_number = s.mobile_number) \n"+
            " WHEN NOT MATCHED \n"+
            "   THEN \n"+
            "       INSERT ( m.id, m.mobile_number,m.state,m.created_date,m.state_updated_date,m.carrier_id ) \n"+
            "       VALUES (MSISDN_ID_SEQ.NEXTVAL,s.mobile_number,'ACTIVE',SYSDATE,SYSDATE,s.carrier_id) where s.mobile_number is not null \n";

我不知道运营商 ID 是如何分配的,但如果您始终使用 mobile_number 和运营商 ID 的一种组合,那么您不会遇到重复此代码的问题。

如果可以接收 mobile_number 和 carrier_id 的不同组合,那么您必须制定您的应用程序规则,我的意思是 ¿您要保存哪个 Carrier ID? ¿为什么?,¿什么规则将管理这个决定?

这可以指导你决定你的代码。

【讨论】:

  • 感谢 Omar 99% 的情况下,运营商 ID 都是相同的,并且将使用默认运营商 ID
猜你喜欢
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
相关资源
最近更新 更多