隔离级别不保证 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 SOURCE
将getPinByNameExternal
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 上的事务存在的主要内容,如果未能解决你的问题,请参考以下文章