已阅读5页,还剩11页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Mysql事务处理博客分类: 数据库MySQLOracleSQL设计模式一、事务【定义】事务:是指作为单个逻辑工作单元执行的一系列操作 当前mysql的存储引擎中只有innodb和BDB实现了事务的ACID,并且实现机制和oracle是一致的,主要使用了mvcc的实现理论。 mysql的事务分两种,一种是标准的事务,也叫normal transaction ,还有一个叫statement transaction。其中normal transaction是标准的实现ACID的事务,而statement transaction是就是一个语句是一个事务。平时我们可以设置mysql autocommit为true,其实这里是只有statement transaction,没有normal transaction,就是把每个statement transaction当作一个normal transaction。MYSQL的事务处理主要有两种方法: 1、用begin,rollback,commit来实现 begin 开始一个事务 rollback 事务回滚 commit 事务确认 2、直接用set来改变mysql的自动提交模式 MYSQL默认是自动提交的,也就是你提交一个QUERY,它就直接执行!我们可以通过 set autocommit=0 禁止自动提交 set autocommit=1 开启自动提交 来实现事务的处理。 当你用 set autocommit=0 的时候,你以后所有的SQL都将做为事务处理,直到你用commit确认或rollback结束。 注意当你结束这个事务的同时也开启了个新的事务!按第一种方法只将当前的作为一个事务! 常用的是第一种方法!二、定义事务MySQL默认的行为是在每条SQL语句执行后执行一个COMMIT语句,从而有效的将每条语句独立为一个事务。在复杂的应用场景下这种方式就不能满足需求了。为了打开事务,允许在COMMIT和ROLLBACK之前多条语句被执行,我们需要做以下两步:1, 设置MySQL的autocommit属性为0,默认为12,使用START TRANSACTION语句显式的打开一个事务如果已经打开一个事务,则SET autocommit=0不会起作用,因为START TRANSACTION会隐式的提交session中所有当前的更改,结束已有的事务,并打开一个新的事务。使用SET AUTOCOMMIT语句的存储过程例子:Java代码1. CREATEPROCEDUREtfer_funds 2. (from_accountint,to_accountint,tfer_amountnumeric(10,2) 3. BEGIN 4. SETautocommit=0; 5. 6. UPDATEaccount_balanceSETbalance=balance-tfer_amountWHEREaccount_id=from_account; 7. 8. UPDATEaccount_balanceSETbalance=balance+tfer_amountWHEREaccount_id=to_account; 9. 10. COMMIT; 11. END;Java代码1. CREATEPROCEDUREtfer_funds 2. (from_accountint,to_accountint,tfer_amountnumeric(10,2) 3. BEGIN 4. SETautocommit=0; 5. 6. UPDATEaccount_balanceSETbalance=balance-tfer_amountWHEREaccount_id=from_account; 7. 8. UPDATEaccount_balanceSETbalance=balance+tfer_amountWHEREaccount_id=to_account; 9. 10. COMMIT; 11. END;使用START TRANSACITON打开事务的例子:Java代码1. CREATEPROCEDUREtfer_funds 2. (from_accountint,to_accountint,tfer_amountnumeric(10,2) 3. BEGIN 4. STARTTRANSACTION; 5. 6. UPDATEaccount_balanceSETbalance=balance-tfer_amountWHEREaccount_id=from_account; 7. 8. UPDATEaccount_balanceSETbalance=balance+tfer_amountWHEREaccount_id=to_account; 9. 10. COMMIT; 11. END;Java代码1. CREATEPROCEDUREtfer_funds 2. (from_accountint,to_accountint,tfer_amountnumeric(10,2) 3. BEGIN 4. STARTTRANSACTION; 5. 6. UPDATEaccount_balanceSETbalance=balance-tfer_amountWHEREaccount_id=from_account; 7. 8. UPDATEaccount_balanceSETbalance=balance+tfer_amountWHEREaccount_id=to_account; 9. 10. COMMIT; 11. END;通常COMMIT或ROLLBACK语句执行时才完成一个事务,但是有些DDL语句等会隐式触发COMMIT,所以应该在事务中尽可能少用或注意一下:Java代码1. ALTERFUNCTION 2. ALTERPROCEDURE 3. ALTERTABLE 4. BEGIN 5. CREATEDATABASE 6. CREATEFUNCTION 7. CREATEINDEX 8. CREATEPROCEDURE 9. CREATETABLE 10. DROPDATABASE 11. DROPFUNCTION 12. DROPINDEX 13. DROPPROCEDURE 14. DROPTABLE 15. UNLOCKTABLES 16. LOADMASTERDATA 17. LOCKTABLES 18. RENAMETABLE 19. TRUNCATETABLE 20. SETAUTOCOMMIT=1 21. STARTTRANSACTIONJava代码1. ALTERFUNCTION 2. ALTERPROCEDURE 3. ALTERTABLE 4. BEGIN 5. CREATEDATABASE 6. CREATEFUNCTION 7. CREATEINDEX 8. CREATEPROCEDURE 9. CREATETABLE 10. DROPDATABASE 11. DROPFUNCTION 12. DROPINDEX 13. DROPPROCEDURE 14. DROPTABLE 15. UNLOCKTABLES 16. LOADMASTERDATA 17. LOCKTABLES 18. RENAMETABLE 19. TRUNCATETABLE 20. SETAUTOCOMMIT=1 21. STARTTRANSACTION3,使用Savepoint使用savepoint回滚难免有些性能消耗,一般可以用IF改写savepoint的良好使用的场景之一是“嵌套事务”,你可能希望程序执行一个小的事务,但是不希望回滚外面更大的事务:Java代码1. CREATEPROCEDUREnested_tfer_funds 2. (in_from_acctINTEGER, 3. in_to_acctINTEGER, 4. in_tfer_amountDECIMAL(8,2) 5. BEGIN 6. DECLAREtxn_errorINTEGERDEFAULT0; 7. 8. DECLARECONTINUEHANDLERFORSQLEXCEPTIONBEGIN 9. SETtxn_error=1; 10. END 11. 12. SAVEPINTsavepint_tfer; 13. 14. UPDATEaccount_balance 15. SETbalance=balance-in_tfer_amount 16. WHEREaccount_id=in_from_acct; 17. 18. IFtxn_errorTHEN 19. ROLLBACKTOsavepoint_tfer; 20. SELECTTransferaborted; 21. ELSE 22. UPDATEaccount_balance 23. SETbalance=balance+in_tfer_amount 24. WHEREaccount_id=in_to_acct; 25. 26. IFtxn_errorTHEN 27. ROLLBACKTOsavepoint_tfer; 28. SELECTTransferaborted; 29. 30. ENDIF: 31. ENDIF; 32. END;Java代码1. CREATEPROCEDUREnested_tfer_funds 2. (in_from_acctINTEGER, 3. in_to_acctINTEGER, 4. in_tfer_amountDECIMAL(8,2) 5. BEGIN 6. DECLAREtxn_errorINTEGERDEFAULT0; 7. 8. DECLARECONTINUEHANDLERFORSQLEXCEPTIONBEGIN 9. SETtxn_error=1; 10. END 11. 12. SAVEPINTsavepint_tfer; 13. 14. UPDATEaccount_balance 15. SETbalance=balance-in_tfer_amount 16. WHEREaccount_id=in_from_acct; 17. 18. IFtxn_errorTHEN 19. ROLLBACKTOsavepoint_tfer; 20. SELECTTransferaborted; 21. ELSE 22. UPDATEaccount_balance 23. SETbalance=balance+in_tfer_amount 24. WHEREaccount_id=in_to_acct; 25. 26. IFtxn_errorTHEN 27. ROLLBACKTOsavepoint_tfer; 28. SELECTTransferaborted; 29. 30. ENDIF: 31. ENDIF; 32. END;4,事务和锁事务的ACID属性只能通过限制数据库的同步更改来实现,从而通过对修改数据加锁来实现。直到事务触发COMMIT或ROLLBACK语句时锁才释放。缺点是后面的事务必须等前面的事务完成才能开始执行,吞吐量随着等待锁释放的时间增长而递减。MySQL/InnoDB通过行级锁来最小化锁竞争。这样修改同一table里其他行的数据没有限制,而且读数据可以始终没有等待。可以在SELECT语句里使用FOR UPDATE或LOCK IN SHARE MODE语句来加上行级锁Java代码1. SELECTselect_statementoptionsFORUPDATE|LOCKINSHAREMODEJava代码1. SELECTselect_statementoptionsFORUPDATE|LOCKINSHAREMODEFOR UPDATE会锁住该SELECT语句返回的行,其他SELECT和DML语句必须等待该SELECT语句所在的事务完成LOCK IN SHARE MODE同FOR UPDATE,但是允许其他session的SELECT语句执行并允许获取SHARE MODE锁死锁:死锁发生于两个事务相互等待彼此释放锁的情景当MySQL/InnoDB检查到死锁时,它会强制一个事务rollback并触发一条错误消息对InnoDB而言,所选择的rollback的事务是完成工作最少的事务(所修改的行最少)Java代码1. mysqlCALLtfer_funds(1,2,300); 2. ERROR1213(40001):Deadlockfoundwhentryingtogetlock;tryrestartingtransactionJava代码1. mysqlCALLtfer_funds(1,2,300); 2. ERROR1213(40001):Deadlockfoundwhentryingtogetlock;tryrestartingtransaction死锁在任何数据库系统里都可能发生,但是对MySQL/InnoDB这种行级锁数据库而言可能性相对较少。可以通过使用一致的顺序来锁row或table以及让事务保持尽可能短来减少死锁的频率。如果死锁不容易debug,你可以向你的程序中添加一些逻辑来处理死锁并重试事务,但这部分代码多了以后很难维护所以,比较好的避免死锁的方式是在做任何修改之前按一定的顺序添加行级锁,这样就能避免死锁:Java代码1. CREATEPROCEDUREtfer_funds3 2. (from_accountINT,to_accountINT,tfer_amountNUMERIC(10,2) 3. BEGIN 4. DECLARElocal_account_idINT; 5. DECLARElock_cursorCURSORFOR 6. SELECTaccount_id 7. FROMaccount_balance 8. WHEREaccount_idIN(from_account,to_account) 9. ORDERBYaccount_id 10. FORUPDATE; 11. 12. STARTTRANSACTION; 13. 14. OPENlock_cursor; 15. FETCHlock_cursorINTOlocal_account_id; 16. 17. UPDATEaccount_balance 18. SETbalance=balance-tfer_amount 19. WHEREaccount_id=from_account; 20. 21. UPDATEaccount_balance 22. SETbalance=balance+tfer_amount 23. WHEREaccount_id=to_account; 24. 25. CLOSElock_cursor; 26. 27. COMMIT; 28. END;Java代码1. CREATEPROCEDUREtfer_funds3 2. (from_accountINT,to_accountINT,tfer_amountNUMERIC(10,2) 3. BEGIN 4. DECLARElocal_account_idINT; 5. DECLARElock_cursorCURSORFOR 6. SELECTaccount_id 7. FROMaccount_balance 8. WHEREaccount_idIN(from_account,to_account) 9. ORDERBYaccount_id 10. FORUPDATE; 11. 12. STARTTRANSACTION; 13. 14. OPENlock_cursor; 15. FETCHlock_cursorINTOlocal_account_id; 16. 17. UPDATEaccount_balance 18. SETbalance=balance-tfer_amount 19. WHEREaccount_id=from_account; 20. 21. UPDATEaccount_balance 22. SETbalance=balance+tfer_amount 23. WHEREaccount_id=to_account; 24. 25. CLOSElock_cursor; 26. 27. COMMIT; 28. END;设置死锁ttl: innodb_lock_wait_timeout,默认为50秒如果你在一个事务中混合使用InnoDB和非InnoDB表,则MySQL不能检测到死锁,此时会抛出“lock wait timeuot”1205错误乐观所和悲观锁策略:悲观锁:在读取数据时锁住那几行,其他对这几行的更新需要等到悲观锁结束时才能继续乐观所:读取数据时不锁,更新时检查是否数据已经被更新过,如果是则取消当前更新一般在悲观锁的等待时间过长而不能接受时我们才会选择乐观锁悲观锁的例子:Java代码1. CREATEPROCEDUREtfer_funds 2. (from_accountINT,to_accountINT,tfer_amountNUMERIC(10,2), 3. OUTstatusINT,OUTmessageVARCHAR(30) 4. BEGIN 5. DECLAREfrom_account_balanceNUMERIC(10,2); 6. 7. STARTTRANSACTION; 8. 9. 10. SELECTbalance 11. INTOfrom_account_balance 12. FROMaccount_balance 13. WHEREaccount_id=from_account 14. FORUPDATE; 15. 16. IFfrom_account_balance=tfer_amountTHEN 17. 18. UPDATEaccount_balance 19. SETbalance=balance-tfer_amount 20. WHEREaccount_id=from_account; 21. 22. UPDATEaccount_balance 23. SETbalance=balance+tfer_amount 24. WHEREaccount_id=to_account; 25. COMMIT; 26. 27. SETstatus=0; 28. SETmessage=OK; 29. ELSE 30. ROLLBACK; 31. SETstatus=-1; 32. SETmessage=Insufficientfunds; 33. ENDIF; 34. END;Java代码1. CREATEPROCEDUREtfer_funds 2. (from_accountINT,to_accountINT,tfer_amountNUMERIC(10,2), 3. OUTstatusINT,OUTmessageVARCHAR(30) 4. BEGIN 5. DECLAREfrom_account_balanceNUMERIC(10,2); 6. 7. STARTTRANSACTION; 8. 9. 10. SELECTbalance 11. INTOfrom_account_balance 12. FROMaccount_balance 13. WHEREaccount_id=from_account 14. FORUPDATE; 15. 16. IFfrom_account_balance=tfer_amountTHEN 17. 18. UPDATEaccount_balance 19. SETbalance=balance-tfer_amount 20. WHEREaccount_id=from_account; 21. 22. UPDATEaccount_balance 23. SETbalance=balance+tfer_amount 24. WHEREaccount_id=to_account; 25. COMMIT; 26. 27. SETstatus=0; 28. SETmessage=OK; 29. ELSE 30. ROLLBACK; 31. SETstatus=-1; 32. SETmessage=Insufficientfunds; 33. ENDIF; 34. END;乐观锁的例子:Java代码1. CREATEPROCEDUREtfer_funds 2. (from_accountINT,to_accountINT,tfer_amountNUMERIC(10,2), 3. OUTstatusINT,OUTmessageVARCHAR(30) 4. 5. BEGIN 6. 7. DECLAREfrom_account_balanceNUMERIC(8,2); 8. DECLAREfrom_account_balance2NUMERIC(8,2); 9. DECLAREfrom_account_timestamp1TIMESTAMP; 10. DECLAREfrom_account_timestamp2TIMESTAMP; 11. 12. SELECTaccount_timestamp,balance 13. INTOfrom_account_timestamp1,from_account_balance 14. FROMaccount_balance 15. WHEREaccount_id=from_account; 16. 17. IF(from_account_balance=tfer_amount)THEN 18. 19. -Hereweperformsomelongrunningvalidationthat 20. -mighttakeafewminutes*/ 21. CALLlong_running_validation(from_account); 22. 23. STARTTRANSACTION; 24. 25. -Makesuretheaccountrowhasnotbeenupdatedsince 26. -ourinitialcheck 27. SELECTaccount_timestamp,balance 28. INTOfrom_account_timestamp2,from_account_balance2 29. FROMaccount_balance 30. WHEREaccount_id=from_account 31. FORUPDATE; 32. 33. IF(from_account_timestamp1from_account_timestamp2OR 34. from_account_balancefrom_account_balance2)THEN 35. ROLLBACK; 36. SETstatus=-1; 37. SETmessage=CONCAT(Transactioncancelledduetoconcurrentupdate, 38. ofaccount,from_account); 39. ELSE 40. UPDATEaccount_balance 41. SETbalance=balance-tfer_amount 42. WHEREaccount_id=from_account; 43. 44. UPDATEaccount_balance 45. SETbalance=balance+tfer_amount 46. WHEREaccount_id=to_account; 47. 48. COMMIT; 49. 50. SETstatus=0; 51. SETmessage=OK; 52. ENDIF; 53. 54. ELSE 55. ROLLBACK; 56. SETstatus=-1; 57. SETmessage=Insufficientfunds; 58. ENDIF; 59. END$Java代码1. CREATEPROCEDUREtfer_funds 2. (from_accountINT,to_accountINT,tfer_amountNUMERIC(10,2), 3. OUTstatusINT,OUTmessageVARCHAR(30) 4. 5. BEGIN 6. 7. DECLAREfrom_account_balanceNUMERIC(8,2); 8. DECLAREfrom_account_balance2NUMERIC(8,2); 9. DECLAREfrom_account_timestamp1TIMESTAMP; 10. DECLAREfrom_account_timestamp2TIMESTAMP; 11. 12. SELECTaccount_timestamp,balance 13. INTOfrom_account_timestamp1,from_account_balance 14. FROMaccount_balance 15. WHEREaccount_id=from_a
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025山东菏泽市第三人民医院第二批招聘编制备案制人员3人参考笔试题库及答案解析
- 2025山东济南新旧动能转换起步区社工招聘30人备考题库完整答案详解
- 2025年玉环市未来新城开发建设中心事业单位公开选聘工作人员1人参考模拟试题及答案解析
- 2025福建三明市将乐县社区工作者招考13人备考题库及答案详解(真题汇编)
- 2025浙江绍兴市外服人力资源服务有限公司聘用制人员招聘4人备考考点试题及答案解析
- 2025广东深圳医学科学院睡眠与意识课题组(丹扬课题组)招聘博士后参考笔试题库及答案解析
- 2025北京一零一中温泉校区招聘参考模拟试题及答案解析
- 2025年安徽水安投资控股有限公司第2批次社会招聘4人备考考点题库及答案解析
- 2025大东区总工会社区工作者招聘备考题库带答案详解
- 儿科CRISPR脱靶效应的精准评估策略-1
- GB/T 7000.217-2023灯具第2-17部分:特殊要求舞台灯光、电视、电影及摄影场所(室内外)用灯具
- 牧场粪污处理原则与工艺
- 北京市海淀区2023-2024学年高三上学期期中考试英语试题【含答案解析】
- 物业公司年度财务预算模板
- 黄瓜杂交种子生产技术
- 四川省自然保护区生物多样性与保护技术研究
- 彭泽县金升铜矿采矿权出让收益评估报告书
- 医学影像学教学课件:急腹症 Acute Abdomen
- YS/T 568.7-2008氧化锆、氧化铪化学分析方法磷量的测定锑盐-抗坏血酸-磷钼蓝分光光度法
- GB 25558-2010食品安全国家标准食品添加剂磷酸三钙
- 兵团屯垦戍边事业课件
评论
0/150
提交评论