Chuyển đến nội dung chính

Sử dụng RowVersion giải quyết cho giải pháp Optimistic Locking

Bài viết này là tổng hợp từ các nguồn từ ViBlo, lập trình VB,...  Và 1 chút kinh nghiệm của mình về việc xử lý khóa dữ liệu
Ở bài viết hôm nay mình sẽ nói về cơ chế Locking RDBMS trong database sqlserver nhằm ngăn chặn nhiều transaction từ người dùng khác nhau gây ra data conflicts.
Có 2 chiến lược lock là: Optimistic LockingPesimistic Locking
Trong bài viết này mình sẽ sử dụng RowVersion trong Sqlserver để giải quyết cho chiến lược Optimistic Locking.
Trước tiên, mình sẽ tìm hiểu về Transaction Basic, Lock type, Kỹ thuật lock.

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.

Để tránh trường hợp get data mà scan cả table, bạn sử dụng Where với column đã được đánh Index
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://laptrinhvb.net/bai-viet/co-so-du-lieu/--SQLSERVER---Su-dung-RowVersion-giai-quyet-cho-giai-phap-Optimistic-Locking-/9e8026e250e6908f.html

https://hainh2k3.com/tim-hieu-ve-with-nolock-trong-ms-sql-server/

Nhận xét

  1. https://lkdev.wordpress.com/2016/11/15/series-ve-entity-framework-phan-17-concurrency-trong-entity-framework/

    Trả lờiXóa

Đăng nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.