面试题答案
一键面试避免数据竞争和脏读的方法
- 事务隔离级别设置:通过设置合适的事务隔离级别,可以有效避免脏读、不可重复读等问题。
psycopg2
支持多种事务隔离级别,如READ COMMITTED
、REPEATABLE READ
、SERIALIZABLE
等。 - 锁机制:使用数据库级别的锁,如行级锁、表级锁,来确保在同一时间只有一个线程可以对特定的数据进行修改。
关键代码示例
import threading
import psycopg2
from psycopg2 import pool
# 创建连接池
postgreSQL_pool = pool.SimpleConnectionPool(
1,
20,
user="your_user",
password="your_password",
host="127.0.0.1",
port="5432",
database="your_database"
)
def worker():
# 从连接池获取连接
connection = postgreSQL_pool.getconn()
try:
cursor = connection.cursor()
# 设置事务隔离级别为 SERIALIZABLE
cursor.execute('SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE')
# 开启事务
connection.autocommit = False
try:
# 读操作
cursor.execute('SELECT * FROM your_table')
rows = cursor.fetchall()
print(f"Read data: {rows}")
# 写操作(例如更新)
cursor.execute('UPDATE your_table SET some_column = %s WHERE some_condition', ('new_value',))
# 提交事务
connection.commit()
except (Exception, psycopg2.Error) as error:
print(f"Error in transaction: {error}")
connection.rollback()
finally:
# 将连接放回连接池
postgreSQL_pool.putconn(connection)
# 创建多个线程
threads = []
for _ in range(5):
thread = threading.Thread(target=worker)
threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
# 关闭连接池
postgreSQL_pool.closeall()
代码说明
- 连接池:使用
psycopg2
的连接池来管理数据库连接,提高性能和资源利用率。 - 事务隔离级别设置:通过
cursor.execute('SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE')
设置事务隔离级别为SERIALIZABLE
,这是最严格的隔离级别,可以避免所有常见的数据竞争问题。 - 事务操作:通过
connection.autocommit = False
开启手动事务管理,在操作完成后使用connection.commit()
提交事务,发生错误时使用connection.rollback()
回滚事务。 - 锁机制:在上述代码中,虽然没有显式地使用锁语句,但
SERIALIZABLE
隔离级别会在数据库内部自动使用锁机制来确保事务的串行化执行,从而避免数据竞争。如果需要更细粒度的控制,可以使用SELECT... FOR UPDATE
语句来获取行级锁,例如:
cursor.execute('SELECT * FROM your_table WHERE some_condition FOR UPDATE')
这会锁定符合条件的行,直到事务结束,其他事务无法修改这些行。