code

단일 명세서에 대한 트랜잭션은 무엇을합니까?

codestyles 2020. 11. 25. 07:58
반응형

단일 명세서에 대한 트랜잭션은 무엇을합니까?


거래가 한 쌍의 업데이트를 조정하는 데 어떻게 유용 할 수 있는지 이해합니다. 내가 이해하지 못하는 것은 트랜잭션에서 단일 진술을 래핑하는 것인데, 이는 내가 본 것의 90 %입니다. 실제로 실제 코드에서 각각 자체 트랜잭션에 래핑 된 일련의 논리적으로 관련된 트랜잭션을 찾는 것이 내 경험상 더 일반적이지만 전체가 트랜잭션에 래핑되지는 않습니다.

MS-SQL에서 트랜잭션에서 단일 선택, 단일 업데이트, 단일 삽입 또는 단일 삭제를 래핑하면 어떤 이점이 있습니까?

나는 이것이 미신적 인 프로그래밍이라고 생각한다.


아무것도하지 않습니다. 모든 개별 SQL 문 (로그가없는 대량 삽입 또는 테이블 자르기와 같은 드문 예외 포함)은 명시 적으로 말하든 말든 자동으로 "In a Transaction"입니다 (수백만 개의 행을 삽입, 업데이트 또는 삭제하더라도). .

편집 : 아래 @Phillip의 주석을 기반으로 ... 현재 버전의 SQL Server에서 대량 삽입 및 Truncate Table은 다른 작업만큼 많이는 아니지만 일부 데이터를 트랜잭션 로그에 기록합니다. 트랜잭션 관점에서 중요한 차이점은 이러한 다른 유형의 작업에서 수정되는 데이터베이스 테이블의 데이터가 롤백 할 수있는 상태의 로그에 없다는 것입니다.

이 모든 것은 데이터베이스의 데이터에 대한 명령문 변경 사항이 트랜잭션 로그에 기록되어 작업이 실패 할 경우 취소 할 수 있음을 의미합니다.

"Begin Transaction", "Commit Transaction"및 "RollBack Transaction"명령이 제공하는 유일한 기능은 두 개 이상의 개별 SQL 문을 동일한 트랜잭션에 넣을 수 있도록하는 것입니다.

편집 : (마크 주석을 강화하기 위해 ...) 예, 이것은 "미신적 인"프로그래밍에 기인하거나 데이터베이스 트랜잭션의 본질에 대한 근본적인 오해의 표시 일 수 있습니다. 좀 더 자선적인 해석은 부적절하고 일관성을 과도하게 적용한 결과이며 에머슨 완곡 어법의 또 다른 예는 다음과 같다는 것입니다.

어리석은 일관성은
작은 정치가와 철학자와 신이 숭배하는 작은 마음의 홉 고블린입니다.


Charles Bretana가 말했듯이 "아무것도하지 않습니다"-이미 수행 된 것 외에는 아무것도하지 않습니다.

관계형 데이터베이스의 "ACID"요구 사항을 들어 본 적이 있습니까? "A"는 Atomic을 의미합니다. 즉, 문이 전체적으로 작동하거나 작동하지 않습니다. 즉, 문이 수행되는 동안 해당 쿼리의 영향을받는 데이터에 대해 다른 쿼리를 수행 할 수 없습니다 . BEGIN TRANSACTION / COMMIT는이 잠금 기능을 여러 명령문에 의해 수행되는 작업으로 "확장"하지만 단일 명령문에는 아무것도 추가하지 않습니다.

그러나 데이터베이스 트랜잭션 로그는 데이터베이스가 수정 (삽입, 업데이트, 삭제) 될 때 항상 기록됩니다. 이것은 옵션이 아니며 사람들을 짜증나게하는 경향이있는 사실입니다. 예, 대량 삽입 및 복구 모드에는 이상한 점이 있지만 여전히 기록됩니다.

여기에서도 격리 수준의 이름을 삭제하겠습니다. 이것으로 소란을 피우면 개별 명령에 영향을 주지만 그렇게해도 선언 된 트랜잭션 래핑 쿼리가 "독립 실행 형"쿼리와 다르게 수행되지는 않습니다. (다중 문으로 선언 된 트랜잭션으로 인해 매우 강력하고 위험 할 수 있습니다.) 또한 "nolock"은 삽입 / 업데이트 / 삭제에 적용 되지 않습니다 . 이러한 작업에는 항상 잠금이 필요합니다.


나에게 트랜잭션에서 단일 문을 래핑한다는 것은 일회성 수동 UPDATE 문을 실행할 때 WHERE 절을 잊어 버린 경우 롤백 할 수 있음을 의미합니다. 그것은 저를 몇 번 구했습니다.

예 :

--------------------------------------------------------------
CREATE TABLE T1(CPK INT IDENTITY(1,1) NOT NULL, Col1 int, Col2 char(3));
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');

SELECT * FROM T1


--------------------------------------------------------------
/* MISTAKE SCENARIO     (run each row individually) */
--------------------------------------------------------------
BEGIN TRAN YOUR_TRANS_NAME_1;   /* open a trans named YOUR_TRANS_NAME_1 */
    UPDATE T1 SET COL2 = NULL;  /* run some update statement */
    SELECT * FROM T1;       /* OOPS ... forgot the where clause */
ROLLBACK TRAN YOUR_TRANS_NAME_1;    /* since it did bad things, roll it back */
    SELECT * FROM T1;       /* tans rolled back, data restored. */



--------------------------------------------------------------
/* NO MISTAKES SCENARIO (run each row individually) */
--------------------------------------------------------------

BEGIN TRAN YOUR_TRANS_NAME_2;
    UPDATE T1 SET COL2 = 'CBA' WHERE CPK = 4;   /* run some update statement */
    SELECT * FROM T1;               /* did it correctly this time */

COMMIT TRAN YOUR_TRANS_NAME_2           /* commit (close) the trans */

--------------------------------------------------------------

DROP TABLE T1

--------------------------------------------------------------

한 가지 가능한 변명은 그 단일 문으로 인해 트리거를 통해 다른 SQL이 실행될 수 있으며, DBMS가 암시 적 트랜잭션을 사용하는 상식을 가질 것으로 기대하지만 그 안에서 문제가 발생하는 것을 방지하고 있다는 것입니다. 이미 같은 방식입니다.

제가 생각할 수있는 또 다른 점은 일부 API를 사용하면 자동 커밋을 비활성화 할 수 있으며 누군가 그렇게 할 경우를 대비하여 코드가 작성된다는 것입니다.


When you start an explicit transaction and issue a DML, the resources being locked by the statement remain locked, and the results of statement are not visible from outside the transaction until you manually commit or rollback it.

This is what you may or may not need.

For instance, you may want to show preliminary results to outer world while still keeping a lock on them.

In this case, you start another transaction which places a lock request before the first one commits, thus avoiding race condition

Implicit transactions are commited or rolled back immediatley after the DML statement completes or fails.


SQL Server has a setting which allows turning autocommit off for a session. It's even the default for some clients (see https://docs.microsoft.com/en-us/sql/t-sql/statements/set-implicit-transactions-transact-sql?view=sql-server-2017)

Depending on a framework and/or a database client you use, not putting each individual command into its own transaction might cause them to be all lumped together into a default transaction. Explicitly wrapping each of them in a transaction clearly declares the intent and actually makes sure it happens the way the programmer intended, regardless of the current autocommit setting, especially if there isn't a company-wide policy on autocommit.

If the begin tran / commit tran commands are being observed in the database (as per your comment here), it is also possible that a framework is generating them on behalf of an unsuspecting programmer. (How many developers closely inspect SQL code generated by their framework?)

I hope this is still relevant, despite the question being somewhat ancient.

참고URL : https://stackoverflow.com/questions/1171749/what-does-a-transaction-around-a-single-statement-do

반응형