MST

星途 面试题库

面试题:Python多线程下数据库事务的处理与并发控制

假设在Python的多线程环境下,使用`psycopg2`连接PostgreSQL数据库。多个线程需要对同一张表进行读写操作,且每个线程都有自己的事务。请阐述如何避免数据竞争和脏读等问题,并给出关键代码示例说明如何实现事务隔离级别设置以及锁机制的应用。
21.8万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

避免数据竞争和脏读的方法

  1. 事务隔离级别设置:通过设置合适的事务隔离级别,可以有效避免脏读、不可重复读等问题。psycopg2支持多种事务隔离级别,如READ COMMITTEDREPEATABLE READSERIALIZABLE 等。
  2. 锁机制:使用数据库级别的锁,如行级锁、表级锁,来确保在同一时间只有一个线程可以对特定的数据进行修改。

关键代码示例

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()

代码说明

  1. 连接池:使用psycopg2的连接池来管理数据库连接,提高性能和资源利用率。
  2. 事务隔离级别设置:通过cursor.execute('SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE')设置事务隔离级别为SERIALIZABLE,这是最严格的隔离级别,可以避免所有常见的数据竞争问题。
  3. 事务操作:通过connection.autocommit = False开启手动事务管理,在操作完成后使用connection.commit()提交事务,发生错误时使用connection.rollback()回滚事务。
  4. 锁机制:在上述代码中,虽然没有显式地使用锁语句,但SERIALIZABLE隔离级别会在数据库内部自动使用锁机制来确保事务的串行化执行,从而避免数据竞争。如果需要更细粒度的控制,可以使用SELECT... FOR UPDATE语句来获取行级锁,例如:
cursor.execute('SELECT * FROM your_table WHERE some_condition FOR UPDATE')

这会锁定符合条件的行,直到事务结束,其他事务无法修改这些行。