未加星标

mysql会话变量和分区的坑

字体大小 | |
[数据库(mysql) 所属分类 数据库(mysql) | 发布者 店小二04 | 时间 2016 | 作者 红领巾 ] 0人收藏点击收藏

最近在新东家做审批系统,业务逻辑和工作流引擎都严重依赖mysql。其中业务逻辑部分大量用到存储过程,几乎所有核心dal都是用存储过程实现的。使用存储过程的优势是对于复杂的数据插入和更新操作效率很高。如果不使用存储过程,一个复杂的操作可能要请求多次数据库才能完成,但使用存储过程只需要请求一次,节省网络请求开销。但存储过程的坏处也很明细:不方便测试和调试。我们前一阵就碰到一个存储过程的bug,困扰了一阵。

某字段莫名其妙被篡改

有一天,同事发现数据库里面存的某个字段和原始申请单里面的字段不一样。而且奇怪的是,并非所有的申请单都是这样,有的是对的,有的不对。我检查了所有可能插入和修改该字段的代码,发现总共只有两个地方会写入该字段,并且这两个地方都是新增记录,不会修改。按理说只要存储过程参数传递正确,该字段就会正确地写入,并且不再变化。但事实却是,这两个地方写入的两种记录都会不确定性地出现字段被篡改的问题。

凭直觉,这种不确定性出现的问题,有可能是线程安全问题引起的。一开始,我们首先怀疑是参数在某个地方被非线程安全的访问,导致被诡异修改。排查代码,我们发现代码逻辑没有问题,不存在这种可能性。那只可能是存储过程的问题,后来终于找到原因。

这个bug是这样产生的。我们数据库里有一些码表,用来定义一些业务相关的类型,比如商品类型表(goods_type),它的定义类似这种:

id code description -2 XER code有误 0 A 日用品 1 B 家电 2 C 厨房电器

用户的申请单中会包含商品类型信息(商品类型code),申请单保存到数据库的时候,会为每件商品存储一条记录,记录中包含该商品在商品类型表中的id。

用于保存商品信息部分的存储过程中有类似这样的语句:

select id into @goods_id from good_type where [email protected]_code; if @goods_id = NULL then set @goods_id = -2; end if

上面语句中 @goods_id , @goods_code 都是会话变量,会在同一个会话中共享。 @goods_code 是从存储过程参数中得到的商品code。

当 @goods_code 是一个在goods_type中找不到的code时,上面的 select 语句不会修改 @goods_id 的值,因此 @goods_id 的值会是上一次修改过后的值。如果当前会话之前的语句恰好修改过 @goods_id ,那该商品保存的商品类型id就会“莫名其妙“的被篡改。如果当前会话之前的语句没设置过 @goods_id 变量,那 @goods_id 值为NULL,就会执行后面的if语句。由于我们使用数据库连接池来访问数据库,连接会被复用,同一个会话就执行多条不同的语句,所以就会不确定性的出现字段被篡改的现象。

有两种方式修复该bug,一是在 select 语句前加上初始化语句 set @goods_id = NULL; ,这样每次使用前都保证会重新初始化变量;另一种方式是改成使用局部变量,不用会话变量。

mysql分区的坑

前一阵我们发现mysql写入、删除压力大,于是决定对其中一个关键表分区,缓解压力。该表有varchar(64)类型的主键,并且主键的生成策略类似UUID。我们使用mysql的key函数按主键分区,一开始设置分区数为64,发现所有的数据全分到一个区。刚开始怀疑是分区语句的问题,但经过确认,分区语句没啥问题。后来调整分区数,发现分区数为奇数时分区比较均匀,偶数有问题。

'c7e74234-40c7-11e6-a64b-7ce9d3efdb89', 'c7e74232-40c7-11e6-a64b-7ce9d3efdb89', 'c7e74230-40c7-11e6-a64b-7ce9d3efdb89', 'c7e609a5-40c7-11e6-a64b-7ce9d3efdb89', 'c7e609a3-40c7-11e6-a64b-7ce9d3efdb89'

观察生成的主键,发现主键中间和后面的部分都一样,只有前面部分不同,猜测key函数分区实现和后面部分关系比较大。有空看看源码分析一下具体原因。

本文数据库(mysql)相关术语:navicat for mysql mysql workbench mysql数据库 mysql 存储过程 mysql安装图解 mysql教程 mysql 管理工具

分页:12
转载请注明
本文标题:mysql会话变量和分区的坑
本站链接:http://www.codesec.net/view/480720.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 数据库(mysql) | 评论(0) | 阅读(47)