最出名的网站建设公司wordpress下载主题footer

张小明 2026/1/8 0:12:16
最出名的网站建设公司,wordpress下载主题footer,江门seo,网站建设网课Python MySQL事务实战#xff1a;从转账异常到数据一致性#xff0c;手把手教你避坑 文章目录Python MySQL事务实战#xff1a;从转账异常到数据一致性#xff0c;手把手教你避坑引言#xff1a;为什么你的转账代码总出问题#xff1f;一、环境准备#xff1a;搭建你的第…Python MySQL事务实战从转账异常到数据一致性手把手教你避坑文章目录Python MySQL事务实战从转账异常到数据一致性手把手教你避坑引言为什么你的转账代码总出问题一、环境准备搭建你的第一个事务测试环境1.1 安装必要的库1.2 创建测试数据库和表二、基础概念事务到底是什么2.1 事务的ACID原则用大白话解释2.2 为什么Python开发者需要事务三、实战演练用pymysql实现完整事务控制3.1 基础事务操作自动提交 vs 手动提交3.2 事务的保存点复杂事务的后悔药四、事务隔离级别解决并发问题4.1 四种隔离级别对比4.2 实战设置和验证隔离级别五、异常处理的最佳实践5.1 完整的异常处理模板5.2 常见异常及处理方案六、实际项目应用电商订单系统七、学习总结与避坑指南7.1 关键要点回顾7.2 常见坑点及解决方案学习交流与进阶我刚开始用Python操作MySQL时最怕的就是转账扣款这种业务——钱扣了但没到账或者重复扣款。直到真正理解了事务才发现原来数据一致性可以这么简单引言为什么你的转账代码总出问题你有没有遇到过这样的场景用户下单支付钱从账户扣了但订单状态没更新或者更糟系统崩溃后数据处于“半完成”状态这些问题的根源就是事务管理没做好。在Python MySQL开发中事务是保证数据一致性的核心机制。今天我将用10年实战经验带你从零掌握MySQL事务管理让你写的转账、库存扣减等关键业务代码再也不会出现数据错乱。学完本文你将掌握事务的ACID原理用大白话讲清楚用pymysql实现完整的事务控制异常处理的正确姿势避免事务泄露事务隔离级别的实战选择一个完整的银行转账案例一、环境准备搭建你的第一个事务测试环境1.1 安装必要的库# 安装pymysql - 我们选择纯Python实现的驱动pipinstallpymysql# 安装mysql客户端可选用于验证# brew install mysql-client # Mac# apt-get install mysql-client # Ubuntu1.2 创建测试数据库和表我们先创建一个简单的银行账户系统来模拟真实业务-- 创建数据库CREATEDATABASEIFNOTEXISTSbank_systemDEFAULTCHARSETutf8mb4;-- 使用数据库USEbank_system;-- 创建账户表CREATETABLEaccounts(idINTPRIMARYKEYAUTO_INCREMENT,account_noVARCHAR(20)UNIQUENOTNULLCOMMENT账号,account_nameVARCHAR(50)NOTNULLCOMMENT账户名,balanceDECIMAL(10,2)DEFAULT0.00COMMENT余额,created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP)ENGINEInnoDBDEFAULTCHARSETutf8mb4;-- 创建交易记录表CREATETABLEtransactions(idINTPRIMARYKEYAUTO_INCREMENT,from_accountVARCHAR(20)COMMENT转出账号,to_accountVARCHAR(20)COMMENT转入账号,amountDECIMAL(10,2)NOTNULLCOMMENT金额,transaction_typeENUM(TRANSFER,DEPOSIT,WITHDRAW)NOTNULL,statusENUM(SUCCESS,FAILED,PENDING)DEFAULTPENDING,created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP,INDEXidx_account(from_account,to_account))ENGINEInnoDBDEFAULTCHARSETutf8mb4;-- 插入测试数据INSERTINTOaccounts(account_no,account_name,balance)VALUES(1001,张三,10000.00),(1002,李四,5000.00),(1003,王五,2000.00);技巧提示一定要用InnoDB引擎只有InnoDB支持完整的事务特性MyISAM不支持事务。二、基础概念事务到底是什么2.1 事务的ACID原则用大白话解释原子性Atomicity就像开关灯要么开全部成功要么关全部失败没有中间状态。转账时扣款和加款必须同时成功或同时失败。一致性Consistency转账前后系统总金额必须保持不变。张三10000元李四5000元转账后总额还是15000元。隔离性Isolation多个用户同时转账时互相看不到对方的中间状态。你转账时别人查余额看到的是转账前或转账后的状态不会看到“钱扣了但没到账”的中间态。持久性Durability一旦转账成功即使服务器断电数据也不会丢失。2.2 为什么Python开发者需要事务我刚开始写Python数据库代码时经常这样写# ❌ 错误示范没有事务的转账代码deftransfer_without_transaction(from_account,to_account,amount):# 扣款cursor.execute(UPDATE accounts SET balance balance - %s WHERE account_no %s,(amount,from_account))# 这里如果程序崩溃...time.sleep(1)# 模拟网络延迟或程序异常# 加款cursor.execute(UPDATE accounts SET balance balance %s WHERE account_no %s,(amount,to_account))问题很明显如果程序在两次UPDATE之间崩溃钱扣了但没到账数据就不一致了三、实战演练用pymysql实现完整事务控制3.1 基础事务操作自动提交 vs 手动提交MySQL默认是自动提交模式每个SQL语句都是一个独立事务。我们需要改为手动控制importpymysqlimportlogging# 配置日志方便调试logging.basicConfig(levellogging.INFO)loggerlogging.getLogger(__name__)classBankSystem:def__init__(self):self.connectionNonedefconnect(self):建立数据库连接try:self.connectionpymysql.connect(hostlocalhost,userroot,passwordyour_password,databasebank_system,charsetutf8mb4,cursorclasspymysql.cursors.DictCursor# 返回字典格式)logger.info(数据库连接成功)returnTrueexceptpymysql.Errorase:logger.error(f数据库连接失败:{e})returnFalsedefbasic_transfer(self,from_account,to_account,amount):基础转账函数 - 演示事务的基本用法cursorNonetry:# 1. 获取游标cursorself.connection.cursor()# 2. 关闭自动提交开始事务self.connection.autocommit(False)# 或者用 self.connection.begin()logger.info(开始事务自动提交已关闭)# 3. 检查转出账户余额cursor.execute(SELECT balance FROM accounts WHERE account_no %s FOR UPDATE,(from_account,))resultcursor.fetchone()ifnotresult:raiseValueError(f账户{from_account}不存在)current_balanceresult[balance]ifcurrent_balanceamount:raiseValueError(f账户{from_account}余额不足当前余额:{current_balance})# 4. 执行转账操作# 扣款cursor.execute(UPDATE accounts SET balance balance - %s WHERE account_no %s,(amount,from_account))logger.info(f从账户{from_account}扣款{amount}元)# 加款cursor.execute(UPDATE accounts SET balance balance %s WHERE account_no %s,(amount,to_account))logger.info(f向账户{to_account}加款{amount}元)# 记录交易cursor.execute( INSERT INTO transactions (from_account, to_account, amount, transaction_type, status) VALUES (%s, %s, %s, TRANSFER, SUCCESS) ,(from_account,to_account,amount))# 5. 提交事务self.connection.commit()logger.info(事务提交成功)returnTrueexceptExceptionase:# 6. 发生异常回滚事务ifself.connection:self.connection.rollback()logger.warning(f事务回滚:{e})# 记录失败交易ifcursor:cursor.execute( INSERT INTO transactions (from_account, to_account, amount, transaction_type, status) VALUES (%s, %s, %s, TRANSFER, FAILED) ,(from_account,to_account,amount))self.connection.commit()returnFalsefinally:# 7. 恢复自动提交并关闭游标ifself.connection:self.connection.autocommit(True)ifcursor:cursor.close()# 测试代码if__name____main__:bankBankSystem()ifbank.connect():# 测试正常转账successbank.basic_transfer(1001,1002,1000)print(f转账结果:{成功ifsuccesselse失败})# 测试余额不足successbank.basic_transfer(1003,1001,5000)print(f转账结果:{成功ifsuccesselse失败})关键点解析autocommit(False)关闭自动提交开始事务FOR UPDATE加行锁防止其他事务修改commit()所有操作成功提交事务rollback()任何一步失败回滚所有操作finally块确保资源释放避免连接泄露3.2 事务的保存点复杂事务的后悔药对于复杂的多步骤事务我们可以设置保存点实现部分回滚defcomplex_transfer_with_savepoint(self,from_account,to_account,amount,fee0):带保存点的复杂转账含手续费cursorNonesavepoint_namebefore_fee_deductiontry:cursorself.connection.cursor()self.connection.autocommit(False)# 步骤1检查余额并扣款cursor.execute(SELECT balance FROM accounts WHERE account_no %s FOR UPDATE,(from_account,))resultcursor.fetchone()ifnotresult:raiseValueError(f账户{from_account}不存在)total_deductionamountfeeifresult[balance]total_deduction:raiseValueError(f余额不足需要{total_deduction}当前{result[balance]})# 扣款cursor.execute(UPDATE accounts SET balance balance - %s WHERE account_no %s,(amount,from_account))# 设置保存点cursor.execute(fSAVEPOINT{savepoint_name})logger.info(f保存点 {savepoint_name} 已创建)try:# 步骤2扣除手续费可能失败iffee0:cursor.execute(UPDATE accounts SET balance balance - %s WHERE account_no %s,(fee,from_account))logger.info(f手续费{fee}元已扣除)# 步骤3加款cursor.execute(UPDATE accounts SET balance balance %s WHERE account_no %s,(amount,to_account))# 记录交易cursor.execute( INSERT INTO transactions (from_account, to_account, amount, transaction_type, status) VALUES (%s, %s, %s, TRANSFER, SUCCESS) ,(from_account,to_account,amount))self.connection.commit()returnTrueexceptExceptionasfee_error:# 只回滚到保存点保留主扣款操作cursor.execute(fROLLBACK TO SAVEPOINT{savepoint_name})logger.warning(f手续费处理失败回滚到保存点:{fee_error})# 继续完成转账不含手续费cursor.execute(UPDATE accounts SET balance balance %s WHERE account_no %s,(amount,to_account))cursor.execute( INSERT INTO transactions (from_account, to_account, amount, transaction_type, status) VALUES (%s, %s, %s, TRANSFER, SUCCESS) ,(from_account,to_account,amount))self.connection.commit()returnTrue# 转账成功只是没收手续费exceptExceptionase:self.connection.rollback()logger.error(f转账失败:{e})returnFalsefinally:ifself.connection:self.connection.autocommit(True)ifcursor:cursor.close()四、事务隔离级别解决并发问题4.1 四种隔离级别对比隔离级别脏读不可重复读幻读性能适用场景READ UNCOMMITTED可能可能可能最高对数据一致性要求极低READ COMMITTED不可能可能可能高Oracle默认大多数场景REPEATABLE READ不可能不可能可能中MySQL默认需要一致性SERIALIZABLE不可能不可能不可能低金融交易绝对一致4.2 实战设置和验证隔离级别defdemonstrate_isolation_levels(self):演示不同隔离级别的影响# 设置隔离级别为 READ COMMITTEDwithself.connection.cursor()ascursor:cursor.execute(SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED)cursor.execute(SELECT transaction_isolation)resultcursor.fetchone()print(f当前隔离级别:{result[transaction_isolation]})# 测试不可重复读问题print(\n 测试不可重复读 )deftransaction1():事务1两次读取同一数据connpymysql.connect(hostlocalhost,userroot,passwordyour_password,databasebank_system,charsetutf8mb4)conn.autocommit(False)withconn.cursor()ascur:# 第一次读取cur.execute(SELECT balance FROM accounts WHERE account_no 1001)balance1cur.fetchone()[balance]print(f事务1第一次读取:{balance1})# 等待事务2修改数据importtime time.sleep(2)# 第二次读取在READ COMMITTED下这里会读到新值cur.execute(SELECT balance FROM accounts WHERE account_no 1001)balance2cur.fetchone()[balance]print(f事务1第二次读取:{balance2})ifbalance1!balance2:print(⚠️ 发生不可重复读两次读取结果不同)conn.commit()conn.close()deftransaction2():事务2修改数据importtime time.sleep(1)# 确保事务1先开始connpymysql.connect(hostlocalhost,userroot,passwordyour_password,databasebank_system,charsetutf8mb4)withconn.cursor()ascur:cur.execute(UPDATE accounts SET balance balance 100 WHERE account_no 1001)conn.commit()print(事务2已修改数据)conn.close()# 启动两个线程模拟并发importthreading t1threading.Thread(targettransaction1)t2threading.Thread(targettransaction2)t1.start()t2.start()t1.join()t2.join()常见问题脏读读到其他事务未提交的数据不可重复读同一事务内两次读取结果不同幻读同一查询条件第二次看到新插入的行五、异常处理的最佳实践5.1 完整的异常处理模板fromcontextlibimportcontextmanagerfromtypingimportOptional,Tuplecontextmanagerdeftransaction_context(connection,isolation_level:Optional[str]None): 事务上下文管理器 使用示例 with transaction_context(conn) as cursor: cursor.execute(UPDATE ...) cursorNoneoriginal_autocommitNoneoriginal_isolationNonetry:# 保存原始设置original_autocommitconnection.get_autocommit()ifisolation_level:withconnection.cursor()astemp_cursor:temp_cursor.execute(SELECT transaction_isolation)original_isolationtemp_cursor.fetchone()[transaction_isolation]temp_cursor.execute(fSET SESSION TRANSACTION ISOLATION LEVEL{isolation_level})# 开始事务connection.autocommit(False)cursorconnection.cursor()yieldcursor# 提交事务connection.commit()exceptExceptionase:# 回滚事务ifconnection:connection.rollback()logger.error(f事务执行失败:{e})raise# 重新抛出异常finally:# 恢复原始设置ifconnection:iforiginal_autocommitisnotNone:connection.autocommit(original_autocommit)ifisolation_levelandoriginal_isolation:withconnection.cursor()astemp_cursor:temp_cursor.execute(fSET SESSION TRANSACTION ISOLATION LEVEL{original_isolation})ifcursor:cursor.close()# 使用示例defsafe_transfer(self,from_account:str,to_account:str,amount:float)-Tuple[bool,str]:安全的转账函数使用上下文管理器try:withtransaction_context(self.connection,REPEATABLE READ)ascursor:# 检查余额cursor.execute(SELECT balance FROM accounts WHERE account_no %s FOR UPDATE,(from_account,))resultcursor.fetchone()ifnotresult:returnFalse,f账户{from_account}不存在ifresult[balance]amount:returnFalse,f余额不足当前余额:{result[balance]}# 执行转账cursor.execute(UPDATE accounts SET balance balance - %s WHERE account_no %s,(amount,from_account))cursor.execute(UPDATE accounts SET balance balance %s WHERE account_no %s,(amount,to_account))# 记录日志cursor.execute( INSERT INTO transactions (from_account, to_account, amount, transaction_type, status) VALUES (%s, %s, %s, TRANSFER, SUCCESS) ,(from_account,to_account,amount))returnTrue,转账成功exceptpymysql.Errorasdb_error:logger.error(f数据库错误:{db_error})returnFalse,f数据库错误:{db_error}exceptExceptionase:logger.error(f系统错误:{e})returnFalse,f系统错误:{e}5.2 常见异常及处理方案异常类型原因解决方案pymysql.err.IntegrityError违反唯一约束、外键约束1. 业务层校验 2. 捕获异常并提示用户pymysql.err.OperationalError连接超时、死锁1. 重试机制 2. 优化查询 3. 减少锁持有时间pymysql.err.DataError数据格式错误1. 参数校验 2. 使用参数化查询Deadlock found死锁1. 自动重试 2. 统一获取锁的顺序Lock wait timeout锁等待超时1. 增加超时时间 2. 优化事务大小defdeadlock_retry_transfer(self,from_account,to_account,amount,max_retries3):带死锁重试的转账函数forattemptinrange(max_retries):try:returnself.safe_transfer(from_account,to_account,amount)exceptpymysql.err.OperationalErrorase:# 错误码1213表示死锁ife.args[0]1213:wait_time(attempt1)*0.5# 指数退避logger.warning(f检测到死锁第{attempt1}次重试等待{wait_time}秒)importtime time.sleep(wait_time)continueelse:raise# 其他错误直接抛出exceptExceptionase:raisereturnFalse,转账失败超过最大重试次数六、实际项目应用电商订单系统让我们看一个真实的电商订单创建场景classOrderSystem:defcreate_order(self,user_id:int,items:list,shipping_address:str)-dict: 创建订单 - 完整的事务示例 涉及库存扣减、订单创建、支付记录 result{success:False,order_id:None,message:,errors:[]}try:withtransaction_context(self.connection)ascursor:# 1. 验证并锁定库存total_amount0foriteminitems:product_iditem[product_id]quantityitem[quantity]# 使用SELECT ... FOR UPDATE锁定库存行cursor.execute( SELECT stock, price FROM products WHERE id %s AND status ACTIVE FOR UPDATE ,(product_id,))productcursor.fetchone()ifnotproduct:raiseValueError(f商品{product_id}不存在或已下架)ifproduct[stock]quantity:raiseValueError(f商品{product_id}库存不足剩余:{product[stock]})total_amountproduct[price]*quantity# 2. 扣减库存foriteminitems:cursor.execute( UPDATE products SET stock stock - %s WHERE id %s AND stock %s ,(item[quantity],item[product_id],item[quantity]))affected_rowscursor.rowcountifaffected_rows0:raiseValueError(f商品{item[product_id]}库存扣减失败)# 3. 创建订单cursor.execute( INSERT INTO orders (user_id, total_amount, status, shipping_address) VALUES (%s, %s, PENDING, %s) ,(user_id,total_amount,shipping_address))order_idcursor.lastrowid# 4. 创建订单明细foriteminitems:cursor.execute( SELECT price FROM products WHERE id %s ,(item[product_id],))pricecursor.fetchone()[price]cursor.execute( INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES (%s, %s, %s, %s) ,(order_id,item[product_id],item[quantity],price))# 5. 记录订单日志cursor.execute( INSERT INTO order_logs (order_id, action, details) VALUES (%s, CREATED, %s) ,(order_id,f订单创建总金额:{total_amount}))result.update({success:True,order_id:order_id,message:订单创建成功})returnresultexceptValueErrorasve:# 业务逻辑错误result[message]str(ve)result[errors].append(str(ve))returnresultexceptpymysql.Errorasdbe:# 数据库错误logger.error(f数据库错误:{dbe})result[message]系统错误请稍后重试result[errors].append(str(dbe))returnresultexceptExceptionase:# 其他未知错误logger.error(f未知错误:{e})result[message]系统异常请联系客服result[errors].append(str(e))returnresult七、学习总结与避坑指南7.1 关键要点回顾始终使用事务对于多个相关操作一定要放在事务中及时提交或回滚避免长事务占用连接资源合理选择隔离级别默认REPEATABLE READ适合大多数场景使用上下文管理器确保资源正确释放处理死锁实现重试机制统一锁获取顺序7.2 常见坑点及解决方案坑点1忘记提交或回滚# ❌ 错误忘记提交conn.autocommit(False)cursor.execute(UPDATE ...)# 忘记 conn.commit() 或 conn.rollback()# 连接关闭时MySQL会自动回滚但可能持有锁时间过长# ✅ 正确使用with语句或try-finallywithtransaction_context(conn)ascursor:cursor.execute(UPDATE ...)坑点2在事务中执行DDL语句# ❌ 错误事务中执行CREATE TABLEconn.begin()cursor.execute(UPDATE accounts ...)cursor.execute(CREATE TABLE temp ...)# DDL语句会隐式提交cursor.execute(INSERT INTO temp ...)# 这行不在事务中了# ✅ 正确分开执行cursor.execute(CREATE TABLE temp ...)# 先执行DDLconn.begin()# 再开始事务cursor.execute(UPDATE accounts ...)cursor.execute(INSERT INTO temp ...)conn.commit()坑点3未处理连接异常# ❌ 错误没有连接健康检查deftransfer_money():cursorconn.cursor()# 如果连接已断开这里会报错# ✅ 正确添加连接检查deftransfer_money():ifnotconn.open:conn.ping(reconnectTrue)# 尝试重连cursorconn.cursor()学习交流与进阶恭喜你现在你已经掌握了Python MySQL事务管理的核心技能。事务是数据库编程中最重要也最容易出错的部分多练习才能真正掌握。欢迎在评论区分享你在项目中遇到过哪些事务相关的问题文中的转账示例你运行成功了吗对于死锁处理你有什么实战经验我会挑选典型问题详细解答。记住数据库学习最好的方式就是动手实践推荐学习资源MySQL官方文档 - 事务 - 最权威的事务原理pymysql事务示例 - 官方代码参考《高性能MySQL》 - 深入理解MySQL内部机制下篇预告下一篇将分享《Python MySQL连接池实战》教你30分钟搞定DBUtils PooledDB告别连接超时最后的小建议我刚开始学事务时总想着这个简单理解了。结果第一次上线就遇到死锁。后来我养成了习惯每个事务代码写完都要问自己三个问题1. 异常时能正确回滚吗2. 会死锁吗3. 持有锁的时间长吗这三个问题能帮你避开80%的坑。现在打开你的IDE把今天的示例代码跑起来吧遇到问题随时回来讨论。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

网站设计网站浏览网站建设茶店网

原神帧率解锁工具深度解析:突破60fps限制的完整解决方案 【免费下载链接】genshin-fps-unlock unlocks the 60 fps cap 项目地址: https://gitcode.com/gh_mirrors/ge/genshin-fps-unlock 《原神》作为一款画面精美、开放世界体验丰富的游戏,其60…

张小明 2026/1/6 4:48:17 网站建设

如何在网站上做咨询浮动窗口那种网站怎么搜关键词

背景分析随着城市化进程加快,大量外来务工人员涌入城市社区,给社区管理带来新挑战。传统手工登记、纸质档案管理方式效率低下,信息更新滞后,难以满足动态化管理需求。社区管理人员缺乏有效工具跟踪流动人口信息,导致政…

张小明 2026/1/5 16:17:22 网站建设

网课系统软件网站建设费用广州番禺专业做网站

还在为特定场景的图像分割任务找不到合适数据集而烦恼吗?想要让FastSAM模型精准识别你的专属目标吗?🚀 本文将为你呈现一套完整的FastSAM自定义数据集制作方案,从数据收集到模型训练,手把手教你打造专属分割模型。Fast…

张小明 2026/1/6 5:49:23 网站建设

有移动端网站 怎么做app临沂seo推广外包

Android开发:NFC、手势输入、无障碍功能及通信同步全解析 1. NFC通信模式 在Android 2.3.3+(API级别10)中,当一台设备设置为通过NFC向另一台能够接收NFC数据的设备传输数据时,就启用了P2P模式。发送设备也可以从接收设备接收数据,从而实现对等(P2P)通信。 1.1 API级…

张小明 2026/1/6 5:49:16 网站建设

岳池住房和城乡建设厅网站电话营销话术

开发日记:大文件上传系统攻坚记 日期:2023年XX月XX日 天气:晴(但心情像在调试IE8的阴天) 一、需求拆解:从"不可能"到"可能" 客户的需求像一座高山: 20G文件传输&#xff…

张小明 2026/1/6 4:52:43 网站建设