自己写:把这一档调松
把 TODO 补完:让甲在事务里读第二次时能看到乙的改动,打出甲两次读到的值(用 / 隔开)。
acct 表:3 行,一开始每人 100,总额 300 id 1 / 2 / 3 name 甲 / 乙 / 丙 bal 100 / 100 / 100 四个现成的工具函数(题面里已经写好) bank(ru_a, ru_b) → 铺一份新库,给你两个连到**同一份数据**的连接 a、b bal(c, i) → 某个账户的余额;读不到(被锁着)就返回"锁住" total(c) → 三个账户加起来多少钱;读不到就返回"锁住" try_write(c, sql)→ 写一下:写得进去返回"成功",被锁住返回"写不进"
import sqlite3
_KEEP = [] # 保管连接:只要它活着,这份内存库就不会被回收
_SEQ = [0]
def bank(ru_a=False, ru_b=False):
"""铺一份新的三账户库,返回两个连到同一份数据的连接 (a, b)。
ru_a / ru_b:把那一边放松成"可以读到别人还没提交的改动"。"""
_SEQ[0] += 1
uri = "file:bank" + str(_SEQ[0]) + "?mode=memory&cache=shared"
keep = sqlite3.connect(uri, uri=True)
_KEEP.append(keep)
keep.execute("CREATE TABLE acct (id INTEGER PRIMARY KEY, name TEXT, bal INTEGER)")
keep.executemany("INSERT INTO acct VALUES (?,?,?)",
[(1, "甲", 100), (2, "乙", 100), (3, "丙", 100)])
keep.commit()
a = sqlite3.connect(uri, uri=True)
b = sqlite3.connect(uri, uri=True)
if ru_a:
a.execute("PRAGMA read_uncommitted = 1")
if ru_b:
b.execute("PRAGMA read_uncommitted = 1")
return a, b
def bal(c, i):
"""某个账户的余额。读不到(表被别人锁着)就返回"锁住"。"""
try:
return c.execute("SELECT bal FROM acct WHERE id = ?", (i,)).fetchone()[0]
except sqlite3.OperationalError:
return "锁住"
def total(c):
"""三个账户加起来一共多少钱。读不到就返回"锁住"。"""
try:
return c.execute("SELECT SUM(bal) FROM acct").fetchone()[0]
except sqlite3.OperationalError:
return "锁住"
def try_write(c, sql):
"""让这个连接写一下,写得进去返回"成功",被锁住返回"写不进"。"""
try:
c.execute(sql)
return "成功"
except sqlite3.OperationalError:
return "写不进"
a, b = bank() # TODO:把甲那边放松开
a.execute("BEGIN")
x = bal(a, 3)
b.execute("UPDATE acct SET bal = 555 WHERE id = 3")
b.commit()
y = bal(a, 3)
a.rollback()
print(str(x) + "/" + str(y))
全部评论