1.MySQL 核心模块揭秘 | 12 期 | 创建 savepoint
2.innodbåmyisamçåºå«
3.MySql轻松入门系列——第二站 使用visual studio 对mysql进行源码级调试
4.MySQL 核心模块揭秘 | 13 期 | 回滚到 savepoint
5.源码详解系列(四) ------ DBCP2的源码使用和分析(包括JNDI和JTA支持)已停更
MySQL 核心模块揭秘 | 12 期 | 创建 savepoint
回滚操作,除了回滚整个事务,源码还可以部分回滚。源码部分回滚,源码需要保存点(savepoint)的源码协助。本文我们先看看保存点里面都有什么。源码垃圾识别小车源码
作者:操盛春,源码爱可生技术专家,源码公众号『一树一溪』作者,源码专注于研究 MySQL 和 OceanBase 源码。源码 爱可生开源社区出品,源码原创内容未经授权不得随意使用,源码转载请联系小编并注明来源
本文基于 MySQL 8.0. 源码,源码存储引擎为 InnoDB。源码
InnoDB 的源码事务对象有一个名为undo_no 的属性。事务每次改变(插入、更新、删除)某个表的一条记录,都会产生一条 undo 日志。这条 undo 日志中会存储它自己的序号。这个序号就来源于事务对象的 undo_no 属性。
也就是说,事务对象的 undo_no 属性中保存着事务改变(插入、更新、删除)某个表中下一条记录产生的 undo 日志的序号。
每个事务都维护着各自独立的 undo 日志序号,和其它事务无关。
每个事务的 undo 日志序号都从 0 开始。事务产生的第 1 条 undo 日志的序号为 0,第 2 条 undo 日志的夜白源码序号为 1,依此类推。
InnoDB 的 savepoint 结构中会保存创建 savepoint 时事务对象的 undo_no 属性值。
我们通过 SQL 语句创建一个 savepoint 时,server 层、binlog、InnoDB 会各自创建用于保存 savepoint 信息的结构。
server 层的 savepoint 结构是一个SAVEPOINT 类型的对象,主要属性如下:
binlog 的 savepoint 结构很简单,是一个 8 字节的整数。这个整数的值,是创建 savepoint 时事务已经产生的 binlog 日志的字节数,也是接下来新产生的 binlog 日志写入 trx_cache 的 offset。
为了方便介绍,我们把这个整数值称为binlog offset。
InnoDB 的 savepoint 结构是一个trx_named_savept_t 类型的对象,主要属性如下:
创建 savepoint 时,server 层会分配一块 字节的内存,除了存放它自己的 SAVEPOINT 对象,还会存放 binlog offset 和 InnoDB 的 trx_named_savept_t 对象。
server 层的 SAVEPOINT 对象占用这块内存的前 字节,InnoDB 的 trx_named_savept_t 对象占用中间的 字节,binlog offset 占用最后的 8 字节。
客户端连接到 MySQL 之后,MySQL 会分配一个专门用于该连接的用户线程。
用户线程中有一个m_savepoints 链表,用户创建的多个 savepoint 通过 prev 属性形成链表,m_savepoints 就指向最新创建的 savepoint。
server 层创建 savepoint 之前,会按照创建时间从新到老,大龙摆尾源码逐个查看链表中是否存在和本次创建的 savepoint 同名的 savepoint。
如果在用户线程的 m_savepoints 链表中找到了和本次创建的 savepoint 同名的 savepoint,需要先删除 m_savepoints 链表中的同名 savepoint。
找到的同名 savepoint,是 server 层的SAVEPOINT 对象,它后面的内存区域分别保存着 InnoDB 的 trx_named_savept_t 对象、binlog offset。
binlog 是个老实孩子,乖乖的把 binlog offset 写入了 server 层为它分配的内存里。删除同名 savepoint 时,不需要单独处理 binlog offset。
InnoDB 就不老实了,虽然 server 层也为 InnoDB 的 trx_named_savept_t 对象分配了内存,但是 InnoDB 并没有往里面写入内容。
事务执行过程中,用户每次创建一个 savepoint,InnoDB 都会创建一个对应的 trx_named_savept_t 对象,并加入 InnoDB 事务对象的 trx_savepoints 链表的末尾。
因为 InnoDB 自己维护了一个存放 savepoint 结构的链表,server 层删除同名 savepoint 时,InnoDB 需要找到这个链表中对应的 savepoint 结构并删除,流程如下:
InnoDB 从事务对象的 trx_savepoints 链表中删除 trx_named_savept_t 对象之后,server 层接着从用户线程的 m_savepoints 链表中删除 server 层的SAVEPOINT 对象,也就连带着清理了 binlog offset。
处理完查找、删除同名 savepoint 之后,server 层就正式开始创建 savepoint 了,这个过程分为 3 步。
第 1 步,找对象源码binlog 会生成一个 Query_log_event。
以创建名为test_savept 的 savepoint 为例,这个 event 的内容如下:
binlog event 写入 trx_cache 之后,binlog offset 会写入 server 层为它分配的 8 字节的内存中。
第 2 步,InnoDB 创建 trx_named_savept_t 对象,并放入事务对象的 trx_savepoints 链表的末尾。
trx_named_savept_t 对象的 name 属性值是 InnoDB 的 savepoint 名字。这个名字是根据 server 层为 InnoDB 的 trx_named_savept_t 对象分配的内存的地址计算得到的。
trx_named_savept_t 对象的savept 属性,是一个 trx_savept_t 类型的对象。这个对象里保存着创建 savepoint 时,事务对象中 undo_no 属性的值,也就是下一条 undo 日志的序号。
第 3 步,把 server 层的 SAVEPOINT 对象加入用户线程的 m_savepoints 链表的尾部。
server 层会创建一个SAVEPOINT 对象,用于存放 savepoint 信息。
binlog 会把binlog offset 写入 server 层为它分配的一块 8 字节的内存里。
InnoDB 会维护自己的 savepoint 链表,里面保存着trx_named_savept_t 对象。
如果 m_savepoints 链表中存在和本次创建的 savepoint 同名的 savepoint, 创建新的 savepoint 之前,server 层会从链表中删除这个同名的 savepoint。
server 层创建的 SAVEPOINT 对象会放入m_savepoints 链表的末尾。
InnoDB 创建的 trx_named_savept_t 对象会放入事务对象的trx_savepoints 链表的末尾。
innodbåmyisamçåºå«
InnoDBMyISAM使ç¨MySQLç¨ä¸¤è¡¨ç±»ååä¼ç¼ºç¹è§å ·ä½åºç¨å®åºæ¬å·®å«ï¼MyISAMç±»åæ¯æäºå¡å¤ççé«çº§å¤çInnoDBç±»åæ¯æMyISAMç±»å表强è°æ§è½å ¶æ§è¡æ°åº¦æ¯InnoDBç±»åæ´å¿«æä¾äºå¡æ¯æInnoDBæä¾äºå¡æ¯æå·²ç»å¤é¨é®çé«çº§æ°æ®åºåè½ããMyIASMIASM表æ°çæ¬æ©å±ï¼ããäºè¿å¶å±ç§»æ¤æ§ããNULLåç´¢å¼ããåè¡æ¯ISAM表æ´å°ç¢çããæ¯ææ件ããæ´ç´¢å¼å缩ããæ´é®ç»è®¡å¸ããæ´æ´å¿«auto_incrementå¤çããäºç»èå ·ä½å®ç°å·®å«ï¼ãã1.InnoDBæ¯æFULLTEXTç±»åç´¢å¼ãã2.InnoDBä¿åè¡¨å ·ä½è¡æ°è¯´æ§è¡select count(*) from tableInnoDBè¦æ«æéæ´è¡¨è®¡ç®å°è¡MyISAMè¦ç®å读ä¿åè¡æ°å³æ³¨æcount(*)è¯å¥å å«whereæ¡ä»¶ä¸¤ç§è¡¨æä½ãã3.äºAUTO_INCREMENTç±»åå段InnoDBå¿ é¡»å å«è¯¥å段索å¼MyISAMè¡¨å ¶å段起建ç«èåç´¢å¼ãã4.DELETE FROM tableInnoDBéæ°å»ºç«è¡¨è¡è¡å é¤ãã5.LOAD TABLE FROM MASTERæä½InnoDBèµ·ä½ç¨è§£å³é¦å InnoDB表æ¹MyISAMè¡¨å¯¼å ¥æ°æ®åæ¹InnoDB表äºä½¿ç¨é¢å¤InnoDBç¹æ§ï¼ä¾å¤é®ï¼è¡¨éç¨ããå¦å¤InnoDB表è¡éç»æ§è¡SQLè¯å¥MySQLè½ç¡®å®è¦æ«æèå´InnoDB表åéå ¨è¡¨ä¾update table set num=1 where name like %aaa%ããä»»ä½ç§è¡¨é½ä¸è½ç¨æ°éä¸å¡ç±»åéæ©åé表类åæè½åæ¥MySQLæ§è½ä¼å¿.ããããMySQLMyISAMå¼æä¸InnoDBå¼ææ§è½ç®åæµè¯ãã[硬件é ç½®]ããCPU : AMD+ (1.8G)ããå å: 1G/ç°ä»£ãã硬ç: G/IDEãã[软件é ç½®]ããOS : Windows XP SP2ããSE : PHP5.2.1ããDB : MySQL5.0.ããWeb: IIS6ãã[MySQL表ç»æ]ããCREATE TABLE `myisam` (ãã`id` int() NOT NULL auto_increment,ãã`name` varchar() default NULL,ãã`content` text,ããPRIMARY KEY (`id`)ãã) ENGINE=MyISAM DEFAULT CHARSET=gbk;ããCREATE TABLE `innodb` (ãã`id` int() NOT NULL auto_increment,ãã`name` varchar() default NULL,ãã`content` text,ããPRIMARY KEY (`id`)ãã) ENGINE=InnoDB DEFAULT CHARSET=gbk;ãã[æ°æ®å 容]ãã$name = "heiyeluren";ãã$content = "MySQLæ¯ææ°åå¨å¼æä½å表类åå¤çå¨MySQLåå¨å¼æå æ¬å¤çäºå¡å®å ¨è¡¨å¼æå¤çéäºå¡å®å ¨è¡¨å¼æï¼Â· MyISAM管çéäºå¡è¡¨æä¾é«éåå¨æ£ç´¢åå ¨ææç´¢è½åMyISAMæMySQLé ç½®æ¯æé»è®¤åå¨å¼æé¤éé ç½®MySQLé»è®¤ä½¿ç¨å¦å¤å¼æ ·MEMORYåå¨å¼ææä¾å å表MERGEåå¨å¼æå 许éåå¤çåMyISAM表ä½åç¬è¡¨åMyISAMMEMORYMERGEåå¨å¼æå¤çéäºå¡è¡¨ä¸¤å¼æé½é»è®¤å å«MySQL éï¼MEMORYåå¨å¼æå¼ç¡®å®HEAPå¼æ· InnoDBBDBåå¨å¼ææä¾äºå¡å®å ¨è¡¨BDBå å«æ¯ææä½ç³»ç»åå¸MySQL-Maxäºè¿å¶åçInnoDBé»è®¤å æ¬æMySQL 5.1äºè¿å¶åçæç §åéé ç½®MySQLå 许æç¦æ¢ä»»å¼æ·EXAMPLEåå¨å¼æåæ ¹å¼æåç¨å¼æå建表没æ°æ®åå¨äºå ¶æå ¶æ£ç´¢å¼æç®æå¡MySQLæºä»£ç ä¾æ¼ç¤ºè¯´æä½å§ç¼åæ°åå¨å¼æå主è¦å ´è¶£åè ";ãã[æå ¥æ°æ®-1] (innodb_flush_log_at_trx_commit=1)ããMyISAM 1Wï¼3/sããInnoDB 1Wï¼/sããMyISAM Wï¼/sããInnoDB Wï¼/sããMyISAM Wï¼/sããInnoDB Wï¼æ²¡æ¢æµè¯ãã[æå ¥æ°æ®-2] (innodb_flush_log_at_trx_commit=0)ããMyISAM 1Wï¼3/sããInnoDB 1Wï¼3/sããMyISAM Wï¼/sããInnoDB Wï¼/sããMyISAM Wï¼/sããInnoDB Wï¼/sãã[æå ¥æ°æ®3] (innodb_buffer_pool_size=M)ããInnoDB 1Wï¼3/sããInnoDB Wï¼/sããInnoDB Wï¼/sãã[æå ¥æ°æ®4] (innodb_buffer_pool_size=M, innodb_flush_log_at_trx_commit=1, set autocommit=0)ããInnoDB 1Wï¼3/sããInnoDB Wï¼/sããInnoDB Wï¼/sãã[MySQL é ç½®æ件] (缺çé ç½®)ãã# MySQL Server Instance Configuration Fileãã[client]ããport=ãã[mysql]ããdefault-character-set=gbkãã[mysqld]ããport=ããbasedir="C:/mysql/"ããdatadir="C:/mysql/Data/"ããdefault-character-set=gbkããdefault-storage-engine=INNODBããsql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"ããmax_connections=ããquery_cache_size=0ããtable_cache=ããtmp_table_size=Mããthread_cache_size=8ããmyisam_max_sort_file_size=Gããmyisam_max_extra_sort_file_size=Gããmyisam_sort_buffer_size=Mããkey_buffer_size=Mããread_buffer_size=Kããread_rnd_buffer_size=Kããsort_buffer_size=Kããinnodb_additional_mem_pool_size=4Mããinnodb_flush_log_at_trx_commit=1ããinnodb_log_buffer_size=2Mããinnodb_buffer_pool_size=Mããinnodb_log_file_size=Mããinnodb_thread_concurrency=8ãããæ»ç»ãããçMySQL 5.0é¢MyISAMInnoDBåå¨å¼ææ§è½å·®å«å¹¶éInnoDB说影åæ§è½ä¸»è¦ innodb_flush_log_at_trx_commit é项设置1æ¯æå ¥æ°æ®åé½èªæ交导è´æ§è½æ¥å§éåºè¯¥è·å·æ°å¿å ³ç³»è®¾ç½®0æçè½å¤çææ¾æååSQLæ交SET AUTOCOMMIT = 0设置达æ§è½å¦å¤å¬è¯´é设置innodb_buffer_pool_sizeè½å¤æåInnoDBæ§è½ææµè¯åç°æ²¡ç¹å«ææ¾æåããåºæ¬æèè使ç¨InnoDBæ¿ä»£æMyISAMå¼æInnoDBèªèº«è¯ç¹ç¹æ¯äºå¡æ¯æãåå¨ç¨ãè§å¾ãè¡çº§éå®çç并åæ åµç¸ä¿¡InnoDB表ç°è¯å®è¦æ¯MyISAM强ç¸åºmy.cnfé ç½®æ¯è¾å ³é®è¯é ç½®è½å¤æå éåºç¨ããå¤æWebåºç¨éå ³é®åºç¨ç»§ç»èèMyISAMå ·ä½æ åµèªæé Mysql InnoDBMyISAMåºå«
MySql轻松入门系列——第二站 使用visual studio 对mysql进行源码级调试
在探索MySQL世界的过程中,有些同学希望更深入地了解如何在Visual Studio中进行源码级调试。不用担心,daz插件源码让我们一步步来。必备工具
MySQL是用C++编写的,要在Windows上编译,需要几个关键工具:CMake用于生成可打开的解决方案,如MySQL.sln;Boost是强大的C++库,Bison是用于解析MySQL语法规则的工具;当然,选择适合自己版本的MySQL源码(如5.7.)也是必不可少的。详细安装步骤
安装过程需要细心,特别是Bison,务必避免默认路径中的空格问题,以免后续VS编译受阻。安装CMake和Bison时选择自定义路径,例如C:\2\GnuWin,确保它们的bin文件路径被添加到环境变量中。接下来解压mysql-5.7..zip,构建项目。编译与调试
使用CMake编译MySQL源码,当看到Build files written to: C:/2/mysql-5.7./brelease,说明成功生成.sln文件。用Visual Studio 打开MySql.Sln,耐心等待十几分钟,编译成功后即可进行下一步。启动MySQL并调试
首先,开启MySQL的调试模式,修改mysqld.cc中的test_lc_time_sz方法。然后,在Visual Studio的命令行参数中加入--console --initialize,开始调试。可能会遇到编码问题,解决后,输入默认密码zJDE>IC5o+ya,连接到MySQL并修改密码。追踪write_row
在上一篇中提到的write_row是一个虚方法,通过实际调试,我们可以看到它在ha_innodb.cc的实现。设置断点,执行insert操作,可以看到代码进入ha_innodb::write_row方法,深入查看局部变量和调用堆栈,验证之前的理论。总结
通过一整天的努力,我们掌握了在Visual Studio中对MySQL源码进行调试的技巧。记住,每一步都可能是个挑战,但只有亲自动手,才能真正理解MySQL的运作机制。希望这些经验能帮助你避免一些常见的坑,祝你在源码的世界里探索得更深入!MySQL 核心模块揭秘 | 期 | 回滚到 savepoint
深入理解 MySQL,了解如何实现部分回滚操作。本文由技术专家操盛春撰写,他在公众号『一树一溪』分享 MySQL 和 OceanBase 源码研究。本文基于 MySQL 8.0.,InnoDB 存储引擎,探讨核心模块的工作原理。
首先,我们创建测试表并插入数据。关键操作分为四个阶段,编号为 SQL 1 至 SQL 4,其中 SQL 4 是讨论焦点。SQL 2 和 SQL 3 分别产生 undo 日志 0 和 1。
当执行事务时,产生的 binlog 日志在 trx cache 中。回滚整个事务时,需要清除这些日志。然而,实际操作中,binlog 回滚步骤看似简单,却并未执行真正清除,只是为后续的 InnoDB 回滚做准备。
InnoDB 回滚是关键环节,它会根据 undo 日志执行反向操作,恢复事务影响的数据。以 SQL 为例,会从最新的 undo 日志开始回滚,逐条执行反向操作,包括记录的删除。
回滚后,事务的执行状态需要通过提交事务来更新。这不同于 commit 语句,因为回滚操作已经改变了数据,即使从逻辑上看恢复了原样,也需要将 InnoDB 中的修改正式提交。
trx cache 中的 binlog 日志会在 InnoDB 回滚完成后进行清除,这个过程涉及内存 buffer 和磁盘临时文件。binlog 回滚步骤延迟到这个阶段,是因为在事务提交前,binlog 日志并不需要写入持久化存储。
总结起来,MySQL 的部分回滚包括:无实际动作的 binlog 回滚,执行 InnoDB 回滚恢复数据,然后提交 InnoDB 事务,最后清理 trx cache 中的临时 binlog。如果你对文中内容有疑问,欢迎留言交流。
对于 SQL 质量管理,如需更多工具支持,可以了解 SQLE,一个覆盖开发到生产环境的 SQL 管理平台,提供流程自动化和数据质量管理功能。
源码详解系列(四) ------ DBCP2的使用和分析(包括JNDI和JTA支持)已停更
深入剖析DBCP2的精髓,掌握连接池管理与事务支持(DBCP2),它在项目开发中的作用不容小觑。让我们一起探索它的配置、源码细节以及JNDI和JTA的支持。1. 环境配置
以JDK 1.8、Maven 3.6.1、Eclipse 4.和MySQL 5.7.为平台,DBCP 2.6.0提供高效连接管理。以下是关键步骤:创建dbcp.properties,配置基础数据库连接信息,如driverClassName、url、字符编码和时区。
通过BasicDataSourceFactory获取BasicDataSource实例,这是连接池的核心。
执行SQL操作时,通过dataSource.getConnection()获取Connection对象。
项目结构上,包括Maven项目、war打包、JUnit测试框架和必要的库依赖。
2. 配置详解
基础配置包括连接池大小(maxTotal、maxIdle、minIdle)和初始化数量(initialSize)。务必关注验证SQL(validationQuery)、超时时间(maxWaitMillis)和资源回收策略。 例如,连接池配置示例:url=jdbc:mysql://localhost:/github_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true
连接池参数如PSCache、lifo、connectionInitSqls等,务必启用testWhileIdle检测连接状态。3. JNDI与JTA支持
DBCP支持JNDI获取数据源,如PerUserPoolDataSource和SharedPoolDataSource,分别针对不同的用户连接管理策略。在Tomcat 9.0.中,可通过Spring-like配置实现,如在web.xml中定义DataSource引用。 对于JTA事务,DBCP提供BasicManagedDataSource和ManagedDataSource类,用于支持XA事务,例如在MySQL中启用innodb_support_xa。4. 实践与测试
使用Atomikos的transactions-jdbc,为JTA事务提供支持,例如设置DefaultCatalog以避免资源冲突。在测试时,确保两阶段提交的正确性,如START、END、PREPARE、COMMIT和ROLLBACK。5. 源码洞察
源码中,从BasicDataSource.getConnection()开始,初始化连接池,包括创建Connection对象、DataSource实例和设置相关参数。核心组件如GenericObjectPool的makeObject()方法展示了连接对象的创建逻辑。 理解了这些,你将能更有效地利用DBCP2来优化数据库资源管理,确保应用程序的稳定性和性能。 欲了解更多源码链接和详细教程,请参考:[源码链接] 和 [原创文章链接] 本文由[作者]撰写,版权所有,转载请注明出处。