首页 > 数据库 >使用一次sql语句,返回分页数据和总条数

使用一次sql语句,返回分页数据和总条数

时间:2024-08-13 16:39:02浏览次数:11  
标签:语句 编译 plugin sql results 条数 SQL

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

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

最近我在思考:

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

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


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

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

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

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

image.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注入风险

// 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注入的核心作用。

标签:语句,编译,plugin,sql,results,条数,SQL
From: https://www.cnblogs.com/JulianHuang/p/18357240

相关文章

  • Chapter 34 PyMySQL 基本操作指南
    欢迎大家订阅【Python从入门到精通】专栏,一起探索Python的无限可能!文章目录前言一、基本操作步骤二、综合案例分析前言在现代应用开发中,与数据库的高效交互是关键的一环。对于使用Python语言的开发者来说,PyMySQL是一个非常实用的工具,它提供了一个简洁且功能强......
  • flink-cdc实时同步(oracle to mysql)
    FlinkCDC于2021年11月15日发布了最新版本2.1,该版本通过引入内置Debezium组件,增加了对Oracle的支持。Flink下载地址https://flink.apache.org/downloads/其他必需的jar包(cdc、jdbc、mysq和oracle等驱动包) 下载Flink后,直接解压到指定目录下即可;tarzxvf flink-......
  • 【华为云MySQL技术专栏】MySQL 8.0事务提交原理解析!
    摘要:当多个引擎/节点同时访问和修改数据时,如何保证数据在各个引擎/节点之间的一致性成为了一项挑战。本文将深入探讨MySQL集群在保持数据一致性的解决方案。本文分享自华为云社区《【华为云MySQL技术专栏】MySQL8.0事务提交原理解析!》,作者:GaussDB数据库。 1.概述MySQL是一......
  • prometheus监控mysql数据库
    监控需要安装一个工具mysqld_exportermysqld_exporter-0.14.0.linux-386.tar.gz上传到服务器后,解压压缩包tar-zxvf mysqld_exporter-0.14.0.linux-386.tar.gzcd mysqld_exporter-0.14.0.linux-386touchmy.cnfvimy.cnf加入有权限的用户名,密码,数据库地址等信息。[cli......
  • C# Sql帮助类,可扩展
    [System.AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct,Inherited=false,AllowMultiple=false)]publicclassDbTableAttribute:Attribute{publicstringName{get;set;}publicstring......
  • 【原创】java+swing+mysql校园表白墙系统设计与实现
    个人主页:程序员杨工个人简介:从事软件开发多年,前后端均有涉猎,具有丰富的开发经验博客内容:全栈开发,分享Java、Python、Php、小程序、前后端、数据库经验和实战开发背景:昨天七夕,大家都去约会了,趁着有时间写了一个校园表白墙系统。在校园环境中,学生们正处于青春期,情感丰富且......
  • 【原创】java+swing+mysql简单图书信息管理系统设计与实现
    个人主页:程序员杨工个人简介:从事软件开发多年,前后端均有涉猎,具有丰富的开发经验博客内容:全栈开发,分享Java、Python、Php、小程序、前后端、数据库经验和实战开发背景:编程小白们刚入门,尤其在学了一点java的基础之后,想通过自己动手来实现一个比较基础的小项目,由于编程经验......
  • mysql: 用户权限的操作
    一,查看mysql内置的权限有哪些?SHOWPRIVILEGES;如图:二,管理给用户的权限1,授予权限:mysql>GRANTSELECT,INSERT,DELETE,UPDATEONnews.*TO'laoliu'@'127.0.0.1';QueryOK,0rowsaffected(0.01sec)2,查询指定用户有哪些权限?mysql>showgrantsfor'laoliu'......
  • pbootcms网站是使用sqlite数据库好还是使用mysql数据库好?
    众多周知pbootcms程序支持sqlite数据库和mysql数据库,目前默认常用最多的是sqlite数据库,有需要转成mysql数据库的可以联系我们。pbootcms数据库sqlite无缝转换mysql数据库 本人从接触pbootcms开始一直都是使用mysql数据库,很少出现被黑和各种不明原因报错。建议有条件的朋友尽量......
  • mysql: auth_socket登录
    一,默认安装的mysql用户root是auth_socket方式登录root@localhost的authentication_string为空,   它的plugin为auth_socket二,如何登录?1,从命令行正常登录会报错:liuhongdi@lhdpc:/data/site/gsapi$mysql-uroot-hlocalhost-pEnterpassword:ERROR1698(28000):......