在 Oracle 中发出 COMMIT 之前 INSERT 是如何工作的

发布于 2025-01-02 22:53:36 字数 1278 浏览 3 评论 0原文

我的问题是 oracle 在发出 COMMIT 之前如何处理 INSERT 事务。

当我执行 INSERT 事务时,oracle 是否会等到我在该过程中插入所有记录,然后当我发出 COMMIT 语句时,记录是否会按此事务的顺序保存?

在下面的代码中,首先插入的是行数(元数据),然后游标循环并开始插入实际数据。

是否有可能,在一个事务中,当我调用此过程时,首先插入我的元数据记录,然后插入一些其他数据(与此事务无关),然后插入我的其余数据。因此,循环中的第一条记录和其余记录不会插入到序列中。

-- This code belongs to proecdure when ever a user clicks on insert 
-- button from the front end form

DECLARE

    rowcnt NUMBER;

    CURSOR c_get_employ IS
    SELECT EMP.EMPLOYER_ID, EMP.EMPLOYER_NAME, EMP.EMPLOYER_LOCATION
          FROM EMP
            WHERE EMP.EMPLOYER_COUNTRY = 'USA'
    ORDER BY EMP.EMPLOYER_ID;

BEGIN

    Select count(*) 
    INTO rowcnt 
    FROM EMP
    WHERE EMP.EMPLOYER_COUNTRY = 'USA'
    ORDER BY EMP.EMPLOYER_ID;

    -- I want to insert the 'number of employee records' that will be inserted (metadata)

    INSERT INTO EMP_OUTPUT 
        (EMPID, EMPNAME, EMPLOC, ECOUNT)
    VALUES
        (,,,rowcnt);

    -- Then loop through the cursor and start inserting the data
    FOR c_post_employ IN c_get_employ LOOP

        INSERT INTO EMP_OUTPUT 
            (EMPID, EMPNAME, EMPLOC)
        VALUES
            (c_post_employ.EMPLOYER_ID,c_post_employ.EMPLOYER_NAME,c_post_employ.EMPLOYER_LOCATION);

    END LOOP;

    COMMIT;

END;

My question is how oracle treats an INSERT transaction before issuing a COMMIT.

While I am doing an INSERT transaction, will oracle wait until I have inserted all my records within that procedure and then when I issue a COMMIT statement will the records be saved in a sequence for this transaction?

In the following code, the first insert that is made is the number of rows (metadata) and then the cursor loops and starts inserting the actual data.

Is there a possibility, in one transaction when I call this procedure, first my metadata record is inserted and then some other data (not related to this transaction) be inserted and then rest of my data. So that, the first record and the rest of the records from the loop are not inserted in a Sequence.

-- This code belongs to proecdure when ever a user clicks on insert 
-- button from the front end form

DECLARE

    rowcnt NUMBER;

    CURSOR c_get_employ IS
    SELECT EMP.EMPLOYER_ID, EMP.EMPLOYER_NAME, EMP.EMPLOYER_LOCATION
          FROM EMP
            WHERE EMP.EMPLOYER_COUNTRY = 'USA'
    ORDER BY EMP.EMPLOYER_ID;

BEGIN

    Select count(*) 
    INTO rowcnt 
    FROM EMP
    WHERE EMP.EMPLOYER_COUNTRY = 'USA'
    ORDER BY EMP.EMPLOYER_ID;

    -- I want to insert the 'number of employee records' that will be inserted (metadata)

    INSERT INTO EMP_OUTPUT 
        (EMPID, EMPNAME, EMPLOC, ECOUNT)
    VALUES
        (,,,rowcnt);

    -- Then loop through the cursor and start inserting the data
    FOR c_post_employ IN c_get_employ LOOP

        INSERT INTO EMP_OUTPUT 
            (EMPID, EMPNAME, EMPLOC)
        VALUES
            (c_post_employ.EMPLOYER_ID,c_post_employ.EMPLOYER_NAME,c_post_employ.EMPLOYER_LOCATION);

    END LOOP;

    COMMIT;

END;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

却一份温柔 2025-01-09 22:53:36

另一个事务可以与您的事务同时执行插入,但您的事务不会看到它们:

  • 直到另一个事务提交(如果您的事务使用 READ COMMITTED 隔离),或者
  • 永远(当使用 SERIALIZABLE 隔离时) - 您需要启动另一笔交易去看他们。

这是否会产生正确的行为,由您决定。


请注意 SELECT COUNT(*) ... - 它可能不会返回您期望的结果。考虑以下场景:

  • EMP 表最初是空的。
  • 事务 A 启动并在 EMP 中插入一行,但不提交。
  • 事务 B 启动并在 EMP 中插入一行,但不提交。
  • 事务 A 执行 SELECT COUNT(*) FROM EMP 并获取 1(因为它看到自己新插入的行,但没有看到 B 新插入的行,因为 B 尚未提交)。
  • 事务B执行SELECT COUNT(*) FROM EMP并且也得到1(出于相同的原因但相反)。
  • 事务 A 将 1 插入 EMP_OUTPUT 并提交。
  • 事务 B 将 1 插入 EMP_OUTPUT 并提交(假设没有密钥违规)。

因此,尽管表实际上有 2 行,但还是插入了 1 行!

不幸的是,即使是 Oracle 的 SERIALIZABLE 隔离也无法避免这种异常情况。如果锁定,几乎是保证“正确”结果的唯一方法整个表,因此不会发生并发插入(或删除)。

Another transaction can perform inserts concurrently to your transaction, but your transaction won't see them:

  • until the other transaction commits (if your transaction is using READ COMMITTED isolation), or
  • ever (when using SERIALIZABLE isolation) - you'll need to start another transaction to see them.

Whether this will yield a correct behavior, is for you to decide.


Just be careful about SELECT COUNT(*) ... - it may not return what you expect. Consider the following scenario:

  • The EMP table is initially empty.
  • Transaction A starts and inserts a row in EMP, but does not commit.
  • Transaction B starts and inserts a row in EMP, but does not commit.
  • Transaction A executes SELECT COUNT(*) FROM EMP and gets 1 (because it sees its own newly inserted row, but does not see B's newly inserted row since B did not commit yet).
  • Transaction B executes SELECT COUNT(*) FROM EMP and also gets 1 (for the same reason but in reverse).
  • Transaction A inserts 1 into EMP_OUTPUT and commits.
  • Transaction B inserts 1 into EMP_OUTPUT and commits (assuming there is no key violation).

So, 1 is inserted despite table actually having 2 rows!

Unfortunately not even Oracle's SERIALIZABLE isolation will save you from this kind of anomaly. Pretty much the only way to guarantee the "correct" result if to lock the entire table, so no concurrent inserts (or deletes) can occur.

数理化全能战士 2025-01-09 22:53:36

如果可能,请使用单个 SQL 语句。它将具有语句级读取一致性,并且速度会快得多。

insert into emp_output(empid, empname, emploc, ecount)
with employees as
(
    select employer_id, employee_name, employer_location
    from emp
    where employer_country = 'USA'
    order by employer_id    
)
select null, null, null, count(*) from employees
union all
select employer_id, employee_name, employer_location, null from employees;

Use a single SQL statement if possible. It will have statement-level read consistency, and will be much faster.

insert into emp_output(empid, empname, emploc, ecount)
with employees as
(
    select employer_id, employee_name, employer_location
    from emp
    where employer_country = 'USA'
    order by employer_id    
)
select null, null, null, count(*) from employees
union all
select employer_id, employee_name, employer_location, null from employees;
一曲爱恨情仇 2025-01-09 22:53:36

您要在 Google 上搜索的术语是“读取一致性”:

http: //docs.oracle.com/cd/B12037_01/server.101/b10743/consist.htm

底线:

  • As你知道,如果你回滚,就好像插入“从未发生过”

  • 但是,其他东西可以(并且可能确实发生过)同时“发生”。

The term you want to google for is "read consistency":

http://docs.oracle.com/cd/B12037_01/server.101/b10743/consist.htm

Bottom line:

  • As you know, if you rollback, it's as though the inserts "never happened"

  • However, other stuff can (and probably did) "happen" in the meantime.

九八野马 2025-01-09 22:53:36

您需要在可序列化隔离级别中运行:

http://docs.oracle.com/cd/E11882_01/server.112/e16508/consist.htm#BABCJIDI

“可序列化事务仅看到事务时提交的那些更改开始,加上事务本身通过 INSERT、UPDATE 和 DELETE 语句进行的更改不会经历不可重复的读取或操作。幻影。”

You need to run in the Serializable Isolation Level:

http://docs.oracle.com/cd/E11882_01/server.112/e16508/consist.htm#BABCJIDI

"Serializable transactions see only those changes that were committed at the time the transaction began, plus those changes made by the transaction itself through INSERT, UPDATE, and DELETE statements. Serializable transactions do not experience nonrepeatable reads or phantoms."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文