Transaction Basic
Một transaction là 1 tập các câu lệnh thực thi tới CSDL, các câu lệnh được thực thi 1 cách tuần tự, nếu có bất kỳ lệnh nào bị lỗi, transaction sẽ dừng lại và roll back DB tất cả các câu lệnh đã thực thi, trả lại DB như lúc start transaction.
Transaction có 4 tính chất (ACID):
- Atomicity (Tính nguyên tử): 1 transaction phải như 1 đơn vị công việc, hoặc tất cả các thay đổi dữ liệu được thực thi, hoặc không thay đổi nào được thực hiện.
- Consistency (Tính nhất quán): Khi đã hoàn thành, 1 transaction phải để tất cả dữ liệu ở trạng thái nhất quán. Trong CSDL quan hệ, rất cả các rules phải được áp dụng cho các thay đổi của transaction tạo ra để giữ cho tất cả dữ liệu toàn vẹn. Tất cả cấu trúc dữ liệu, như indexs phải đúng khi kết thúc transaction.
- Isolation (Tính độc lập): Các sự thay đổi của các transactions khác nhau phải độc lập với nhau. 1 transaction chỉ được lấy dữ liệu ở trạng thái trước hoặc sau khi dữ liệu này bị 1 transaction khác thay đổi chứ không phải ở 1 trạng thái trung gian.
- Durability (Tính bền vững): Sau khi 1 transaction thực hiện thành công, các thay đổi của nó sẽ trở thành chính thức và bền vững, khộng bị roll back.
Locking và Row Versioning
- Locking và Row Versioning là các cơ chế được SQL sử dụng để đảm bảo tính toàn vẹn của các transaction và duy trì tính nhất quán của CSDL khi nhiều người cùng lúc thao tác trên dữ liệu.
- Locking: Mỗi transaction yêu cầu các loại khóa khác nhau trên resource như: row lock, page lock hay table lock, ... tùy theo transaction phụ thuộc vào gì. Lock ngăn các transaction khác không cho chúng thay đổi dữ liệu. Các transaction sẽ giải phóng Lock khi nó không còn phụ thuộc vào các tài nguyên bị Lock nữa. Khi này các transaction khác mới có thể truy cập những tài nguyên này,
- Row versioning: Khi 1 tài nguyên bị Lock, các transaction khác sẽ không thể thao tác được với tài nguyên này mà phải đợi đến khi transaction đang giữ tài nguyên giải phóng Lock mới có thể truy cập. Điều này sẽ dẫn đến việc các transaction phải đợi nhau quá lâu dẫn tới giảm đáng kể hiệu năng của hệ thống. Row versioning lưu trữ các versions của tài nguyên đang bị lock, các transaction khác nếu chỉ yêu cầu đọc các tài nguyên này sẽ được trả về version phù hợp mà không cần phải đợi đến khi tài nguyên được giải phóng Lock. Điều này sẽ giúp giảm đáng kể khả năng nhiều transaction phải đợi nhau để sử dụng tài nguyên,
Các loại Lock
Có 3 loại Lock chính đó là: Share lock, exclusive lock và update lock
- Share Lock: hay còn gọi là read-only lock (khóa chỉ đọc) là lock mà một transaction chiếm hữu khi muốn đọc 1 dữ liệu. Giao dịch giữ Share lock được phép đọc dữ liệu, nhưng không được phép ghi. Nhiều transaction có thể đồng thời giữ Share lock trên cùng 1 đơn vị dữ liệu
- Exclusive Lock: hay còn gọi là write lock là lock mà một transaction chiếm hữu khi muốn đọc + ghi dữ liệu. Tại 1 thời điểm chỉ có tối đa 1 transaction được quyền giữ Exclusive lock trên 1 đơn dữ liệu.Không thể thiết lập Share lock trên đơn vị dữ liệu đang có Exclusive lock.
- Update lock: Khóa dự định ghi. Update lock sử dụng khi đọc dữ liệu với dự định ghi trở lại trên dữ liệu này. Update lock là chế độ khoá trung gian giữa Share lock và Exclusive lock. Khi thực hiện thao tác ghi lên dữ liệu thì bắt buộc Update lock phải tự động chuyển thành Exclusive lock. Transaction giữ Update lock được phép GHI + ĐỌC dữ liệu. Tại 1 thời điểm chỉ có tối đa 1 transaction được quyền giữ Update lock trên 1 đơn dữ liệu. Có thể thiết lập Share lock trên đơn vị dữ liệu đang có Update lock
Các kiểu quản lý truy cập đồng thời
Có 2 loại thiết lập quản lý truy cập đồng thời
- Pessimistic concurrency control: Với thiết lập này, khi 1 transaction thực hiện lock 1 tài nguyên để thao tác, các transaction khác sẽ không thể truy cập được tài nguyên này mà phải chờ tới khi khóa được giải phóng. Nó được gọi là pessimistic control bởi nó được sử dụng chủ yếu cho các trường hợp môi trường có sự tranh chấp dữ liệu cao, trong đó việc bảo vệ dữ liệu bằng Lock hiệu quả hơn việc roll back dữ liệu nếu xảy ra xung đột đồng thời
- Optimistic concurrency control: Ở thiết lập này, transaction không được lock dữ liệu khi đọc. Khi 1 transaction update dữ liệu, hệ thống sẽ kiểm tra xem có transaction nào khác thay đổi dữ liệu này cùng lúc hay không, nếu có sẽ raise error và roll back dữ liệu. Thiết lập này sử dụng chủ yếu trong môi trường có sự tranh chấp dữ liệu thấp.
Các kỹ năng khoá dữ liệu
Database lock thực tế có thể được thực hiện ở nhiều cấp độ khác nhau - còn được biết đến như là lock granularity - bên trong cơ sở dữ liệu.
Đây là danh sách của các cấp độ lock và kiểu dữ liệu hỗ trợ.
Khóa cấp cơ sở dữ liệu (database level locking)
Với khóa cấp độ cơ sở dữ liệu, toàn bộ cơ sở dữ liệu bị khóa - điều đó có nghĩa là chỉ một database session có thể áp dụng bất kỳ cập nhật nào cho cơ sở dữ liệu. Loại khóa này không thường được sử dụng, vì rõ ràng nó ngăn tất cả người dùng ngoại trừ một người cập nhật bất cứ điều gì trong cơ sở dữ liệu. Tuy nhiên, khóa này có thể hữu ích khi cần một số cập nhật hỗ trợ chính - như nâng cấp cơ sở dữ liệu lên phiên bản mới của phần mềm. Cơ sở dữ liệu Oracle thực sự có một chế độ độc quyền, được sử dụng để cho phép chỉ một session database user - về cơ bản, đây là một khóa cơ sở dữ liệu.
Khoá cấp tệp tin (file level locking)
Với khoá cấp tệp tin, toàn bộ một database file bị lock. Vậy chính xác thì một file trong database là gì? Nó có thể một khoảng rộng dữ liệu - bên trong một file có thể là cả một bảng, một phần của bảng, hoặc nhiều phần của các bảng khác nhau. Vì có sự đa dạng trong dữ liệu được lưu trong một file, cấp độ khoá này không được nhiều người sử dụng.
Khóa cấp bảng (table level locking)
Khóa cấp bảng khá đơn giản - có nghĩa là toàn bộ bảng bị khóa toàn bộ. Cấp khóa này có ích khi thực hiện thay đổi ảnh hưởng đến toàn bộ bảng, như cập nhật tất cả các hàng trong bảng hoặc điều chỉnh bảng Trong Oracle, đây được gọi là khóa DDL, bởi vì nó được sử dụng với các câu lệnh DDL (Ngôn ngữ định nghĩa dữ liệu) như CREATE, ALTER và DROP - về cơ bản là các câu lệnh sửa đổi toàn bộ bảng bằng cách này hay cách khác.
Khóa cấp độ trang hoặc khối (page or block level locking)
Khoá cấp độ trang hoặc khối xảy ra khi một khối hoặc trang là một phần của tệp cơ sở dữ liệu bị khóa. Để đọc thêm về các trang và khối nếu bạn chưa quen với chúng, hãy truy cập vào đây: Pages versus blocks.
Bởi vì dữ liệu có thể được lưu trữ trong các khối / trang có thể rộng và đa dạng, khóa trang / khối ít được ưa chuộng trong cơ sở dữ liệu ngày nay.
Khóa cấp độ cột (column level locking)
Khóa cấp độ cột có nghĩa là một số cột trong một hàng nhất định trong một bảng đã cho bị khóa. Hình thức khóa này không được sử dụng phổ biến vì nó đòi hỏi nhiều tài nguyên để kích hoạt và giải phóng các khóa ở cấp độ này. Ngoài ra, có rất ít hỗ trợ khóa cấp cột trong hầu hết các nhà cung cấp cơ sở dữ liệu.
Khóa cấp độ hàng (row level locking)
Khóa cấp hàng áp dụng cho một hàng trong bảng. Đây cũng là cấp khóa phổ biến nhất và thực tế tất cả các nhà cung cấp cơ sở dữ liệu chính đều hỗ trợ khóa cấp hàng.
Optimistic Locking là gì?
Optimistic lock nhiều người dùng có thể cùng truy cập đến đối tượng và đọc dữ liệu từ nó.
Nhưng khi có 2 hay nhiều người dùng muốn update đối tượng đó thì chỉ người truy cập đầu tiên mới có thể update, những người dùng khác sẽ bị bắn ra exception
Trường hợp locking cụ thể.
Ví dụ: Có 2 người dùng đang load một dòng dữ liệu sản phẩm lên để chỉnh sửa số lượng, giả sử số lượng ban đầu là 10
- Người dùng thứ 1, update số lượng 10 => 5.
- Người dùng thứ 2, update số lượng 10 => 6.
Vậy theo như bình thường lưu thì 2 người sẽ update đè cho vào một dòng dữ liệu gây ra hiện tượng conflicts data.
Cơ chế Optimistic locking trong trường hợp này, chỉ cho phép người dùng nào update đầu tiên sẽ update thành công, người dùng sau update sẽ không thành công.
Mở rộng: RowVersion là gì?
Có nhiều phương pháp optimistic, trong đó sử dụng row-version là phương pháp khá hay. SQLServer có cung cấp 1 kiểu dữ liệu là Timestamp.
Mỗi table trong SQLServer chỉ có thể có tối đa 1 trường TimeStamp. Mỗi khi 1 row trong DB được insert hoặc update, Timestamp của DB sẽ thay đổi (tăng lên 1 đơn vị) và cập nhật vào trường Timestamp của row đó. Để lấy giá trị Timestamp của DB, sử dụng câu query:
SELECT @@DBTS
Chú ý
Giá trị @@DBTS không phải giá trị current datetime như function Current_Timestamp() trả về
Việc sử dụng trường timestamp để quản lý optimistic concurrency là rất có lợi.
Ví dụ, câu lệnh update sau sẽ đảm bảo tính tương tranh:
UPDATE PRODUCT_ROWVERSION SET [NAME]=‘Spiderum’
where id=‘1’ AND version=0x00000000000007D3
với giá trị 0x00000000000007D3 là giá trị timestamp của row. Như vậy, process nào update sau sẽ không thể update được và đảm bảo tính tương tranh.
Do Timestamp data type có thể thay đổi mục đích sử dụng trong tương lai nên khi viết lệnh DDL, hãy cố gắng thay thế kiểu Timestamp bằng RowVersion datatype.
(TIMESTAMP is deprecated and will be removed in a future version of SQL Server)
RowVersion synonyms là 1 trong các Data Type Synonyms được thêm vào SQL Server 2005 nhằm mục đích tương thích với SQL-92.
Sử dụng RowLock
with(rowlock) là một chỉ dẫn khóa với phạm row scope, tránh trường hợp khóa block hoặc table scope.
XLOCK
Specifies that exclusive locks are to be taken and held until the transaction completes. If specified with ROWLOCK, PAGLOCK, or TABLOCK, the exclusive locks apply to the appropriate level of granularity.
Kết hợp XLOCK và ROWLOCK sẽ block session khác đọc trên cùng một dòng.
SELECT * FROM TableA FROM Id = 1
Để tìm được Row Id, bạn cần thực hiện query với WITH(NOLOCK) để tìm ra được ID
SELECT * FROM TableA WITH (NOLOCK) FROM ColumnA = 'conditionA'
Tham khảo
https://viblo.asia/p/dao-sau-ve-sql-transactions-E375z4jWZGW
https://viblo.asia/p/database-locking-naQZRDGd5vx
https://hainh2k3.com/tim-hieu-ve-with-nolock-trong-ms-sql-server/

https://lkdev.wordpress.com/2016/11/15/series-ve-entity-framework-phan-17-concurrency-trong-entity-framework/
Trả lờiXóa