MySql基础学习笔记

时间:2019-02-11
本文章向大家介绍MySql基础学习笔记,主要包括MySql基础学习笔记使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

SQL语句在编译的时候,操作系统会将所有字符转换成大写的,再进行编译。

连接数据库:mysql -u root -p 密码
查询语句:SELECT Distinct …… FROM …… WHERE …… GROUP BY …… HAVING …… ORDER BY …… LIMIT <–>,<–>
注释:-- (空格)

DDL(数据定义语言):用来定义数据库对象:创建库、表、列等。
数据库操作
(1)创建数据库:create databases 数据库名 character set utf8;
(2)使用数据库:use 数据库名称;
(3)查看数据表:show tables;
(4)删除数据库:drop database 数据库名称;
(5)修改数据库密码:方法一:UPDATE mysql.user set authentiction string=password(‘新密码’) WHERE user=‘root’ AND Host=‘localhost’;
flush privileges;刷新MySQL的系统权限相关表。
方法二:mysqladmin -u root -p password 新密码;
(6)退出:exit;/quit;

表操作
(1)创建表:CREATE TABLE 表名(列名1 列的类型 [约束],列名2 列的类型 [约束],列名3 列的类型 [约束],…);
(2)添加一列:ALTER TABLE 表名 ADD 列名 数据类型;
(3)查看表的字段类型:DESC 表名;
(4)修改一个表的字段类型:ALTER TABLE 表名 MODIFY 字段名 数据类型;
(5)删除一列:ALTER TABLE 表名 DROP 字段名;
(6)修改表名:RENAME TABLE 原始表名 TO 修改的表名;
(7)查看表的创建细节:SHOW CREATE TABLE 表名;
(8)修改表的字符集为GBK:ALTER TABLE 表名 CHARACTER SET 字符集名称;
(9)修改表的列名:ALTER TABLE 表名 CHANGE 原始列名 新列名 类型;
(10)删除表:DROP TABLE 表名;

SQL数据类型:
类型:数据类型 字符串类型 时间和日期类型 《MySQL必知必会》 P225
常用:(在MySQL中,子字符串类型和日期类型都要用单引号括起来,如’MySQL’,‘2020-01-01’)
int(n):整型,int(10)表示前边用0补齐至10位。
double:浮点型,例如double(5,2)表示最多5位,其中必须有两位小数,即最大值为999.99;
char:固定长度字符串类型,char(10) 'abc ’
varchar:可变长度字符串类型,varchar(10) ‘abc’
text:字符串类型
blob:二进制类型
date:日期类型,格式为:yyyy-MM-dd
time:时间类型,格式为:hh:mm:ss
date-time:日期时间类型,格式为:yyyy-MM-dd hh:mm:ss

DML(数据操作语言):用来操作数据库表中的记录。(增删改查)
(1)查询表中的所有数据:SELECT * FROM 表名 (\G,一条一条显示);
(2)插入操作:INSERT INTO 表名 (列名1,列名2,…) VALUES (列值1,列值2,…),(列值1,列值2,…)…;
(3)更新操作:UPDATE 表名 SET 列名1=列值1,列名2=列值2…WHERE 列名=值;
(4)删除操作:
DELETE FROM 表名 [WHERE 列名=值]; (删除后能找回来)
TRUNCATE TABLE 表名; (删除后不能找回来,删除表后再创建新表)

DQL(数据查询语言):用来查询数据。
(1)查询所有列:SELECT * FROM 表名;
(2)查询指定列的数据:SELECT 列名1,列名2,… FROM 表名; (列名可以加 AS 别名)
(3)条件查询:在查询时给出WHERE子句,在WHERE子句后可以使用一些运算符及关键字:
=,!=,<>(不等于),<,<=,>,>=
BETWEEN…AND;值在什么范围
IN(set); 查询固定的范围值(列名 IN(值1,值2,…))
IS NULL;/IS NOT NULL
AND; OR; NOT

(4)模糊查询:(使用LIKE关键字后跟通配符,通配符“”任意一个字符,“%”任意(包括 0个)个字符)
例:SELECT * FROM students WHERE name LIKE '
’;
SELECT * FROM students WHERE name LIKE ‘S%L%’;

(5)字段控制查询:
a.去除重复记录:DISTINCT (例: SELECT DISTINCT name FROM students;)
b.把查询的字段数据计算:例如,SELECT *,字段1+字段2 AS 列名别名 FROM students;
IFNULL(字段,0)表示如果为NULL,则按0计算。

(6)排序:ORDER BY (升序 ASC 默认; 降序 DESC)
例:SELECT * FROM students ORDER BY id ASC, name DESC;

(7)聚合函数(对查询的结果进行统计计算)
COUNT():统计指定列不为NULL的记录行数; SELECT COUNT(id(或者*)) FROM students;
MAX():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
MIN():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
SUM():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;
AVG():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;

(8)分组查询:将查询结果按照1个或者多个字段进行分组,字段值相同的为一组。
GROUP BY:SELECT name,id FROM students GROUP BY name,id;
GROUP_CONCAT():SELECT sex,GROUP_CONCAT(name) FROM students GROUP BY sex;
+聚合函数
+having 用来分组查询后指定一些条件来输出查询结果,having和WHERE一样,只是having只能用于GROUP BY

(9)LIMIT从哪一行开始查,总共查多少行。
LIMIT m,n 从m行的下一行开始,往下取n行

(9)书写顺序:SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY LIMIT;
(10)执行顺序:FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT

数据完整性:保证用户输入的数据保存到数据库中是正确的。
可以在创建表时添加约束,包括实体完整性,域完整性,引用完整性。
实体完整性: 表中的一行(一条记录)为一个实体。
作用:标识每一行的数据不能重复,行级约束。
约束类型:
1.主键约束(primary key):每个表中有一个主键,数据唯一,且不能为null,两个主键为联合主键,不同时想同时可以添加成功。
添加方式:CREATE TABLE 表名(字段1 数据类型 primary key,字段2 数据类型);
CREATE TABLE 表名(字段1 数据类型,字段2 数据类型,primary key(要设置为主键的字段));
CREATE TABLE 表名(字段1 数据类型,字段2 数据类型,primary key(主键1,主键2));
联合主键:1.先创建表 2.再去修改表,添加主键
ALTER TABLE 表名 ADD CONSTRAINT PRIMARY KEY(字段名);
2.唯一约束(unique):指定列的数据不能重复,可以为空值
格式: CREATE TABLE 表名(字段1 数据类型 unique,字段2 数据类型);
3.自动增长列(auto_increment):指定列的数据自动增长,即使删除数据,还是从删除的序号继续往下。
格式: CREATE TABLE 表名(字段1 数据类型 primary key auto_increment,字段2 数据类型 unique);

域完整性:限制此单元格的数据正确,不对照此列的其它单元格比较,域代表当前单元格。
域完整性约束:
数据类型:数值类型、日期类型、字符串类型
非空约束(not null):CREATE TABLE 表名(字段1 数据类型 primary key auto_increment,字段2 数据类型 unique not null);
默认值约束(default):CREATE TABLE 表名(字段1 数据类型 primary key auto_increment,字段2 数据类型 default ‘值’);

参照完整性:指表与表之间的一种对应关系,通常情况下可以通过设置两表之间的主键、外键关系,或者编写两表的触发器来实现。
有对应参照表完整性的两张表格,在对他们进行数据插入、更新、删除的过程中,系统都会将被修改表格与另一张对应表进行对照,从而阻止一些不正确的数据操作。
数据库的主键和外键类型一定要一致;
两个表必须是InnoDB类型;
设置参照完整性后,外键当中的内值,必须得是主键当中的内容;
一个表设置当中的字段设置为主键,设置主键的为主表
创建表时,设置外键,设置外键的为子表
– CREATE TABLE stu(id INT PRIMARY KEY,name VARCHAR(50),age INT);
CREATE TABLE score(sid INT, score INT,
CONSTRAINT sc_st_fk FOREIGN KEY(sid) REFERENCES stu(id)
);

ALTER TABLE 表名 CONSTRAINT 外键名 FOREIGN KEY(字段名) REFERENCES 关联表名(字段名);

多表查询:
表之间关系:
一对一:
一对多关系:
– CREATE TABLE person(id INT PRIMARY KEY auto_increment, name VARCHAR(50));
CREATE TABLE car(name VARCHAR(20),color VARCHAR(20),pid INT,
CONSTRAINT person_car_fk FOREIGN KEY(pid) REFERENCES person(id)
);
多对多关系:
CREATE TABLE teacher(sid int PRIMARY KEY auto_increment,name VARCHAR(50),age int,gender char(1) DEFAULT ‘男’);
CREATE TABLE student(sid INT PRIMARY KEY auto_increment,name VARCHAR(50) NOT NULL,age INT,gender CHAR(1) DEFAULT ‘男’);
CREATE TABLE teacher_student_rel(tid INT,sid INT);
ALTER TABLE teacher_student_rel ADD CONSTRAINT FOREIGN KEY(tid) REFERENCES teacher(tid);
ALTER TABLE teacher_student_rel ADD CONSTRAINT FOREIGN KEY(sid) REFERENCES student(sid);
为什么要拆分表?避免大量冗余数据的出现。

多表查询:
1.合并结果集:将两个select语句的查询结果合并到一起,当时合并的结果列数、列类型必须相同。
方式: UNION:合并时去除重复记录
SELECT * FROM 表一 UNION SELECT * FROM 表二;
UNION ALL:合并时不去除重复记录
SELECT * FROM 表一 UNION ALLSELECT * FROM 表二;
2.连接查询:即跨表查询,需要关联多个表进行查询。
笛卡尔集:SELECT * FROM 表一,表二; 就会差生笛卡尔集、
查询时给表取别名:SELECT * FROM 表一 表一别名,表二 表二别名;
将一张表当做两张表使用是需要使用别名。
多表联查,如何保证数据正确:在查询时要把主键和外键保持一致,主表当中的数据参照子表当中的数据, 例: SELECT * FROM stu,score WHERE stu.id=score.sid;
内连接:
1. 等值连接(INNER JOIN …… ON):两个表同时出现的id号(值)相同才显示,与多表联查约束主外键是一样的,只是写法改变了,ON后边只写主外键,如果还有条件直接在后边写where,多表联查后面还有条件直接写and。
例: SELECT * FROM stu st INNER JOIN score sc ON st.id = sc.sid;
例:SELECT * FROM stu st INNER JOIN score sc ON st.id = sc.sid INNER JOIN course c ON sc.sid = c.cid ;
2.多表连接:方法:99连接查询法(使用where and),内联查询
3.非等值连接,和等值相同
4.自连接

	外连接:
		1.左外连接(左连接)( LEFT OUTER JOIN …… ON):两表满足条件相同的数据查出来,如果左边表当中有不相同的数据,也要把左边表当中的数据查出来。(左边表全部显示,右表中满足条件才查出来)
			例: SELECT * FROM stu LEFT OUTER JOIN score ON stu.id=score.sid;
		2.右外连接(右连接)( RIGHT OUTER JOIN …… ON):右边表当中的所有数据全部查出,左边表只查出满足条件的记录。
	
	自然连接:连接查询会产生无用笛卡尔集,通常使用主外键关系等式来去除它,而自然连接无需你去给出主外键等式,它会自动找到这一等式,也就是说不用去写条件。
		要求:两张连接的表中列名称和类型完全一致的列作为条件,会去除相同的列。
		例:SELECT * from stu NATURAL JOIN score;(两张表中有相同的列)
		如果有两个相同列,则两列同时相同才能查到,并且只显示一列。

3.子查询:一个select语句中包含另一个完整的select语句,或者两个以上select,那么就是子查询语句。用括号括起来
	子查询出现的位置:	where后,把select查询出的结果当做另一个select的条件值。
			from后,把查询出的结果当做一个新表。
				例:SELECT ename,salary FROM (SELECT ename,salary,deptno FROM emp WHERE deptno = 30) WHERE s.salary > 2000;	

SQL常用函数:事先提供好的一些功能可以直接使用,函数可以用在SELECT语句及其子句,也可以用在UPDATE、DELETE语句中。
函数分类:
1.字符串函数
concat(s1,s2,…,sn):将传入的字符连接成一个字符串,任何字符串与null进行连接结果都是null;
insert(str,x,y,instr):将字符串str从x位置开始,y个字符长的子串替换为指定的字符。例:insert(‘abcdefg’,3,2,’’) -> abefg.
LOWER(str)和UPPER(str):将字符串转换成小写或者大写。
LEFT(str,x)和RIGHT(str,x):分别返回字符串最左边的x个字符或者最右边的x个字符。如果第二个参数为null,那么不反悔任何字符。
LPAD(str,n,pad)和RPAD(str,n,pad):用字符串pad对str最左边或最右边进行填充,直接到长度为n个字符长度。 例:LPAD(‘my’,5,123456) -> 1234my 不够时循环pad
LTRIM(str)和RTRIM(str):去掉字符串当中最左侧和最右侧的空格。
TRIM(str):去掉字符串左右的空格。
REPEAT(str,x):返回str重复x次的结果。
REPLACE(str,a,b):用字符串b替换字符串str中所有出现的a。
SUBSTR(str,x,y):返回字符串str中第x位置起y个字符长度的字符串。

2.数值函数
ABS(x):返回X的绝对值。
CEIL(x):小数不为0部分向上取整。
FLOOR(x):向下取整。
MOD(x,y):返回x/y的模。
RAND():返回0-1的随机值。

3.日期和时间函数
CURDATE():返回当前日期,只包含年月日。
CURTIME():返回当前时间,只包含时分秒。
NOW():返回当前日期和时间,年月日时分秒都包含。
UNIX_TIMESTAMP():返回当前日期的时间戳。
FROM_UNIXTIME(unixtime):将一个时间戳转换成日期。
WEEK(DATE):返回当前是一年中的第几周。
YEAR(DATE):返回所给的日期是哪一年。
HOUR(TIME):返回当前时间的小时。
MINUTE(TIME):返回当前时间的分钟。
DATE_FORMAT(date,fmt):按字符串格式化日期。如:'%M,%D,%Y'
DATE_ADD(date,interval expr type):就按日期间隔。如:DATE_ADD(NOW(),INTERVAL 1 DAY);
DATEDIFF(date1,date2):计算两个日期相差的天数。如:DATEDIFF('2018-02-05',now());

4.流程函数
IF(value,t,f):如果value是真,返回t,否则返回f。
IFNULL(value1,value2):如果value1不为空,返回value1否则返回value2。
CASE WHEN …… THEN …… END:如:SELECT CASE WHEN 2>3 THEN '对' ELSE '错' END;

5.其他函数
DATABASE():返回当前数据库名。
VERSION():返回当前数据库版本。
USER():返回当前登录用户名
PASSWORD(STR):对STR进行加密。
MD5(STR):返回STR的MD5值。

事务: 不可分割的操作,假设该操作有ABCD四个步骤,则如果ABCD四个步骤都成功完成,则认为事务成功,若任意一个步骤失败,则任务事务失败。
每条SQL语句都是一个事务。
事务只对DML语句有效(增删改查),对于DQL无效。

事务的ACID:
原子性(Atomicity):指事务包括的所有操作要么全部成功,要么全部失败。
一致性(Consistency):指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
		让数据保持合理,一个商品出库时,仓库商品数量减一,对应用户的购物车中商品数加一。
隔离性(Isolation):没有提交之前,别人不能读取。
持久性(Durability):提交后没办法修改。

事务的使用:默认是一条语句一个事务。事务没完成前,另一个客户端访问时,数据没变。
开启事务:start transaction;每次事务开始前都需要运行。
提交事务:commit; 所有语句全部执行完毕,没有发生异常,提交事务,更新到数据库当中。
回滚事务:rollback; 当遇到突发情况,撤销执行SQL语句。

事务的并发问题:
脏读:可以看到未提交的数据(脏读)。解决办法:Read committed! 读提交。
不可重复读:一个事务范围内两个相同的查询却返回了不同的数据,这就是不可重复读。解决:Repeatable read;
重复读:开启事务后,不允许其他事务修改操作。
幻读:在查询时,别的事务插入一条信息,产生幻读,解决:Serializable;

事务隔离级别:
Read uncommitted:就是一个事务可以读取另一个未提交事务的数据。
Read committed:一个事务要等另一个事务提交后才能读取数据。读取提交的数据。但是,可能多次读取的数据结果不一致(不可重复读,幻读)。用读写的观点就是:读取的行数据,可以写。
Repeatable read:(MySQL默认隔离级别):可以重复读取,但有幻读。读写观点:读取的数据行不可写,但是可以往表中新增数据。在MySQL中,其他事务新增的数据,看不到,不会产生幻读。采用多版本并发控制(MVCC)机制解决幻读问题。
Serializable:可读,不可写。像java中的锁,写数据必须等待另一个事务结束。性能低,一般不使用。

1.查看当前会话隔离级别:select @@transaction_isolation;
2.查看系统当前隔离级别:select @@global.transaction_isolation;
3.设置当前会话隔离级别:set session transaction isolatin level repeatable read;
4.设置系统当前隔离级别:set global transaction isolation level repeatable read;
5.命令行,开始事务时:set autocommit=off 或者 start transaction

权限管理
查看权限:show grants;/ show grants for 用户名@localhost;
权限:限制一个用户能够做什么事情,在MySql中,可以设置全局权限,指定数据库权限,指定表权限,指定字段权限。
创建用户:create user ‘用户名’@‘localhost’ identified by ‘密码’;
删除用户:drop user 用户名称;
所有权限:ALL PRIVILEGES;
分配权限:grant 权限(columns) on 数据库对象 to 用户 identified by ‘密码’with grant option;
删除权限:REVOKE 权限 ON 数据库对象 FROm 用户;

视图:视图是一个虚拟表,其内容由查询定义,同真实的表一样,视图包含一些列带有名称的列和行数据,列和行数据来自定义视图的查询所应用的表,并且引用视图时动态生成,简单来说,视图是由select结果组成的表。
视图的作用:安全性,查询性能提高,提高数据的独立性。
创建视图:CREATE VIEW 视图名 AS (SELECT语句);
CREATE [ALGORITHM]={UNDEFINED|MERGE|TEMPTABLE} VIEW 视图名 [(属性清单)] AS SELECT语句 [WITH[CASCADED|LOCAL]CHECK OPTION];
ALGORITHM参数: MERGE:处理方式为替代式,可以进行更新真实表中的数据;
TEMPTABLE:具化式,由于数据存储在临时表中,所以不可以进行更新操作。
UNDEFINED:没有定义ALGORITHM参数,MySql更倾向于选择替换方式。
WITH CHECK OPTION:更新数据时,不能插入或更新不符合视图限制条件的记录。
CASCADED和LOCAL:为可选参数,决定了检查测试的范围,默认为CASCADED。
修改视图:CREATE OR DEPLACE VIEW 视图名 AS(SELECT 语句);
删除视图:DROP VIEW 视图名称;
视图机制:
替换时:操作视图时,视图名直接被视图定义给替换掉。(替换方式,将视图公式替换后,当成一个整体sql语句进行处理)
具化式:先得到视图的执行结果,该结果形成一个中间结果暂时存在内存中,外面的SELECT语句就调用了这些中间结果(临时表)(具体化方式,先处理视图结果,后处理外面的查询需求)
视图不可更改部分:数据不来自基表,就不能更改,比如聚合函数,UNION等。

存储过程:一组可编程的函数,是为了完成特定功能SQL语句集,存储过程就是具有名字的一段代码,用来完成一个特定的功能,创建的存储过程保存在数据库的数据字典中。
特点: 将重读性很高的一些操作,封装到一个存储过程中,简化了对这些SQL的调用。
批量处理
统一接口,确保数据的安全
相对于Oracle数据库来说,MySql的存储过程相对功能较弱,使用较少。
存储过程的创建和调用:
DELIMITER ;:将标准分隔符(分号;)更改为:
创建存储过程:CREATE PROCEDURE 名称(模式 参数名称 数据类型(大小)) BEGIN …… END
DELIMITER KaTeX parse error: Expected 'EOF', got '#' at position 70: …T * FROM stu; #̲存储过程语句 END
DELIMITER ;

	调用存储过程:	CALL show_stu();
	
查看存储过程:SHOW PROCEDURE STATUS;
查看指定数据库存储过程:SHOW PROCEDURE STATUS WHERE db='数据库名';
查看存储过程源码:SHOW CREATE PROCEDURE 存储过程名;
删除存储过程:DROP PROCEDURE 存储过程名;

存储过程变量:在存储过程中声名一个变量,使用DECLARE语句,分配变量值,变量的范围
DECLARE 变量名 数据类型(大小) DEFAULT 默认值;
可以声名一个名为total_sale的变量,数据类型为INT,默认值为0;DECLARE total_sale INT DEFAULT 0;
声名共享相同数据类型的两个或多个变量。DECLARE x,y INT DEFAULT 0;

分配变量值:要为变量分配一个值,可以使用SET语句。 SET 变量名 = 值;
使用SELECT INTO语句将查询的结果分配给一个变量。 SELECT 字段名 INTO 变量名 from……;

变量的范围:只在声名的过程中使用(BEGIN……END)

存储过程参数:
类型: IN:输入;CREATE PROCEDURE 存储过程名(IN 变量名 变量类型名(大小)) BEGIN …… END;
OUT:输出;CREATE PROCEDURE 存储过程名(IN 变量名 变量类型名(大小),OUT 变量名 变量类型名(大小)) BEGIN …… END; 调用 CALL 存储过程名(‘值’,@s); SELECT @s;
INOUT:输入输出; CREATE PROCEDURE 存储过程名(INOUT 变量名 变量类型名(大小),OUT 变量名 变量类型名(大小)) BEGIN …… END; 调用 CALL 存储过程名(@变量1,值); SELECT @变量1;

存储过程语句: IF语句: IF expression THEN statements; END IF;
IF expression THEN statements;ELSE else-statements; END IF;
CASE语句:CASE case_expression WHEN when_expression_1 THEN commands WHEN when_expression_2 THEN commands …… ELSE commands END CASE;
循环: WHILE expression DO statements END WHILE;
REPEAT statements UNTIL expression END REPEAT;

自定义函数:
随机生成一个指定个数的字符串
delimiter CREATEfunctionrandstr(nINT)RETURNSVARCHAR(255)BEGINstr52DECLAREstrVARCHAR(100)DEFAULTabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;DECLAREiINTDEFAULT0;DECLAREresstrVARCHAR(255)DEFAULT;WHILEi&lt;nDOSETresstr=CONCAT(resstr,SUBSTR(str,FLOOR(1+RAND()52),1));SETi=i+1;ENDWHILE;RETURNresstr;END CREATE function rand_str(n INT) RETURNS VARCHAR(255) BEGIN -- 声名一个str 52个字母 DECLARE str VARCHAR(100) DEFAULT &#x27;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&#x27;; -- 记录当前是第几个 DECLARE i INT DEFAULT 0; -- 生成的结果 DECLARE res_str VARCHAR(255) DEFAULT &#x27;&#x27;; WHILE i&lt;n DO SET res_str = CONCAT(res_str,SUBSTR(str,FLOOR(1+RAND()*52),1)); SET i = i + 1; END WHILE; RETURN res_str; END
delimiter ;

添加多条数据,调用存储过程:
DELIMITER CREATEPROCEDUREinsertemp(instartNumINT,inmaxNumINT)BEGINDECLAREiINTDEFAULT0;sqlSETautocommit=0;sql;REPEATSETi=i+1;INSERTINTOempVALUES(startNum+i,randstr(10),FLOOR(RAND()40+1));UNTILi=maxNumENDREPEAT;commit;END CREATE PROCEDURE insert_emp(in startNum INT, in maxNum INT) BEGIN DECLARE i INT DEFAULT 0; -- 默认情况下自动提交sql; SET autocommit = 0; -- 不自动提交sql语句; REPEAT SET i = i + 1; INSERT INTO emp VALUES(startNum+i,rand_str(10),FLOOR(RAND()*40+1)); UNTIL i = maxNum END REPEAT; commit; -- 整体提交语句 提高效率 END

原文地址:http://www.manongjc.com/article/51299.html