12 Ekim 2020 Pazartesi

ACID - Repeatable Read Seviyesi Nedir ? - Benim Dokunduğum Satırı Kilitler Gibi Düşünülebilir

Giriş
Şeklen şöyle. Üçüncü satırda Repeatable Read görülebilir.

SQL Server için şeklen şöyle
Açıklaması şöyle
It ensures that the same select query will always return the same result, no matter how many times it is executed, even if some other concurrent transactions have committed new changes that satisfy the query.
Transaction içinde kullanılan tüm verinin her seferinde aynı değeri taşıyacak şekilde okunması garanti edilir. 
- Dirty Read problemini engeller. 
- Lost Update problemini engeller.
- Phantom Read problemini engellemez. Benim dokunmadığım satırlar kilitlenmediği için bunlar değiştirilebilir veya yeni satır eklenebilir
- Phantom satır kapsamında Write skew problemini engellemez.

Şeklen şöyle. Burada Transaction 1 başlıyor ve 2 numaralı satırı okuyor, ancak 3 numaralı satıra dokunmuyor. Transaction 2 ise 3 numaralı satırı değiştirip commit'liyor. Transaciton 2 3 numaralı satırı okusa bile eski veriyi görüyor.

Açıklaması şöyle
REPEATABLE READ isolation level guarantees that transactions see the committed view of the database snapshot taken by the first read. Unlike READ COMMITTED isolation level, data that is read at one point in the transaction is the same as data that is read at another point in the transaction.

... The concurrent transactions see the committed view of the snapshot taken within each transaction. Transaction 1 gets charlie, not chris, because Transaction 1 began before Transaction 2. To put it another way, the two concurrent transactions are performed in serial.


Note that the snapshot is taken by the table, not by the row or database. A first read to the table creates a new table snapshot. As to the above diagram, Transaction 1 creates a snapshot of the users table when issuing SELECT name FROM users WHERE id = 2. Once the transaction ends, the snapshot is deleted.


1. Lock Çeşitleri Nedir?
Açıklaması şöyle. Lock çeşitleri yanında lock'ın ne zaman bırakıldığı da önemlidir.
What are the locks in RDBMS?

Shared read lock: When a single row is read, a read lock is held. This allows another transaction from another thread to have a read lock on the same record — but no other transaction from another thread can impose a write lock to update it.

Update lock: When an update lock is held, other threads can only acquire a shared read lock — not update nor an exclusive write lock.

Exclusive write lock: An update lock is promoted to a write lock. I think this promotion is only possible when only one lock, which is this update lock (no other shared read lock), is locking this row. When a write lock holds a row, no other transaction from any other thread can hold any lock on that row.
-Shared read lock aynı anda okumayı engellemez, başkası yazamaz
-Update lock aynı anda okumayı engellemez, başkası yazamaz. Update lock, Exclusive Lock'a yükseltilebilir.
-Exclusive Lock başka herhangi bir lock'a müsaade etmez

2. Repeatable Read Gerçekleştirimi
Repeatable read gerçekleştirimi için iki tane yöntem var. Bunlar şöyle
1. With transaction 1 as Repeatable Read, other transactions can not update a row after it has been selected by transaction 

2. With transaction 1 as Repeatable Read, other transactions can update a row, but transaction 1 does not take into account those changes.
Çoğu veri tabanı 1. yöntemi seçiyor. 

1. Yöntem şu anlama gelir Kullanılan Lock - Okumayı Engellemez Ama Yazmayı Engeller
Repeatable Read "Update Lock" kullanır. Bu lock read committed seviyesinin aksine transaction bitmeden bırakılmaz. Yani bu lock çeşidi ile başkasının benim satırıma yazması engellenir.

SQLServer - 1. Yöntem
Açıklaması şöyle
With transaction 1 as REPEATABLE READ, you cannot update a row in transaction 2 after you selected it in transaction 1.
MYSQL - 2. Yöntem
Açıklaması şöyle
While many database systems will actually behave like your first version, for MySQL, version 2 is the expected behaviour, see the documentation about repeatable read:
Bu yüzden "select ... for update" kullanılıyor. Açıklaması şöyle
In MySQL, if you want to block another transaction from updating the rows in repeatable read, you need to lock them by e.g. using select ... for update. A simple select will not place a lock unless you are in serializable isolation mode.
PostgreSQL - 1. Yöntem
Repetable Read yazısına taşıdım.

Repeatable Read Kullanım Senaryosu Örnekleri
Örnek
Eğer bir mali rapor hazırlıyorsam ve kârı iki farklı yerde gösteriyorsam iki tane SUM cümlesi çalıştırırım. Eğer repeatable read kullanmazsam okuduğum veri güncellenebilir ve iki farklı sonuç elde ederim.


3. Lost Update Çözümü Nasıldır
Örnek
Lost Update için en açıklayıcı senaryo aşağıdaki gibi. İki thread'in aynı anda banka hesabındaki paradan 100 TL çekmeye çalıştığını düşünelim.
  •     funds == 100; amount == 100
  •     thread A enters withdraw / transaction A starts
  •     thread A executes isEnoughFunds which evaluates to true
  •     thread B enters withdraw / transaction B starts
  •     thread B executes isEnoughFunds which evaluates to true
  •     thread A executes decreaseFunds / thread A locks db record
  •     thread B waits for thread A to commit transaction and release write lock
  •     thread A exits withdraw / transaction A commits
  •     thread B executes decreaseFunds / thread B locks db record
  •     thread B exits withdraw / transaction B commits
  •     funds == -100
Yukarıdaki örnekte para olmadığı halde 100 TL çekilebildi. Eğer Repeatable read kullanırsak B thread'i A'nın işini bitirmesini beklemek zorunda kalır, çünkü satırı güncelleme niyeti ile kilitlemek istediğini bildirecek ancak kayıt zaten A tarafından kilitlendiği için bekleyecektir. Kilidi alınca da ilk transaction commit yaptığı için çekme işlemi gerçekleşmez. Açıklaması şöyle
If two transactions attempt to modify the same record, the second transaction will wait for the first one to either commit or rollback. If the first transaction commits, then the second one must be aborted to prevent lost updates.

4. Select İşlemi - Phantom Read Problemi
Bu problem halen karşımıza çıkabilir
Örnek
T1 begins
T1Queries select * from Tbl where X>100 → 3 rows
T2 begins
T2 Inserts 1 additional row with X=150.
T2 Commits.
T1 Queries select * from Tbl where X>100 → 4rows [Phantom Read].
5. Diğer Konular
Spring
Spring ile bu isolation level ile transaction başlatmak için aşağıdaki kod kullanılabilir.
@Transactional (isolation=Isolation.REPEATABLE_READ)
Oracle
Oracle bu isolation seviyesini desteklemez. Açıklaması şöyle.
REPEATABLE READ; Oracle does not normally support this isolation level, except as provided by SERIALIZABLE.
Vitess
Çoğu sharded veri tabanı gibi "Cross Shard" işlemlerde Repeatable Read seviyesi desteklenmez


Hiç yorum yok:

Yorum Gönder