mysql中prepare的设计_prepare的设计与实现

本文详细介绍了数据库中间件Gaea如何处理Prepare请求,包括计算参数、保存Statement对象、执行Execute、处理Send_Long_Data以及Close操作。Gaea通过将Prepare转换为SQL执行,实现了对分库分表的支持,并确保协议兼容。尽管使用Prepare在Gaea环境下性能提升有限,但文章阐述了其设计思想和优化策略。
摘要由CSDN通过智能技术生成

prepare的设计与实现

背景

应用端使用prepare主要考虑通过固定sql模板,在执行sql时只传输参数,减少数据包传输大小,提升sql执行效率。对于非分库分表的情况,我们可以直接通过转发execute(对应后端连接可能是prepare+execute+close)的方式进行支持。但是对于分库分表的情形,需要计算路由,重写sql,支持起来会非常麻烦。商城目前的分库分表中间件是mycat,而mycat是支持prepare的,而gaea的prepare方案也是参照mycat,即将prepare statements的执行转换为sql的执行,然后在应答阶段,根据文本的应答内容构造二进制应答内容,返回给客户端,从而统一了分库分表的处理逻辑。

prepare

gaea在接到preprae请求后,首先计算参数个数、参数偏移位置和stmt-id。然后根据以上数据,构造statement对象并保存在SessionExecutor的stmts内,stmts为一个map,key为stmt-id,value即为构造的statement对象。

prepare阶段主要是计算、保存execute需要使用的变量信息,prepare应答数据内也会包含这些变量信息。

execute

execute请求时会携带prepare应答返回的stmt-id,服务端根据stmt-id从SessionExecutor的stmts中查询对应的statement信息。根据statement信息的参数个数、偏移和execute上传的参数值,进行关联绑定,然后rewrite一条同等含义的sql。同时,为了安全性考虑,也会进行特殊字符过滤,防止比如sql注入的发生。

生成sql之后,无论是分表还是非分表,我们都可以调用handleQuery进行统一的处理,避免了因为要支持prepare,而存在两套计算分库、分表路由的逻辑。

处理完成之后,需要进行文本应答协议到二进制应答协议的转换,相关实现在BuildBinaryResultset内。

execute执行完成之后,执行ResetParams,重新初始化send_long_data对应的args字段,病返回应答。

send_long_data

send_long_data不是必须的,但是如果execute有多个参数,且不止一个参数长度比较大,一次execute可能达到mysql max-payload-length,但是如果分多次,每次只发送一个,这样就绕过了max-payload-length,send_long_data就是基于这样的背景产生的。

客户端发送send_long_data报文,会携带stmt-id、param-id(参数位置),我们根据stmt-id参数可以检索prepare阶段存储的stmt信息,根据param-id和对应上送的数据,可以建立一个k-v映射,存储在Stmt.args(interface slice)。在上述execute执行阶段,也会根据参数位置从Stmt.args查询对应位置的参数值,进行关联绑定。

send_long_data不需要应答。

close

close的处理逻辑比较简单,服务端收到close请求后,删除prepare阶段stmt-id及其数据的对应关系。

总结

gaea对于prepare的处理初衷还是考虑协议的兼容和简化处理逻辑,对于client->proxy->mysql这样接口来说,client->proxy是prepare协议,proxy->mysql是文本协议,所以整体来看在gaea环境下使用prepare性能提升有限,还是建议直接使用sql。

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL的预处理语句(Prepare)是一种将SQL语句预处理为占位符的方式,然后通过执行execute语句来为这些占位符赋值,最后执行占位符替换后的SQL语句。该机制可以有效地避免SQL注入攻击,同时提高SQL的执行效率。 以下是预处理语句的基本用法: 1. 准备预处理语句 ``` PREPARE stmt_name FROM 'SELECT * FROM mytable WHERE col = ?'; ``` 2. 执行预处理语句 ``` SET @col_value = 'value'; EXECUTE stmt_name USING @col_value; ``` 3. 删除预处理语句 ``` DEALLOCATE PREPARE stmt_name; ``` 在执行预处理语句时,使用USING子句为占位符赋值。占位符可以是问号(?)或命名占位符(@placeholder),如下所示: ``` PREPARE stmt_name FROM 'SELECT * FROM mytable WHERE col1 = ? AND col2 = @col2'; SET @col1_value = 'value1'; SET @col2_value = 'value2'; EXECUTE stmt_name USING @col1_value, @col2_value; ``` 注意,在使用命名占位符时,需要在prepare语句使用@符号来定义占位符的名称。 另外,预处理语句还支持IN参数,用于在一个查询一次性传递多个值。 ``` PREPARE stmt_name FROM 'SELECT * FROM mytable WHERE col1 IN (?)'; SET @col1_values = 'value1,value2,value3'; EXECUTE stmt_name USING @col1_values; ``` 在上面的例子,@col1_values是一个逗号分隔的字符串,包含多个值,这些值将被解析为一个数组并用于查询。 总的来说,预处理语句可以提高数据库查询的安全性和效率,特别是在处理用户输入时,应该优先考虑使用预处理语句。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值