不止于连接:用Python+Psycopg2玩转openGauss,从增删改查到事务实战
·
不止于连接:用Python+Psycopg2玩转openGauss,从增删改查到事务实战
在数据库应用开发中,仅仅建立连接只是万里长征的第一步。本文将带你深入探索如何利用Python的Psycopg2库与openGauss数据库进行高效交互,从基础的增删改查操作到复杂的事务处理,构建一个完整的员工信息管理系统实战项目。
1. 环境准备与高级连接配置
在开始实战之前,确保已完成以下准备工作:
- Python 3.6+环境
- openGauss数据库服务正常运行
- Psycopg2库已安装(推荐版本2.8.6+)
安全连接配置示例:
import psycopg2
from psycopg2 import pool
# 创建连接池
connection_pool = psycopg2.pool.ThreadedConnectionPool(
minconn=1,
maxconn=10,
database="hr_system",
user="app_user",
password="SecurePass123!",
host="db.example.com",
port="5432",
sslmode="require",
sslrootcert="/path/to/root.crt"
)
提示:生产环境务必使用SSL加密连接,避免敏感数据在传输过程中被窃取
连接参数对比表:
| 参数 | openGauss | PostgreSQL | 说明 |
|---|---|---|---|
| sslmode | 支持 | 支持 | 安全连接模式 |
| sslrootcert | 必需 | 可选 | 根证书路径 |
| application_name | 支持 | 支持 | 应用标识 |
| connect_timeout | 支持 | 支持 | 连接超时设置 |
2. 构建员工信息管理系统核心功能
2.1 数据库模型设计
首先设计员工管理系统的基础表结构:
-- 部门表
CREATE TABLE departments (
dept_id SERIAL PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL,
location VARCHAR(100)
);
-- 员工表
CREATE TABLE employees (
emp_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
hire_date DATE NOT NULL,
salary NUMERIC(10,2) CHECK (salary > 0),
dept_id INTEGER REFERENCES departments(dept_id)
);
-- 薪资调整记录表
CREATE TABLE salary_history (
history_id SERIAL PRIMARY KEY,
emp_id INTEGER REFERENCES employees(emp_id),
old_salary NUMERIC(10,2),
new_salary NUMERIC(10,2),
change_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
reason VARCHAR(200)
);
2.2 参数化查询与防注入实践
使用参数化查询是防止SQL注入的关键:
def add_employee(first_name, last_name, email, hire_date, salary, dept_id):
conn = connection_pool.getconn()
try:
with conn.cursor() as cur:
# 使用参数化查询
cur.execute(
"INSERT INTO employees (first_name, last_name, email, hire_date, salary, dept_id) "
"VALUES (%s, %s, %s, %s, %s, %s) RETURNING emp_id",
(first_name, last_name, email, hire_date, salary, dept_id)
)
new_id = cur.fetchone()[0]
conn.commit()
return new_id
except psycopg2.Error as e:
conn.rollback()
print(f"Error adding employee: {e}")
return None
finally:
connection_pool.putconn(conn)
2.3 批量数据处理技巧
处理大量数据时,使用executemany和服务器端游标提高效率:
def bulk_insert_employees(employee_list):
conn = connection_pool.getconn()
try:
with conn.cursor() as cur:
# 准备数据
data = [(emp['first_name'], emp['last_name'], emp['email'],
emp['hire_date'], emp['salary'], emp['dept_id'])
for emp in employee_list]
# 批量插入
cur.executemany(
"INSERT INTO employees (first_name, last_name, email, hire_date, salary, dept_id) "
"VALUES (%s, %s, %s, %s, %s, %s)",
data
)
conn.commit()
return True
except psycopg2.Error as e:
conn.rollback()
print(f"Bulk insert failed: {e}")
return False
finally:
connection_pool.putconn(conn)
3. 事务管理与数据一致性
3.1 基本事务控制
openGauss的事务特性与PostgreSQL高度兼容:
def transfer_employee(emp_id, from_dept, to_dept):
conn = connection_pool.getconn()
try:
with conn.cursor() as cur:
# 开始事务
conn.autocommit = False
# 检查员工当前部门
cur.execute("SELECT dept_id FROM employees WHERE emp_id = %s FOR UPDATE", (emp_id,))
current_dept = cur.fetchone()
if not current_dept or current_dept[0] != from_dept:
raise ValueError("Employee not in source department")
# 更新部门
cur.execute(
"UPDATE employees SET dept_id = %s WHERE emp_id = %s",
(to_dept, emp_id)
)
# 记录调动
cur.execute(
"INSERT INTO employee_transfers (emp_id, from_dept, to_dept, transfer_date) "
"VALUES (%s, %s, %s, CURRENT_TIMESTAMP)",
(emp_id, from_dept, to_dept)
)
conn.commit()
return True
except Exception as e:
conn.rollback()
print(f"Transfer failed: {e}")
return False
finally:
conn.autocommit = True
connection_pool.putconn(conn)
3.2 保存点(Savepoint)应用
复杂事务中使用保存点实现部分回滚:
def complex_employee_update(emp_id, updates):
conn = connection_pool.getconn()
try:
with conn.cursor() as cur:
conn.autocommit = False
# 创建保存点
cur.execute("SAVEPOINT start_update")
# 更新基本信息
if 'email' in updates:
cur.execute(
"UPDATE employees SET email = %s WHERE emp_id = %s",
(updates['email'], emp_id)
)
# 薪资调整需要特殊处理
if 'salary' in updates:
# 获取当前薪资
cur.execute("SELECT salary FROM employees WHERE emp_id = %s", (emp_id,))
old_salary = cur.fetchone()[0]
# 验证新薪资
if updates['salary'] < old_salary * 0.9:
# 薪资降幅超过10%需要额外审批
raise ValueError("Salary decrease exceeds 10% limit")
# 更新薪资
cur.execute(
"UPDATE employees SET salary = %s WHERE emp_id = %s",
(updates['salary'], emp_id)
)
# 记录薪资变更
cur.execute(
"INSERT INTO salary_history (emp_id, old_salary, new_salary, reason) "
"VALUES (%s, %s, %s, %s)",
(emp_id, old_salary, updates['salary'], updates.get('reason', 'Regular adjustment'))
)
conn.commit()
return True
except ValueError as ve:
# 回滚到保存点
cur.execute("ROLLBACK TO SAVEPOINT start_update")
conn.commit()
print(f"Validation error: {ve}")
return False
except Exception as e:
conn.rollback()
print(f"Update failed: {e}")
return False
finally:
conn.autocommit = True
connection_pool.putconn(conn)
4. 高级特性与性能优化
4.1 游标分页查询
处理大量数据时使用游标分页:
def get_employees_by_department(dept_id, page_size=100):
conn = connection_pool.getconn()
try:
with conn.cursor(name='employee_cursor') as cur:
# 使用命名游标
cur.itersize = page_size # 每次从服务器获取的行数
cur.execute(
"SELECT emp_id, first_name, last_name, email, salary "
"FROM employees WHERE dept_id = %s ORDER BY emp_id",
(dept_id,)
)
while True:
employees = cur.fetchmany(page_size)
if not employees:
break
for emp in employees:
yield {
'id': emp[0],
'name': f"{emp[1]} {emp[2]}",
'email': emp[3],
'salary': emp[4]
}
finally:
connection_pool.putconn(conn)
4.2 连接池监控与管理
合理管理连接池资源:
def monitor_connection_pool():
stats = {
'total_connections': connection_pool.maxconn,
'idle_connections': connection_pool.maxconn - len(connection_pool._used),
'waiting_requests': connection_pool._waiting,
'connection_timeout': connection_pool._timeout
}
# 记录连接池使用情况
with open('connection_pool.log', 'a') as f:
f.write(f"{datetime.now()}: {stats}\n")
return stats
# 定期执行监控
import threading
def start_pool_monitor(interval=300):
def monitor():
while True:
monitor_connection_pool()
time.sleep(interval)
thread = threading.Thread(target=monitor, daemon=True)
thread.start()
4.3 openGauss特有功能利用
利用openGauss的MOT内存表提升性能:
def create_mot_table():
conn = connection_pool.getconn()
try:
with conn.cursor() as cur:
# 创建内存优化表
cur.execute("""
CREATE FOREIGN TABLE employee_cache (
emp_id INTEGER PRIMARY KEY,
name VARCHAR(100),
dept_name VARCHAR(50),
salary NUMERIC(10,2)
) SERVER mot_server
""")
# 初始化缓存数据
cur.execute("""
INSERT INTO employee_cache
SELECT e.emp_id, e.first_name || ' ' || e.last_name, d.dept_name, e.salary
FROM employees e JOIN departments d ON e.dept_id = d.dept_id
""")
conn.commit()
return True
except psycopg2.Error as e:
conn.rollback()
print(f"Failed to create MOT table: {e}")
return False
finally:
connection_pool.putconn(conn)
在实际项目中,我发现合理使用连接池和事务隔离级别能显著提升应用性能。特别是在高并发场景下,设置合适的连接池大小和事务超时时间至关重要。
更多推荐


所有评论(0)