使用 Ksycopg2 驱动实现 Kingbase 数据库增删改查系统

46 阅读12分钟

@TOC

在这里插入图片描述

本篇文章我将介绍如何使用Python的ksycopg2驱动连接Kingbase数据库,并使用Flask框架搭建一个简单的Web应用实现增删改查功能。

一、环境准备

本文使用的环境是,Python 3.12+,KingbaseV9R1C10,Ksycopg2驱动。在文章开始前,要确保电脑上面已经安装了开发环境。 Kingbase安装可参考以下的安装教程: 金仓数据库KingbaseES V9R1C10安装教程 - Windows版详细指南​ Kingbase官网:www.kingbase.com.cn/ Kingbase学习文档:docs.kingbase.com.cn/cn/KES-V9R1…

验证Python版本:

Python -V

在这里插入图片描述 安装 Flask 框架和Ksycopg2 驱动:

# 安装 Flask 框架
pip3 install flask

# 安装 Ksycopg2 驱动
pip3 install ksycopg2

Ksycopg2 是专为 Kingbase 数据库设计的 Python 驱动,其 API 设计与 PostgreSQL 的 Psycopg2 驱动高度兼容,这使得从 PostgreSQL 迁移到 Kingbase 变得非常容易。

在这里插入图片描述

二、Ksycopg2 基础使用

在开始构建完整的 Web 应用之前,我们先学习如何使用 Ksycopg2 驱动连接和操作 Kingbase 数据库。

2.1 测试数据库连接

创建一个测试文件 test_connection.py,验证是否能成功连接数据库:

重要提示:请将代码中的 user、password、host、port 和 database 替换为您自己的数据库配置信息。

# -*- coding: utf-8 -*-
import ksycopg2

# 数据库连接参数
database = "TEST"
user = "SYSTEM"
password = "123456"
host = "127.0.0.1"
port = "54321"

try:
    # 建立数据库连接
    conn = ksycopg2.connect(
        "dbname={} user={} password={} host={} port={}".format(
            database, user, password, host, port
        )
    )
    print("数据库连接成功!")
    
    # 获取数据库版本信息
    cur = conn.cursor()
    cur.execute("SELECT version()")
    version = cur.fetchone()
    print(f"数据库版本: {version[0]}")
    
    cur.close()
    conn.close()
    
except Exception as e:
    print(f"数据库连接失败: {e}")

这里连接成功后咱们就可以继续进行下去了。此时已经说明我们使用ksycopg2成功驱动Kingbase 在这里插入图片描述

知识点:ksycopg2.connect() 方法使用连接字符串建立数据库连接。连接成功后,我们可以通过 cursor() 方法创建游标对象来执行 SQL 语句。

2.2 基础 CRUD 操作示例

创建 test_crud.py 文件,演示基本的增删改查操作:

# -*- coding: utf-8 -*-
import ksycopg2
from ksycopg2.extras import RealDictCursor

# 数据库连接配置
DB_CONFIG = {
    'dbname': 'TEST',
    'user': 'SYSTEM',
    'password': '123456',
    'host': '127.0.0.1',
    'port': '54321'
}

def get_connection():
    """获取数据库连接"""
    return ksycopg2.connect(
        "dbname={dbname} user={user} password={password} host={host} port={port}".format(**DB_CONFIG)
    )

# 1. 创建表 (Create Table)
def create_table():
    """创建测试表"""
    conn = get_connection()
    cur = conn.cursor()
    
    try:
        # 删除已存在的表
        cur.execute('DROP TABLE IF EXISTS test_users')
        
        # 创建新表
        cur.execute('''
            CREATE TABLE test_users (
                id SERIAL PRIMARY KEY,
                username VARCHAR(50) NOT NULL,
                email VARCHAR(100),
                age INTEGER,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        conn.commit()
        print("表创建成功!")
        
    except Exception as e:
        print(f"创建表失败: {e}")
        conn.rollback()
    finally:
        cur.close()
        conn.close()

# 2. 插入数据 (Create)
def insert_data():
    """插入测试数据"""
    conn = get_connection()
    cur = conn.cursor()
    
    try:
        # 单条插入
        cur.execute(
            "INSERT INTO test_users (username, email, age) VALUES (%s, %s, %s)",
            ('张三', 'zhangsan@example.com', 25)
        )
        
        # 批量插入
        users = [
            ('李四', 'lisi@example.com', 28),
            ('王五', 'wangwu@example.com', 30),
            ('赵六', 'zhaoliu@example.com', 22),
            ('测试用户', 'test@example.com', 35)
        ]
        
        cur.executemany(
            "INSERT INTO test_users (username, email, age) VALUES (%s, %s, %s)",
            users
        )
        
        conn.commit()
        print(f"成功插入 {len(users) + 1} 条数据!")
        
    except Exception as e:
        print(f"插入数据失败: {e}")
        conn.rollback()
    finally:
        cur.close()
        conn.close()

# 3. 查询数据 (Read)
def query_data():
    """查询数据"""
    conn = get_connection()
    # 使用 RealDictCursor 返回字典格式的结果
    cur = conn.cursor(cursor_factory=RealDictCursor)
    
    try:
        # 查询所有数据
        cur.execute("SELECT * FROM test_users ORDER BY id")
        users = cur.fetchall()
        
        print("\n所有用户列表:")
        print("-" * 80)
        for user in users:
            print(f"ID: {user['id']}, 姓名: {user['username']}, "
                  f"邮箱: {user['email']}, 年龄: {user['age']}")
        print("-" * 80)
        
        # 条件查询
        cur.execute("SELECT * FROM test_users WHERE age > %s", (25,))
        filtered_users = cur.fetchall()
        print(f"\n年龄大于25的用户: {len(filtered_users)} 人")
        
    except Exception as e:
        print(f"查询数据失败: {e}")
    finally:
        cur.close()
        conn.close()

# 4. 更新数据 (Update)
def update_data():
    """更新数据"""
    conn = get_connection()
    cur = conn.cursor()
    
    try:
        # 更新指定用户的邮箱
        cur.execute(
            "UPDATE test_users SET email = %s WHERE username = %s",
            ('zhangsan_new@example.com', '张三')
        )
        
        # 批量更新年龄
        cur.execute(
            "UPDATE test_users SET age = age + 1 WHERE age < %s",
            (30,)
        )
        
        conn.commit()
        print(f"更新了 {cur.rowcount} 条数据!")
        
    except Exception as e:
        print(f"更新数据失败: {e}")
        conn.rollback()
    finally:
        cur.close()
        conn.close()

# 5. 删除数据 (Delete)
def delete_data():
    """删除数据"""
    conn = get_connection()
    cur = conn.cursor()
    
    try:
        # 删除指定用户
        cur.execute("DELETE FROM test_users WHERE username = %s", ('测试用户',))
        
        conn.commit()
        print(f"删除了 {cur.rowcount} 条数据!")
        
    except Exception as e:
        print(f"删除数据失败: {e}")
        conn.rollback()
    finally:
        cur.close()
        conn.close()

# 6. 统计查询
def statistics():
    """统计查询"""
    conn = get_connection()
    cur = conn.cursor()
    
    try:
        # 总数统计
        cur.execute("SELECT COUNT(*) FROM test_users")
        total = cur.fetchone()[0]
        
        # 平均年龄
        cur.execute("SELECT AVG(age) FROM test_users")
        avg_age = cur.fetchone()[0]
        
        # 年龄范围
        cur.execute("SELECT MIN(age), MAX(age) FROM test_users")
        min_age, max_age = cur.fetchone()
        
        print(f"\n数据统计:")
        print(f"总用户数: {total}")
        print(f"平均年龄: {avg_age:.2f}")
        print(f"年龄范围: {min_age} - {max_age}")
        
    except Exception as e:
        print(f"统计查询失败: {e}")
    finally:
        cur.close()
        conn.close()

# 主函数
if __name__ == '__main__':
    print("=" * 80)
    print("Ksycopg2 CRUD 操作演示")
    print("=" * 80)
    
    # 执行各项操作
    create_table()      # 创建表
    insert_data()       # 插入数据
    query_data()        # 查询数据
    update_data()       # 更新数据
    query_data()        # 再次查询查看更新结果
    delete_data()       # 删除数据
    query_data()        # 最终查询
    statistics()        # 统计信息
    
    print("\n所有操作完成!")

运行以下命令进行测试:

python test_connection.py

成功执行,创建表结构和CRUD操作没问题。 在这里插入图片描述 在这里插入图片描述

知识点总结: execute() 用于执行单条 SQL 语句 executemany() 用于批量执行相同结构的 SQL 语句 fetchone() 获取单条结果 fetchall() 获取所有结果 commit() 提交事务 rollback() 回滚事务

2.3 Ksycopg2 关键特性说明

2.3.1 参数化查询

Ksycopg2 使用 %s 作为参数占位符,可以有效防止 SQL 注入:

# 正确的参数化查询
cur.execute("SELECT * FROM users WHERE id = %s", (user_id,))

# 错误的字符串拼接(容易被 SQL 注入攻击)
cur.execute(f"SELECT * FROM users WHERE id = {user_id}")

安全提示:永远不要使用字符串拼接来构建 SQL 语句,这会导致严重的安全漏洞。参数化查询会自动处理特殊字符的转义,有效防止 SQL 注入攻击。

2.3.2 游标类型

# 默认游标 - 返回元组
cur = conn.cursor()
cur.execute("SELECT id, name FROM users")
result = cur.fetchone()  # (1, 'John')

# 字典游标 - 返回字典(推荐)
from ksycopg2.extras import RealDictCursor
cur = conn.cursor(cursor_factory=RealDictCursor)
cur.execute("SELECT id, name FROM users")
result = cur.fetchone()  # {'id': 1, 'name': 'John'}

最佳实践:推荐使用 RealDictCursor,因为字典格式的结果更易读,代码可维护性更好。

2.3.3 事务管理

conn = get_connection()
cur = conn.cursor()

try:
    # 开始事务(自动开始)
    cur.execute("INSERT INTO users ...")
    cur.execute("UPDATE accounts ...")
    
    # 提交事务
    conn.commit()
except Exception as e:
    # 回滚事务
    conn.rollback()
    print(f"事务失败: {e}")
finally:
    cur.close()
    conn.close()

事务特性:事务保证了数据操作的原子性(要么全部成功,要么全部失败),这对于保持数据一致性至关重要。

三、完整 Web 应用实战

通过前面的学习,我们已经掌握了 Ksycopg2 的基础用法。现在让我们将这些知识应用到实际项目中,构建一个功能完整的学生管理系统。

3.1 项目结构

看一下整体的项目结构

student_system/
├── app.py              # 主程序
├── database.py         # 数据库操作
└── templates/
    ├── index.html      # 列表页面
    ├── add.html        # 添加页面
    └── edit.html       # 编辑页面

设计思想:采用 MVC 架构模式,将数据库操作(Model)、业务逻辑(Controller)和页面展示(View)分离,提高代码的可维护性和可扩展性。

3.2 database.py (数据库操作)

# -*- coding: utf-8 -*-
import ksycopg2
from ksycopg2.extras import RealDictCursor

class Database:
    def __init__(self):
        self.config = {
            'dbname': 'TEST',
            'user': 'SYSTEM',
            'password': '123456',
            'host': '127.0.0.1',
            'port': '54321'
        }
    
    def get_connection(self):
        """获取数据库连接"""
        try:
            conn = ksycopg2.connect(
                "dbname={dbname} user={user} password={password} host={host} port={port}".format(**self.config)
            )
            return conn
        except Exception as e:
            print(f"数据库连接失败: {e}")
            return None
    
    def init_table(self):
        """初始化数据表"""
        conn = self.get_connection()
        if not conn:
            return False
        
        try:
            cur = conn.cursor()
            cur.execute('''
                CREATE TABLE IF NOT EXISTS students (
                    id SERIAL PRIMARY KEY,
                    student_no VARCHAR(50) NOT NULL,
                    name VARCHAR(100) NOT NULL,
                    age INTEGER,
                    gender VARCHAR(10),
                    major VARCHAR(100),
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            ''')
            conn.commit()
            cur.close()
            conn.close()
            print("数据表初始化成功!")
            return True
        except Exception as e:
            print(f"初始化表失败: {e}")
            return False
    
    def add_student(self, student_no, name, age, gender, major):
        """添加学生"""
        conn = self.get_connection()
        if not conn:
            return False
        
        try:
            cur = conn.cursor()
            cur.execute(
                "INSERT INTO students (student_no, name, age, gender, major) VALUES (%s, %s, %s, %s, %s)",
                (student_no, name, age, gender, major)
            )
            conn.commit()
            cur.close()
            conn.close()
            return True
        except Exception as e:
            print(f"添加学生失败: {e}")
            return False
    
    def get_all_students(self):
        """查询所有学生"""
        conn = self.get_connection()
        if not conn:
            return []
        
        try:
            cur = conn.cursor(cursor_factory=RealDictCursor)
            cur.execute("SELECT * FROM students ORDER BY id DESC")
            students = cur.fetchall()
            cur.close()
            conn.close()
            return students
        except Exception as e:
            print(f"查询学生失败: {e}")
            return []
    
    def get_student_by_id(self, student_id):
        """根据ID查询学生"""
        conn = self.get_connection()
        if not conn:
            return None
        
        try:
            cur = conn.cursor(cursor_factory=RealDictCursor)
            cur.execute("SELECT * FROM students WHERE id = %s", (student_id,))
            student = cur.fetchone()
            cur.close()
            conn.close()
            return student
        except Exception as e:
            print(f"查询学生失败: {e}")
            return None
    
    def update_student(self, student_id, student_no, name, age, gender, major):
        """更新学生信息"""
        conn = self.get_connection()
        if not conn:
            return False
        
        try:
            cur = conn.cursor()
            cur.execute(
                "UPDATE students SET student_no=%s, name=%s, age=%s, gender=%s, major=%s WHERE id=%s",
                (student_no, name, age, gender, major, student_id)
            )
            conn.commit()
            cur.close()
            conn.close()
            return True
        except Exception as e:
            print(f"更新学生失败: {e}")
            return False
    
    def delete_student(self, student_id):
        """删除学生"""
        conn = self.get_connection()
        if not conn:
            return False
        
        try:
            cur = conn.cursor()
            cur.execute("DELETE FROM students WHERE id = %s", (student_id,))
            conn.commit()
            cur.close()
            conn.close()
            return True
        except Exception as e:
            print(f"删除学生失败: {e}")
            return False

设计亮点: 使用类封装数据库操作,提高代码复用性 统一的异常处理机制 自动管理数据库连接的打开和关闭 所有方法都有明确的返回值,便于调用者判断操作是否成功

3.3 app.py (Flask应用)

# -*- coding: utf-8 -*-
from flask import Flask, render_template, request, redirect, url_for, flash
from database import Database

app = Flask(__name__)
app.secret_key = 'your_secret_key_here'

# 初始化数据库
db = Database()
db.init_table()

@app.route('/')
def index():
    """主页 - 显示所有学生"""
    students = db.get_all_students()
    return render_template('index.html', students=students)

@app.route('/add', methods=['GET', 'POST'])
def add():
    """添加学生"""
    if request.method == 'POST':
        student_no = request.form.get('student_no')
        name = request.form.get('name')
        age = request.form.get('age')
        gender = request.form.get('gender')
        major = request.form.get('major')
        
        if db.add_student(student_no, name, age, gender, major):
            flash('学生添加成功!', 'success')
            return redirect(url_for('index'))
        else:
            flash('学生添加失败!', 'error')
    
    return render_template('add.html')

@app.route('/edit/<int:student_id>', methods=['GET', 'POST'])
def edit(student_id):
    """编辑学生"""
    if request.method == 'POST':
        student_no = request.form.get('student_no')
        name = request.form.get('name')
        age = request.form.get('age')
        gender = request.form.get('gender')
        major = request.form.get('major')
        
        if db.update_student(student_id, student_no, name, age, gender, major):
            flash('学生信息更新成功!', 'success')
            return redirect(url_for('index'))
        else:
            flash('学生信息更新失败!', 'error')
    
    student = db.get_student_by_id(student_id)
    return render_template('edit.html', student=student)

@app.route('/delete/<int:student_id>')
def delete(student_id):
    """删除学生"""
    if db.delete_student(student_id):
        flash('学生删除成功!', 'success')
    else:
        flash('学生删除失败!', 'error')
    
    return redirect(url_for('index'))

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

Flask 路由说明: @app.route('/') - 主页,显示学生列表 @app.route('/add') - 添加学生(支持 GET 和 POST) @app.route('/edit/int:student_id') - 编辑学生(动态路由参数) @app.route('/delete/int:student_id') - 删除学生 flash() 函数用于显示操作提示消息

3.4 templates/index.html (列表页面)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>学生管理系统</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: Arial, 'Microsoft YaHei', sans-serif; padding: 20px; background: #f5f5f5; }
        .container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 5px; }
        h1 { color: #333; margin-bottom: 20px; }
        .alert { padding: 10px; margin-bottom: 15px; border-radius: 3px; }
        .alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
        .alert-error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
        .btn { display: inline-block; padding: 8px 15px; text-decoration: none; border-radius: 3px; margin-bottom: 15px; }
        .btn-primary { background: #007bff; color: white; }
        .btn-success { background: #28a745; color: white; }
        .btn-warning { background: #ffc107; color: #333; }
        .btn-danger { background: #dc3545; color: white; }
        table { width: 100%; border-collapse: collapse; margin-top: 10px; }
        th, td { padding: 12px; text-align: left; border: 1px solid #ddd; }
        th { background: #007bff; color: white; }
        tr:hover { background: #f5f5f5; }
        .no-data { text-align: center; padding: 40px; color: #999; }
    </style>
</head>
<body>
    <div class="container">
        <h1>🎓 学生管理系统</h1>
        
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                    <div class="alert alert-{{ category }}">{{ message }}</div>
                {% endfor %}
            {% endif %}
        {% endwith %}
        
        <a href="{{ url_for('add') }}" class="btn btn-primary">➕ 添加学生</a>
        
        {% if students %}
        <table>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>学号</th>
                    <th>姓名</th>
                    <th>年龄</th>
                    <th>性别</th>
                    <th>专业</th>
                    <th>创建时间</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                {% for student in students %}
                <tr>
                    <td>{{ student.id }}</td>
                    <td>{{ student.student_no }}</td>
                    <td>{{ student.name }}</td>
                    <td>{{ student.age }}</td>
                    <td>{{ student.gender }}</td>
                    <td>{{ student.major }}</td>
                    <td>{{ student.created_at }}</td>
                    <td>
                        <a href="{{ url_for('edit', student_id=student.id) }}" class="btn btn-warning">编辑</a>
                        <a href="{{ url_for('delete', student_id=student.id) }}" 
                           class="btn btn-danger" 
                           onclick="return confirm('确定要删除吗?')">删除</a>
                    </td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
        {% else %}
        <div class="no-data">暂无学生数据</div>
        {% endif %}
    </div>
</body>
</html>

3.5 templates/add.html (添加页面)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>添加学生</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: Arial, 'Microsoft YaHei', sans-serif; padding: 20px; background: #f5f5f5; }
        .container { max-width: 600px; margin: 0 auto; background: white; padding: 20px; border-radius: 5px; }
        h1 { color: #333; margin-bottom: 20px; }
        .form-group { margin-bottom: 15px; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input, select { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 3px; }
        .btn { display: inline-block; padding: 10px 20px; text-decoration: none; border: none; border-radius: 3px; cursor: pointer; margin-right: 10px; }
        .btn-success { background: #28a745; color: white; }
        .btn-secondary { background: #6c757d; color: white; }
    </style>
</head>
<body>
    <div class="container">
        <h1>➕ 添加学生</h1>
        
        <form method="POST">
            <div class="form-group">
                <label>学号:</label>
                <input type="text" name="student_no" required>
            </div>
            
            <div class="form-group">
                <label>姓名:</label>
                <input type="text" name="name" required>
            </div>
            
            <div class="form-group">
                <label>年龄:</label>
                <input type="number" name="age" min="1" max="150" required>
            </div>
            
            <div class="form-group">
                <label>性别:</label>
                <select name="gender" required>
                    <option value="">请选择</option>
                    <option value="男"></option>
                    <option value="女"></option>
                </select>
            </div>
            
            <div class="form-group">
                <label>专业:</label>
                <input type="text" name="major" required>
            </div>
            
            <button type="submit" class="btn btn-success">保存</button>
            <a href="{{ url_for('index') }}" class="btn btn-secondary">返回</a>
        </form>
    </div>
</body>
</html>

3.6 templates/edit.html (编辑页面)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>编辑学生</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: Arial, 'Microsoft YaHei', sans-serif; padding: 20px; background: #f5f5f5; }
        .container { max-width: 600px; margin: 0 auto; background: white; padding: 20px; border-radius: 5px; }
        h1 { color: #333; margin-bottom: 20px; }
        .form-group { margin-bottom: 15px; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input, select { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 3px; }
        .btn { display: inline-block; padding: 10px 20px; text-decoration: none; border: none; border-radius: 3px; cursor: pointer; margin-right: 10px; }
        .btn-success { background: #28a745; color: white; }
        .btn-secondary { background: #6c757d; color: white; }
    </style>
</head>
<body>
    <div class="container">
        <h1>✏️ 编辑学生</h1>
        
        {% if student %}
        <form method="POST">
            <div class="form-group">
                <label>学号:</label>
                <input type="text" name="student_no" value="{{ student.student_no }}" required>
            </div>
            
            <div class="form-group">
                <label>姓名:</label>
                <input type="text" name="name" value="{{ student.name }}" required>
            </div>
            
            <div class="form-group">
                <label>年龄:</label>
                <input type="number" name="age" value="{{ student.age }}" min="1" max="150" required>
            </div>
            
            <div class="form-group">
                <label>性别:</label>
                <select name="gender" required>
                    <option value="男" {% if student.gender == '男' %}selected{% endif %}></option>
                    <option value="女" {% if student.gender == '女' %}selected{% endif %}></option>
                </select>
            </div>
            
            <div class="form-group">
                <label>专业:</label>
                <input type="text" name="major" value="{{ student.major }}" required>
            </div>
            
            <button type="submit" class="btn btn-success">更新</button>
            <a href="{{ url_for('index') }}" class="btn btn-secondary">返回</a>
        </form>
        {% else %}
        <p>学生不存在</p>
        <a href="{{ url_for('index') }}" class="btn btn-secondary">返回</a>
        {% endif %}
    </div>
</body>
</html>

3.5 运行和测试应用

3.5.1 运行应用

在项目根目录下执行:

python app.py

访问系统:打开浏览器访问: http://localhost:5000

3.5.2 测试添加功能

在这里插入图片描述 填写学生信息后点击保存: 在这里插入图片描述

3.5.3 测试编辑功能

点击编辑按钮: 在这里插入图片描述 修改信息后保存: 在这里插入图片描述

3.5.4 测试删除功能

点击删除按钮,确认后删除: 在这里插入图片描述

四、文章总结

本文详细介绍了如何使用 Python 的 Ksycopg2 驱动连接 Kingbase 数据库,并基于 Flask 框架构建了一个完整的学生管理系统。文章从环境准备开始,循序渐进地讲解了 Ksycopg2 的基础使用方法,包括数据库连接、CRUD 操作、参数化查询、事务管理等核心知识点。随后通过实战项目演示了如何将数据库操作封装成独立的 Database 类,采用 MVC 架构模式实现了学生信息的增删改查功能,并提供了完整的前端页面展示。整个教程代码完整、注释详细,适合初学者快速掌握 Python + Kingbase 的 Web 应用开发技能。 在这里插入图片描述


关键技术栈总结:

  • 数据库:Kingbase V9R1C10
  • Python 版本:3.12+
  • 核心驱动:Ksycopg2(兼容 Psycopg2 API)
  • Web 框架:Flask
  • 架构模式:MVC(Model-View-Controller)
  • 安全特性:参数化查询防止 SQL 注入、事务管理保证数据一致性