好雷。不踩嗎
Isolation Level 在 DB 裡面是 ACID 中的 I,也就是 隔離性 ,主要解決在 併發(concurrency) 處理時,由於互相執行導致結果不一致的狀況。基本上分為四種等級:Read Uncommitted、Read Committed、 Repeatable Read、Serializable
下面是一個簡單的 Python publisher 程式碼,會定期增加一個 event:
#! /usr/bin/env python
# Copyright (C) 2017-2018 cmj<cmj@cmj.tw>. All right reserved.
import time
from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, DateTime
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class TestEvent(Base):
__tablename__ = 'test_event_table'
id = Column(Integer, primary_key=True)
created = Column(DateTime, default=datetime.utcnow)
def __repr__(self):
return f'event #{self.id}'
if __name__ == '__main__':
engine = 'mysql+pymysql://localhost/test?charset=utf8mb4'
engine = create_engine(engine)
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
session = scoped_session(Session)
Base.metadata.create_all(engine)
while True:
event = TestEvent()
session.add(event)
session.commit()
print(event)
time.sleep(1)
Serializable
跟 Repeatable Read 類似,但是在 InnoDB 中會幫每個 SELECT 加上 FOR SHARE 語法。如果有使用 autocommit 則會每次 SELECT 都當作是一個 transaction。在尚未 commit 之前都會 blocking 直到 commit
:::python
engine = 'mysql+pymysql://localhost/test?charset=utf8mb4'
engine = create_engine(engine, isolation_level='SERIALIZABLE')
Repeatable Read
在 Mysql / InnoDB 中的預設選項:當第一次執行 SELECT 語法時會產生一個 snapshot,當在同一個 transaction 中再次執行時會被視為是跟第一次執行一樣的結果。
以下使用預設的 Isolation Level 撰寫的 subscriber:
:::python
#! /usr/bin/env python
# Copyright (C) 2017-2018 cmj<cmj@cmj.tw>. All right reserved.
import time
from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, DateTime
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class TestEvent(Base):
__tablename__ = 'test_event_table'
id = Column(Integer, primary_key=True)
created = Column(DateTime, default=datetime.utcnow)
def __repr__(self):
return f'event #{self.id}'
if __name__ == '__main__':
engine = 'mysql+pymysql://localhost/test?charset=utf8mb4'
engine = create_engine(engine)
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
session = scoped_session(Session)
Base.metadata.create_all(engine)
while True:
event = session.query(TestEvent).order_by(TestEvent.id.desc()).first()
print(event)
time.sleep(1)
Read Committed
在 Read Committed 中依然在每次 transaction 使用 Write Lock,但是 Read Lock 會在每次 SELECT 之後釋放。透過這種方式,就可以拿到每次更新之後的結果:
:::python
engine = 'mysql+pymysql://localhost/test?charset=utf8mb4'
engine = create_engine(engine, isolation_level='READ COMMITTED')
Read Uncommitted
這是最低階的 Isolation Level:在這個層級中 髒讀 (Dirty Read) 是被允許的,也就是讀取尚未被 commit 的修改。
:::python
engine = 'mysql+pymysql://localhost/test?charset=utf8mb4'
engine = create_engine(engine, isolation_level='READ UNCOMMITTED')
)