当前位置: 首页 > 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…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...