2026/3/28 16:23:23
网站建设
项目流程
网站基础建设ppt,常州网络推广公司哪家好,酷站官网,东莞市大朗镇这个例子模拟了一个经典的“转账”场景#xff1a;A 给 B 转钱#xff0c;如果在扣款后、收款前系统发生错误#xff08;比如断电、代码异常#xff09;#xff0c;必须让数据回到转账前的状态#xff0c;保证钱不凭空消失。
环境准备#xff1a;
你需要安装 pymysql 库…这个例子模拟了一个经典的“转账”场景A 给 B 转钱如果在扣款后、收款前系统发生错误比如断电、代码异常必须让数据回到转账前的状态保证钱不凭空消失。环境准备你需要安装pymysql库pipinstallpymysql代码实现importpymysqlimportsys# 数据库配置请根据你的实际情况修改DB_CONFIG{host:localhost,user:root,password:your_password,database:test_db,charset:utf8mb4}defsetup_database(cursor):初始化测试表和数据try:cursor.execute(DROP TABLE IF EXISTS accounts)cursor.execute( CREATE TABLE accounts ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), balance DECIMAL(10, 2) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 )# 插入初始数据Alice有1000元Bob有500元cursor.execute(INSERT INTO accounts (name, balance) VALUES (Alice, 1000.00))cursor.execute(INSERT INTO accounts (name, balance) VALUES (Bob, 500.00))print(✅ 数据库初始化完成Alice1000, Bob500)exceptExceptionase:print(f❌ 初始化失败:{e})deftransfer_money_with_rollback(from_user,to_user,amount): 模拟转账业务并在发生错误时回滚 connectionNonetry:# 1. 建立连接connectionpymysql.connect(**DB_CONFIG)# 2. 关键步骤关闭自动提交开启事务connection.autocommit(False)withconnection.cursor()ascursor:# --- 步骤一扣款 ---print(f\n 正在从{from_user}扣除{amount}元...)sql_deductUPDATE accounts SET balance balance - %s WHERE name %scursor.execute(sql_deduct,(amount,from_user))# 模拟查询扣款后的余额仅为了演示实际业务中可能不需要cursor.execute(SELECT balance FROM accounts WHERE name %s,(from_user,))resultcursor.fetchone()print(f 扣款后查询{from_user}余额:{result[0]}(此时数据在内存/Redo Log中未永久落盘))# --- 步骤二模拟突发异常 ---# 比如此时服务器断电、网络中断、或者代码逻辑错误print(⚠️ 模拟系统崩溃准备加款时发生除零错误)error_simulation1/0# 故意制造一个异常# --- 步骤三加款正常情况下会执行但上面报错了就不会走到这 ---sql_addUPDATE accounts SET balance balance %s WHERE name %scursor.execute(sql_add,(amount,to_user))# 3. 如果一切顺利提交事务connection.commit()print(✅ 转账成功事务已提交)exceptExceptionase:print(f\n❌ 发生严重错误:{e})ifconnection:# 4. 核心发生任何异常回滚所有操作print( 正在执行回滚操作 (ROLLBACK)...)connection.rollback()print(️ 回滚成功数据已恢复到事务开始前的状态。)finally:ifconnection:# 5. 恢复自动提交模式并关闭连接connection.autocommit(True)connection.close()defcheck_final_balance():检查最终结果connpymysql.connect(**DB_CONFIG)withconn.cursor()ascursor:cursor.execute(SELECT name, balance FROM accounts)resultscursor.fetchall()print(\n----- 最终账户余额 -----)forrowinresults:print(f用户:{row[0]}, 余额:{row[1]})print(------------------------)# 验证结果alice_balanceresults[0][1]ifresults[0][0]Aliceelseresults[1][1]bob_balanceresults[0][1]ifresults[0][0]Bobelseresults[1][1]assertalice_balance1000,fAlice余额错误期望1000实际{alice_balance}assertbob_balance500,fBob余额错误期望500实际{bob_balance}print( 验证通过数据一致回滚生效)conn.close()if__name____main__:# 初始化conn_initpymysql.connect(**DB_CONFIG)withconn_init.cursor()ascur:setup_database(cur)conn_init.commit()conn_init.close()# 执行带回滚的转账transfer_money_with_rollback(Alice,Bob,200)# 检查最终数据是否正确回滚check_final_balance()代码讲解重点写进博客里connection.autocommit(False)这是事务的开关。默认情况下 MySQL 是自动提交的每句 SQL 都是一个事务关掉它才能把多步操作打包成一个整体。try...except...结构业务逻辑必须放在try里。connection.rollback()这是“后悔药”。一旦进入except块调用此方法会撤销从autocommit(False)之后的所有未提交更改。connection.commit()这是“确认键”。只有执行了这个数据才真正写入磁盘配合 Redo Log 和 Binlog。EngineInnoDB注意建表时指定了引擎为 InnoDB。如果是 MyISAM 引擎它不支持事务rollback会失效这是面试常考点。运行这个脚本你会看到虽然执行了扣款 SQL但因为中间报错触发了回滚最后 Alice 的钱还是 1000Bob 还是 500完美保证了数据的一致性。