隔离级别不保证 ORACLE Sql 上的事务存在

Posted

技术标签:

【中文标题】隔离级别不保证 ORACLE Sql 上的事务存在【英文标题】:Isolation level does not guarantee transaction existence on ORACLE Sql 【发布时间】:2022-01-08 17:42:18 【问题描述】:

我有 2 个表:Customers 和 customers_external。他们都使用“NAME”和“PIN”保存数据。 当我的逻辑是,将带有 PIN 参数的 get 请求发送到客户表。

我的业务逻辑描述如下: 案例 1:请求 1 发送 getNameByPin(AAA) 并在“客户”上找到,它返回我的姓名(罗伯特)。还没有问题。一切正常。

案例 2:请求 2 发送 getNameByPin(BBB) 并在“客户”上找不到,然后它创建原始数据,将 PIN 设置为“BBB”,将名称设置为 NULL,并创建另一个请求 getNameByPinFromExternal(BBB) 到“客户外部'。如果找到,它会更新“客户”表,设置从外部表中获得的名称(杰克)。还没有问题。一切正常。 案例 3:如果有人在我们已经向客户外部发送 pin=BBB 的请求并且尚未返回数据的时候发送 getNameByPin(BBB) - 那么我们会显示错误(系统忙,请稍后再试)。如何检查:当请求到来时,它检查客户表上的原始存在。如果存在 pin = BBB 的原始数据,它会检查名称是否为 Null。如果名称为空(所以其他人现在正在从customers_external 进行检查),我们向他显示错误“系统忙,请重试)。通过这种方式,我们保证对external_customers 的请求只能为一次一个 PIN。还没有问题。一切正常。

案例 4 - 问题:请求 3,4,5,n 在同一时刻,彼此无关,将 getNameByPin(CCC) 发送到客户表。由于他们同时发送,如果他们检查客户表中是否存在 PIN=CCC 的原始数据。他们都没有在表客户中找到这个原始数据,所有这些请求都使用 PIN=CCC、Name=NULL 创建原始数据。这些请求被转发给 external_customers。 我检查了 ISOLATION.LEVEL = SERIALIZAB 并阅读已提交。数据库是甲骨文。我在图像上描述了整个过程 HERE

【问题讨论】:

你想要发生什么?我的猜测是,您希望在 customers 表中的 pin 列上具有唯一约束,以便请求 4 和 5 阻塞等待事务 3 提交(或回滚)customers 上的插入。 唯一约束应该导致除第一个事务之外的任何事务失败(可能是请求 3、4、5 等中的任何一个 - 取决于哪个处理得更快),因此您的请求应该捕获结果异常并再次检查。您可能还想研究更新场景的乐观锁定,即记录已经存在的地方。 【参考方案1】:

您可以考虑使用CREATE JAVA SOURCEgetPinByNameExternal java 函数编译为 PL/SQL 函数,然后将整个逻辑移动到数据库上的一个过程中,例如:

CREATE PROCEDURE get_name_by_pin(
  v_pin  IN  customers.pin%TYPE,
  v_name OUT customers.name%TYPE
)
IS
BEGIN
  SELECT name
  INTO   v_name
  FROM   customers
  WHERE  pin = v_pin;

  IF v_name IS NULL THEN
    RAISE_APPLICATION_ERROR( -20000, 'System is busy');
  END;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    INSERT INTO customers (pin, name) VALUES (v_pin, NULL);

    UPDATE customers
    SET   name = get_pin_by_name_from_external(v_pin)
    WHERE pin  = v_pin
    RETURNING name INTO v_name;

    -- Or just
    -- INSERT INTO customers (pin, name)
    -- VALUES (v_pin, get_pin_by_name_from_external(v_pin))
    -- RETURNING name INTO v_name;
END;
/

(其中pin 是唯一/主键列)。


您可以考虑在单个事务中使用 Java 中的类似功能,但您会在 Java 和 Oracle 之间产生额外的通信开销,因此完全在数据库上执行此操作可能更有效。

【讨论】:

以上是关于隔离级别不保证 ORACLE Sql 上的事务存在的主要内容,如果未能解决你的问题,请参考以下文章

mysql,oracle,sql server中的默认事务隔离级别查看,更改

MySQL的默认事务隔离级别是?

MySQL高级篇——事务的隔离级别与简单应用

MySQL高级篇——事务的隔离级别与简单应用

MySQL 事务的默认隔离级别是啥?可以解决幻读问题么?

SQL SERVER的锁机制——概述(锁与事务隔离级别)