当前位置: 首页 > news >正文

一次sql请求,返回分页数据和总条数

06822c1b706026f08a919abf1655d518.gif

日常搬砖,总少不了需要获取分页数据和总行数

一直以来的实践是编码两次sql请求,分别拉分页数据和totalCount。

最近我在思考:

常规实践为什么不是 在一次sql请求中中执行多次sql查询或多次更新,显而易见的优势:

① 能显著减低“客户端和服务器之间的网络往返次数”,提高吞吐量
② 简化客户端代码逻辑


1. mysql 默认单sql请求单语句

mysql客户端选项client_multi_statements默认为false:会禁止多条 SQL 语句的执行,这意味着在单个sql请求中只有第一条 SQL 语句会被执行,后续的 SQL 语句将被忽略。

这是一种提高数据库操作安全性的方法,可以有效防止 SQL 注入攻击和意外执行多条语句带来的风险。

MySQL客户端支持修改这样的设定 :client_multi_statements=true。

5b12b1fea06772519f8057bfb6eab25d.png

劣势:存在sql注入的风险, 错误处理比较复杂。

(1) go-sql-driver开启多语句支持: multiStatements=true

(2)

SELECT *  FROM `dict_plugin`  limit  20 ,10;
SELECT count(*) as  totalCount  from `dict_plugin`;

将会形成2个数据集,golang的实践如下:

results, err = p.Query(querystring)for results.Next() {err = results.Scan(&...)}if !results.NextResultSet() {log.ErrorF(ctx, "expected more result sets: %v", results.Err())}for results.Next() {err = results.Scan(&totalCount)}

既然提到了开启client_multi_statements 有sql注入的风险,我们就展开聊一聊。

2. sql注入

我们先看下sql注入的原理:

有这样的业务sql:

var input_name string
query: = "select  * from user where user_name='" + input_name+"'"
sql.Query(query)

如果从界面输入的input_name="janus';delete from user;  --",
会形成恶意sql:select * from user where user_name='janus';delete from user;  --' 。

这个时候,客户端的client_multi_statements默认值为false就能于水火之间挽救数据库:执行第一个sql之后,后面的恶意sql都不会执行。

由此可知,client_multi_statements=false,确实可以显著降低sql注入的风险,但是还是没有办法避免单sql注入, 比如从界面密码框注入' OR '1'='1 会绕过登录认证。

query:= "select * from user where user='" + input_name +"' and  pwd='" +input_pwd +"'" select * from user where user='xxx' and pwd='' OR '1'='1'  -- 会绕过认证逻辑。

3. 参数化查询防止sql注入

参数化查询可以防止sql注入风险[1]

// Correct format for executing an SQL statement with parameters.var queryStr = "SELECT * FROM `dict_plugin_Test` WHERE `plugin_name` = ?"
var args string = "55 union select * from `dict_plugin_Test`"rows, err := db.Query(queryStr, args)

sql查询内部会利用提供的参数1创建预编译语句, 在运行时,实际是执行带参的预编译后的语句。

在服务器收到的查询日志如下:

2024-08-13T08:07:18.922818Z   26 Connect root@localhost on tcinfra_janus_sharing using TCP/IP
2024-08-13T08:07:18.924525Z   26 Prepare SELECT * FROM `dict_plugin_Test` WHERE `plugin_name` = ?
2024-08-13T08:07:18.924671Z   26 Execute SELECT * FROM `dict_plugin_Test` WHERE `plugin_name` = '55 union select * from `dict_plugin_Test`'
2024-08-13T08:07:18.925273Z   26 Close stmt

判断mysql数据库开启了查询日志:show variables like '%general_log%';
打开sql查询日志的开关:set global general_log = on; 。

注意:参数占位符根据DBSM和驱动而有所不同,例如,Postgres 的pq驱动程序接受占位符形式是 $1而不是?。

3.1 预编译语句

数据库预编译后, SQL语义结构和数据分离,这样即使输入包含恶意代码,它也只会被当作数据处理,不会影响已经被解析固定的SQL语义结构。

预编译语句包含两次 sql交互:

①  预编译阶段(Prepare Phase):

  • 客户端向服务器发送一个包含 SQL 语句(带有参数占位符)的请求。

  • sql服务器对SQL 语句进行语法和语义检查,然后对其进行预编译,并为其分配一个标识符(Statement ID)。

  • 服务器返回一个确认响应,表示预编译语句已经成功准备好。

②  执行阶段(Execute Phase):

  • 客户端发送执行请求,包含预编译语句的标识符和实际参数值。

  • 服务器将参数值绑定到预编译语句的占位符上,然后执行该语句。

  • 服务器返回执行结果(如结果集或影响的行数)。

图示如下:

客户端                          服务器|                               ||----预编译语句(Prepare)------>||                               ||<-------确认响应(OK)----------||                               ||---执行语句(Execute) + 参数---->||                               ||<----------查询结果-------------|

我们了解到预编译语句,将SQL语义和数据分离,通过两次sql交互(在预编译阶段固定了sql语义结构), 有效防止了SQL注入攻击, 另一方面,预编译语句在重复执行某一sql语句时确实有加快查询结果的效果。

golang的预编译的写法与常规的sql查询类似:

stmt, err := p.Prepare("SELECT * FROM `dict_plugin_Test` WHERE `plugin_name` = ?")
var args string = "55 union select * from `dict_plugin_Test`"
results, err := stmt.Query(args)
if err != nil {fmt.Printf("query fail: %v", err)return err
}
defer stmt.Close()for results.Next() {err = results.Scan(.....)......
}

btw, C#  其实也支持预编译语句版本的sqlCommand:SqlCommand.Prepare()

总结

本文通过我们最初开始数据库编程时的一个实践, 提出在【一次sql请求中执行多次sql查询】的猜想;

了解到client_multi_statements= false 确实能避免一部分sql注入风险;

之后落地到sql注入的原理, 给出了参数化查询(预编译语句)能防止sql注入的核心机制。

参考资料

[1]

参数化查询可以防止sql注入风险: https://go.dev/doc/database/sql-injection

8d06b98bd82aa73ca9652fba819f28b0.gif

自古以来,同步/异步都是八股文第一章

async/await 贴脸输出,这次你总该明白了

流量调度、微服务可寻址性和注册中心

Go语言正/反向代理的姿势

两将军问题和TCP三次握手

"家长进校园"之《计算机和人工智能》

903d18c5a32d92d0ca579dc91845b98f.png

点“5188979d1bab0f1d4604485dca023c3b.gif戳“在看545b5850adc9ae8bc1ff113e573a0446.gif

相关文章:

一次sql请求,返回分页数据和总条数

日常搬砖&#xff0c;总少不了需要获取分页数据和总行数。 一直以来的实践是编码两次sql请求&#xff0c;分别拉分页数据和totalCount。 最近我在思考&#xff1a; 常规实践为什么不是 在一次sql请求中中执行多次sql查询或多次更新&#xff0c;显而易见的优势&#xff1a; ① 能…...

2.5 pyautogui 实现微信自动回复

第四节&#xff1a;实战微信自动回复 课程目标 学习如何通过pyautogui完成微信自动回复 课程内容 编码实现 import pyautogui as pg import time from pyautogui import ImageNotFoundException import pyperclip from cnocr import CnOcr import random ocr CnOcr() msg…...

观存储历史,论数据未来

数据存储 这几天我反复观看了腾讯云社区的《中国数据库前世今生》纪录片&#xff0c;每次的感受都大相径庭。以下是我在这段时间里对纪录片的两个不同感想&#xff0c;希望感兴趣的小伙伴们也能去观看一番。 一个是关于国产数据库的发展趋势的探讨&#xff1a;https://blog.c…...

linux:对目录的操作

一、对目录操作 1,打开目标目录 2.读取目录&#xff0c;&#xff0c; 3.关闭目录 目录 当文件看&#xff0c;只不过操作函数和操作文件函数不一样。 *1.opendir DIR *opendir(const char *name); 功能:打开一个目录获得一个目录流指针 参数:name:目录名 返回值&#xf…...

详解Redis 高可用的方式 Redis Cluster

Redis 高可用方式 Redis 提供了多种高可用性方案&#xff0c;主要包括以下几种方式&#xff1a; 主从复制&#xff08;Replication&#xff09; 主从复制是最基本的高可用性方案&#xff0c;通过将数据从一个主节点复制到多个从节点来实现数据的冗余和读写分离。主节点负责所…...

$clog2(1)=0

项目场景&#xff1a; 写ip 时&#xff0c; 使用参数化的方式实现2w1r 时&#xff0c;出现计算读返回index 时&#xff0c;减下溢&#xff01; 问题描述 verilog中会使用parameter 参数化&#xff0c;例如使用dpth 和$clog2(dpth)addr 。 常见的写法没有什么问题。 module …...

开发学习日记1

用这个系列博客记录下学习开发的一些小收获 git的使用&#xff1a; 说来惭愧&#xff0c;学到了大二&#xff0c;git的使用还是一团糟&#xff0c;记录一下如何使用git进行团队合作开发 当要加入其他人的项目时首先你要创建自己的分支&#xff08;克隆一下其他分支&#xff…...

孙宇晨领航波场TRON:引领数字资产迈向崭新纪元

​ 在风起云涌的数字资产领域&#xff0c;孙宇晨这个名字始终与创新、突破和引领紧密相连。作为波场TRON的创始人&#xff0c;他不仅是一位远见卓识的领导者&#xff0c;更是推动数字资产迈向新纪元的坚实力量。 自波场TRON诞生以来&#xff0c;孙宇晨便以其敏锐的洞察力…...

python运维(twenty-four day)

一、python基础 1、环境python2、python3 [rootpython ~]# yum list installed | grep python #检查是否有python包 [rootpython ~]# yum list installed | grep epel #检查是否有epel包 [rootpython ~]# yum -y install epel-release [rootpython ~]# yum -y instal…...

Eureka原理实践

1. 简介 1.1. 概述 Eureka是Netflix开源的一个服务注册与发现框架,它在微服务架构中扮演着至关重要的角色。 Eureka由两个核心组件组成: Eureka Server(服务注册中心):负责存储、管理和提供服务实例信息,如服务名、IP地址、端口号等。Eureka Server通常采用集群部署以保…...

Ant-Design-Vue快速上手指南+排坑

1. 简介 1.1. 概述 Ant-Design-Vue是由阿里巴巴开源的一个基于Vue.js框架的企业级UI设计语言。它旨在帮助开发者构建设计优雅、体验流畅的企业级应用。Ant-Design-Vue提供了一系列高质量的Vue组件,包括表单、表格、布局、导航、图标等,可以帮助开发者快速搭建应用程序界面。…...

mysql5.7安装

1.创建一个software文件 2.先下载mysql的repo源 wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 3安装源包 rpm -ivh mysql-community-release-el7-5.noarch.rpm 可能会报错 改成命令 rpm -ivh mysql-community-release-el7-5.noarch.rpm --nodeps…...

UE开发中的设计模式(三) —— 对象池模式

在FPS游戏中&#xff0c;射击会生成子弹&#xff0c;在命中敌人后子弹会被销毁&#xff0c;那么会导致子弹对象频繁地创建和销毁&#xff0c;会造成运行效率降低且会产生内存碎片问题&#xff0c;而对象池模式可以很好地解决这个问题。 文章目录 问题提出概述问题解决总结 问题…...

Mocha测试框架:JavaScript自动化测试的瑞士军刀

在JavaScript开发中&#xff0c;自动化测试是确保代码质量和可靠性的关键环节。Mocha是一个广泛使用的JavaScript测试框架&#xff0c;它支持多种断言库&#xff0c;允许开发者编写简洁、灵活的测试用例。Mocha特别适用于Node.js环境&#xff0c;但也可以在浏览器中运行。本文将…...

flask实现Streaming内容传输

当传输大量内存&#xff0c;以至于超出内存大小&#xff0c;一般http服务器会报500错误&#xff0c;这时可以使用Streaming流的方式来传输内容&#xff0c;类似ChatGPT和视频流那样的输出方式&#xff0c;flask里要用到生成器和直接响应。 from flask import stream_with_cont…...

seata的使用(SpringBoot项目整合seata)

文章目录 1、解压 seata-server-1.7.1.zip2、启动 双击 seata-server.bat3、启动 seata 控制台用户界面4、所有分布式事务相关数据库要有undo-log5、项目引入seata依赖6、项目添加seata配置7、代码实现&#xff1a; 1、解压 seata-server-1.7.1.zip 2、启动 双击 seata-server.…...

docker容器和宿主机网络不通

防火墙未开启&#xff0c;检查网络配置无异常 解决&#xff1a; [rootlocalhost ~]# vim /etc/sysctl.confnet.bridge.beidge-nf-call-iptables 1 net.bridge.beidge-nf-call-ip6tables 1[rootlocalhost ~]# sysctl -p [rootlocalhost ~]# systemctl restart docker 如果网…...

编程学习之旅:高效记录与整理笔记的艺术

引言&#xff1a;知识的海洋与导航的灯塔 在编程的浩瀚星空中&#xff0c;每一位学习者都像是勇敢的航海家&#xff0c;驾驶着知识的帆船&#xff0c;在无尽的信息海洋中探索未知的领域。然而&#xff0c;这片海洋既充满了机遇&#xff0c;也潜藏着挑战。信息的过载、知识的碎…...

dev c++中,在C++11模式下编译带M_PI宏的文件报错的解决办法

一、问题描述 当使用C11的模式&#xff0c;编译引用了math库中的M_PI的源文件时&#xff0c;报M_PI未声明的错误。 二、问题原因 因为M_PI是GNU扩展的宏&#xff0c;它不属于C11的标准&#xff0c;而-stdc11&#xff0c;表示以C11的标准进行编译&#xff0c;因此会产生以上问…...

【ubutnu24.04】k8s部署2:摸索修复问题

1.30.0 一直init失败有人说版本兼容问题重新安装了最新的1.31.0 版本kubeadm init 仍旧失败。安装依赖项 sudo apt-get install -y apt-transport-https ca-certificates curl gpgroot@PerfSvr:/home/zhangbin/perfwork/k8sadmin# sudo apt-get install -y apt-transport-https…...

处理JSON数据时遇到的解析错误:“Unexpected character (`“`)”

问题背景 在开发过程中&#xff0c;经常会遇到需要解析JSON数据的情况。然而&#xff0c;在某些情况下&#xff0c;可能会遇到类似“Unexpected character (")”这样的错误。本文将详细介绍该错误的原因、如何诊断以及解决方法。 错误示例 以下是一个典型的错误信息示例…...

RDKit|分子输入输出格式解析(如 SMILES、Mol、SDF)

2.3 分子输入输出格式解析(如 SMILES、Mol、SDF) 在化学信息学中,分子的表示方式有很多种,常见的包括 SMILES、Mol 文件、SDF 文件等。RDKit 支持对这些格式的分子数据进行解析和处理,这使得它在化学和药物设计领域得到了广泛应用。本节将介绍如何在 RDKit 中解析和操作这…...

【模电笔记】——反馈放大电路

tips&#xff1a;本章节的笔记已经打包到word文档里啦&#xff0c;建议大家下载文章顶部资源&#xff08;有时看不到是在审核中&#xff0c;等等就能下载了。手机端下载后里面的插图可能会乱&#xff0c;建议电脑下载&#xff0c;兼容性更好且易于观看&#xff09;&#xff0c;…...

【面试题】Redis缓存问题全解:击穿、雪崩与穿透

文章目录 Redis缓存问题全解&#xff1a;击穿、雪崩与穿透引言1. 缓存击穿&#xff08;Cache Penetration&#xff09;2. 缓存雪崩&#xff08;Cache Avalanche&#xff09;3. 缓存穿透&#xff08;Cache Penetration&#xff09; 总结1. 缓存击穿&#xff08;Cache Penetratio…...

676. 实现一个魔法字典

676. 实现一个魔法字典 题目链接&#xff1a;676. 实现一个魔法字典 代码如下&#xff1a; class MagicDictionary { public:MagicDictionary() {}void buildDict(vector<string> dictionary) {wordsdictionary;}bool search(string searchWord) {for(const auto&…...

Spring Boot 入门以及对微服务的理解

目录 1.Spring Boot 简介 1.1什么是自动装配 1.2什么是内嵌Tomcat 2.微服务 2.1单体应用系统 2.2分布式应用系统 2.3微服务 2.3.1什么是微服务 微服务有哪些优点 微服务有哪些缺点 2.3.2为什么选择微服务 1.Spring Boot 简介 Spring Boot 是简化 Spring 应用开发的…...

仿RabbiteMq实现简易消息队列正式篇(需求分析)

TOC 目录 MQ的实现方法 RabbitMq中的相关概念 消息队列系统模块划分 总体划分 服务端模块 数据管理模块 虚拟机数据管理模块 交换机路由模块 消费者管理模块 信道&#xff08;通信&#xff09;管理模块 连接管理模块 服务端BrokerServer模块 客户端模块 消费者管…...

Python酷库之旅-第三方库Pandas(082)

目录 一、用法精讲 341、pandas.Series.str.startswith方法 341-1、语法 341-2、参数 341-3、功能 341-4、返回值 341-5、说明 341-6、用法 341-6-1、数据准备 341-6-2、代码示例 341-6-3、结果输出 342、pandas.Series.str.strip方法 342-1、语法 342-2、参数 …...

0101中文乱码-BufferedImage-图片处理

文章目录 1、问题描述2 、电子证书生成3、中文乱码原因及修复4、思考 结语 1、问题描述 接手维护一个休闲赛事类项目&#xff0c;因为服务器到期&#xff0c;项目从云服务器迁移到本地服务器。 项目生成比赛&#xff0c;分为二人组、三人组等等的团体&#xff1b;比赛设置几个…...

[Qt][Qt 事件][下]详细讲解

目录 1.定时器0.是什么&#xff1f;1.QTimerEvent2.QTimer3.获取系统⽇期及时间 2.事件分发器1.概述2.事件分发器工作原理3.使用 3.事件过滤器0.是什么&#xff1f;2.使用 1.定时器 0.是什么&#xff1f; 在进⾏窗⼝程序的处理过程中&#xff0c;经常要周期性的执⾏某些操作&…...