MySQL必知必会笔记(全)

微信搜索关注公众号【三朝猿老】,第一时间获取更多内容。

说明:本文所使用的书籍《MySQL必知必会》[英] Ben Forta 著,刘晓霞 钟鸣 译

本文中 tbl_name 为数据库表名称,db_name 为数据库名称,col_name 为字段名称。

1. 设置自增字段

创建时设置自动增量:

CREATE TABLE tbl_name
(	id int PRIMARY KEY AUTO_INCREMENT,
 	...
); 

分析:上述代码创建表,设置表主键id自动增长,默认自动增长的起始值为1开始。

修改表中列为自动增量:

ALTER TABLE 表名 MODIFY 字段名 字段类型 AUTO_INCREMENT;

修改后从下一条记录开始自动增长。如果想让原来的自动增长就得复制现有表的结构(无id),添加id并加上AUTO_INCREMENT,然后通过循环,添加n条空记录,然后对应先前表的id,依次插入数据。

注意

  • 每个表只允许一个AUTO_INCREMENT列,必须为int类型,而且它必须被索引(如:使用它做为主键) 。
  • 如果使用AUTO_INCREMENT=1001,表示从1001开始自增增量,默认自动变量从1开始。
  • 使用自动增量时需要获得最后一次添加记录的 AUTO_INCREMENT 值,可以使用last_insert_id()函数获得这个值。

2.导入导出数据库

2.1 导出数据库

在命令行(CMD)里,进入MySQL安装根目录下的bin目录下
比如:C:\Program Files\MySQL\MySQL Server 5.5\bin

进入MySQL的bin路径:

cd "C:\Program Files\MySQL\MySQL Server 5.5\bin"

注意:命令行中不加分号。以下导出都在bin目录下进行。

(1)导出数据库:

mysqldump -uroot -p 数据库名 > 导出文件的路径\导出文件名.sql

注意:这里最后不加分号。按回车后,输入MySQL密码,验证后开始导出整个数据库和数据。

(2)使用条件导出数据库:

mysqldump -uroot -p --where='id < 5' 数据库名 > 导出文件的路径\导出文件名.sql

(3)只导出一张表:

mysqldump -uroot -p 数据库名 表名 > 导出文件的路径\导出文件名.sql

特别注意

在CMD命令行里输入的路径如果有空格,可用如下解决方法:

  1. 给路径名上加上双引号(" ")然后cd执行即可;

  2. 用缩写。比如c:\Program Files缩写为c:\Progra~1;

    采用8个字符缩写,即写头六个字母(略去空白),另加波浪号和1,首字母不足六个字母,略去空白,用第二个词的字母,凑成六个。例如:

    • "Documents and Settings“ --> Docume~1
    • “Local Settings” --> LOCALS~1

    如果多个文件前6字符一样怎么办?看看如下例子:

    假设下面是你的C盘根目录中的文件夹:
    Program Files
    Progra file
    Progra zhang
    则三个目录分别表示为:C:\Progra~1; C:\Progra~2; C:\Progra~3;

  3. 绕过去,创建一个镜像。

    例如在CMD中输入 subst w: "C:\Documents and Settings",然后就可以直接用w:\替代C:\Documents and Settings了。

2.2 导入数据库

首先创建数据库,然后在use数据库后运行*.sql的脚本文件,即执行如下代码:

source 脚本文件路径/script.sql

注意:文件路径层次的分隔使用/,如下形式:

source C:/Users/Eric/Desktop/create.sql

3. SHOW语句用法

3.1 常用show语句(< = >表示等价关系)

-- 显示所有数据库
show databases
-- 显示所有表格(首先应use 数据库)
show tables
-- 显示表的列详细信息(字段名、数据类型、是否运行NULL、键信息、默认值以及其他信息)
show columns from tbl_name < = >  describe tbl_name
-- 显示创建数据库时的详细信息
show create database db_name
-- 显示创建表时的详细信息
show create table tbl_name
-- 显示授权用户的安全权限
show grants

3.2 完整show用法

SHOW {BINARY | MASTER} LOGS
SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]
SHOW CHARACTER SET [like_or_where]
SHOW COLLATION [like_or_where]
SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where]★
SHOW CREATE DATABASE db_name★
SHOW CREATE EVENT event_name
SHOW CREATE FUNCTION func_name
SHOW CREATE PROCEDURE proc_name★
SHOW CREATE TABLE tbl_name★
SHOW CREATE TRIGGER trigger_name★
SHOW CREATE VIEW view_name★
SHOW DATABASES [like_or_where]
SHOW ENGINE engine_name {STATUS | MUTEX}
SHOW [STORAGE] ENGINES
SHOW ERRORS [LIMIT [offset,] row_count]
SHOW EVENTS
SHOW FUNCTION CODE func_name
SHOW FUNCTION STATUS [like_or_where]
SHOW GRANTS FOR user
SHOW INDEX FROM tbl_name [FROM db_name]
SHOW MASTER STATUS
SHOW OPEN TABLES [FROM db_name] [like_or_where]
SHOW PLUGINS
SHOW PROCEDURE CODE proc_name★
SHOW PROCEDURE STATUS [like_or_where]
SHOW PRIVILEGES
SHOW [FULL] PROCESSLIST
SHOW PROFILE [types] [FOR QUERY n] [OFFSET n] [LIMIT n]
SHOW PROFILES
SHOW RELAYLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]
SHOW SLAVE HOSTS
SHOW SLAVE STATUS [FOR CHANNEL channel]
SHOW [GLOBAL | SESSION] STATUS [like_or_where]
SHOW TABLE STATUS [FROM db_name] [like_or_where]
SHOW [FULL] TABLES [FROM db_name] [like_or_where]★
SHOW TRIGGERS [FROM db_name] [like_or_where]★
SHOW [GLOBAL | SESSION] VARIABLES [like_or_where]
SHOW WARNINGS [LIMIT [offset,] row_count]

like_or_where:
    LIKE 'pattern'
  | WHERE expr

4. 常用引擎类型

  1. InnoDB:一个可靠的事务处理引擎,它不支持全文本搜索(默认);
  2. MyISAM:一个性能极高的引擎,支持全文本搜索,但是不支持事务处理。
  3. MEMORY:在功能上等同于MyISAM,但是数据存储在内存中,速度很快(特别适用于临时表)。

使用方法:

CREATE TABLE tbl_name
( ...
  ...
) ENGINE=InnoDB;

CREATE TABLE tbl_name
( ...
  ...
) ENGINE=MyISAM;

注意:引擎类型可以混用,即不同的表可以使用不用的引擎类型。但是外键不能跨引擎,也就是使用一个引擎的表不能引用使用不同引擎表的外键。

5. ALTER修改表和约束

  1. 更改表的名字
alter table old_tbl_name rename to new_tbl_name;
  1. 增加列
ALTER TABLE tbl_name ADD col_name char(20);
  1. 修改列的字段
-- 修改字段名称
alter table tbl_name change old_col_name new_col_name type;
-- 修改字段类型
ALTER TABLE tbl_name MODIFY col_name char(20);
  1. 删除列
ALTER TABLE tbl_name DROP COLUMN col_name;

比较常用的Alter用法是对表添加约束,主要约束有主键约束、外键约束、check约束、unique约束、not null约束。

  1. 定义主键约束
ALTER TABLE tbl_name1 ADD CONSTRAINT pk_name PRIMARY KEY(col_name, ...); 
  1. 定义外键约束
ALTER TABLE tbl_name1 ADD CONSTRAINT fk_tblname1_tblname2 FOREIGN KEY (col_name1) REFERENCES tbl_name2 (col_name2);

-- 可以在创建表时同时创建外键约束
CREATE TABLE selectcourse
(
    sno char(8),
    cno char(10),
    score int not null default 0,
    constraint pk_sc primary key (sno, cno),  -- 主键
    constraint fk_sc_s foreign key(sno) references students(sno),
    constraint fk_sc_c foreign key(cno) references courses(cno)   
);
  1. 定义check约束
ALTER TABLE student ADD CONSTRAINT ck_student_sex CHECK(sex = '男' or sex = '女');
  1. 定义unique约束
ALTER TABLE tbl_name ADD CONSTRAINT uq_name UNIQUE(col_name);
  1. 定义not null约束
ALTER TABLE tbl_name MODIFY col_name NOT NULL;
-- 取消not null约束
ALTER TABLE tbl_name MODIFY col_name NULL;
  1. 删除约束
ALTER TABLE tbl_name DROP CONSTRAINT 约束名称;

6. LIMIT限制查询行数

6.1 LIMIT n用法

SELECT col_name FROM tbl_name
LIMIT 5;

其中LIMIT 5指示MySQL从行0开始,一共返回5行的数据。

6.2 LIMIT m, n用法

SELECT col_name FROM tbl_name
LIMIT 5,3;

其中LIMIT 5,3表示为MySQL从行5开始,一共返回3行数据。

注意:检索出来的第一行的行号为行0而不是行1。如LIMIT 1,1返回的其实是检索结果中的第二行数据,但是第二行数据的行号为行1。

6.3 LIMIT n OFFSET m用法

为了可读性更强,可以使用如下代码表示从行号5开始返回3行数据:

LIMIT 3 OFFSET 5

其中的OFFSET 5表示为起始行号为5,3表示为返回的数据行数为3。

7. MySQL中的正则表达式

正则表达式的作用是匹配文本,将一个模式(pattern,也即正则表达式)与一个文本串(text)比较,如果text中含有此pattern,则返回1,否则返回0。

可利用此性质在where子句中使用正则表达式获得相应的匹配数据行。

用法: REGEXP '正则表达式',表示利用正则表达式进行匹配。

7.1 基本字符的匹配

SELECT col_name 
FROM tbl_name
WHERE col_name REGEXP '1000'

分析:上述语句中的REGEXP '1000'表示匹配正则表达式1000,如果相应列值内容中含有1000子串,则返回此数据记录。

SELECT col_name
FROM tbl_name
WHERE col_name REGEXP '.000'

分析:上述语句中的REGEXP '.000'表示匹配正则表达式.000,其中的.表示匹配任意一个字符,所以如果相应列值内容中含有*000子串(星号代表任意字符),则返回此数据记录。

LIKE和 REGEXP 重要区别:

  • LIKE匹配整个串。如果被匹配的文本在列值中出现,LIKE不会找到它,相应的行也不会被返回。即如果LIKE后的匹配串中如果不带有通配符( % 或 _ ),则不会返回任何结果。
  • REGEXP匹配子串。如果被匹配的文本在列值中出现,REGEXP会找到它并将相应的行返回。

现在假如数据库中有表mytable,表中有id号为1000的数据记录,则下列代码会有不同的返回结果:

-- 无返回结果
SELECT *
FROM mytable
WHERE id LIKE '1000';

-- 有返回id为1000的数据行
SELECT *
FROM mytable
WHERE id REGEXP '1000';

注意:正则表达式默认匹配不区分大小写,若要区分大小写,用法为REGEXP BINARY '正则表达式',即在关键字REGEXP后添加BINARY关键字。

7.2 OR匹配

  1. 使用|符号

|为正则表达式中的OR操作符,它表示匹配其中之一。如下代码将匹配1或2或3:

REGEXP '1|2|3'
  1. 使用[]符号

[]是另一种形式的OR语句。上述代码可改写成:

REGEXP '[123]'

使用^符号可以对字符集合进行否定,如下代码表示匹配除1、2、3外的其它任何东西:

REGEXP '[^123]'
  1. 使用-定义范围

集合可用来定义要匹配的一个或多个字符,也可以定义一个要匹配的集合范围,为了简化这种范围的表示,可以使用-来定义集合的范围。如下:

REGEXP '[1-9]' < = > REGEXP '[123456789]'
REGEXP '[a-z]' -- 匹配任意字母字符(如果数据库配置为不区分大小写)

7.3 匹配特殊字符

正则表达式中包含了许多特殊的字符,如上述我们学到的.[]|-等,如果我们要匹配的正好是这些特殊字符,该怎么办呢?

⭐️ 为了匹配正则表达式中的特殊字符,在MySQL中必须使用\\进行转义。多数正则表达式实现用一个\,但在MySQL中要用两个,MySQL解释一个,正则表达式库解释另一个。

如:

REGEXP '\\.' -- 匹配.字符
REGEXP '\\|' -- 匹配|字符
REGEXP '\\\' -- 匹配\字符

空白元字符的转义:

元字符 说明
\\f 换页
\\n 换行
\\r 回车
\\t 制表
\\v 纵向制表

7.4 匹配字符类

为了更方便的工作,可以使用预定义的字符集,称为字符类

Posix字符类:

说明
[:alpha:] 任意字符(同[a-z][A-Z]
[:lower:] 任意小写字母(同[a-z]
[:upper:] 任意大写字母(同[A-Z]
[:digit:] 任意数字(同[0-9]
[:alnum:] 任意字母和数字(同[a-zA-Z0-9]
[:cntrl:] ASCII控制字符(ASCII 0到31和127)
[:punct:] 不在[:alnum:][:cntrl:]中的其他任意字符
[:blank:] 空格和制表(同[\\t]
[:space:] 包括空格在内的任意空白字符(同[\\f\\n\\r\\t\\v]
[:xdigit:] 任意十六进制数字(同[a-fA-F0-9]
[:print:] 任意可打印字符
[:graph:] 与[:print:]相同,但不包括空格

字符类的使用,如下语句代码:

REGEXP '[[:digit:]]{3}' < = > REGEXP '[0-9]{3}' < = > REGEXP '[0-9][0-9][0-9]'

上述代码表示匹配连在一起的任意3位数。

7.5 多实例匹配

正如上述匹配任意3位数的代码,其中就用到了匹配字符的3次出现,除了上述的[0-9]{3}用法之外还有另一些匹配多实例的元字符。

重复元字符:

元字符 说明
* 匹配0个或多个
+ 匹配1个或多个(同{1,})
匹配0个或1个(同{0,1})
{n} 匹配n个
{n,} 匹配[n,+∞]个
{n,m} 匹配[n,m]个

注意:使用上述重复元字符时一定要注意其涵盖的范围,如123?(123)?表示不同的匹配含义。

7.6 定位符

为了匹配特定位置的文本,需要使用定位符。

定位符:

元字符 说明
^ 文本的开始
$ 文本的结尾
[[:<:]] 词的开始
[[:>:]] 词的结尾
  1. ^的双重用途

在上述7.2中的第2个例子中,我们使用了正则表达式[^123]用来匹配除1、2、3外的其他字符,如果我们把正则表达式改为^[123]则表示匹配开始字符为数字1或2或3的文本。

总结:^符号用在[]外边,用来指串的开始处;用在[]里边,用来否定该集合。

  1. 使用^$匹配整个数据串,此时发挥和LIKE一样得效果。
REGEXP '^1000$' < = > LIKE '1000' -- 参照7.1 LIKE和REGEXP区别

7.8 简单的正则表达式测试

可以在不使用数据库表的情况下用SELECT来测试正则表达式。REGEXP检查总是返回0(没有匹配)或1(匹配)。可以用带文字串的REGEXP来测试表达式,并实验他们。相应的语法如下:

SELECT 'hello, world' REGEXP '[0-9]'

上述代码显然返回0,因为文本’hello, world’中没有数字。

8. MySQL中的函数

8.0 函数的简单测试方法以及取别名

对于下文将要介绍的函数,可以使用如下方式进行简单的测试而不需使用具体的数据库表格,但是使用函数检索结果的列名是以函数的复杂信息显示的,为了显示简洁及便于利用检索出来的值,我们可以使用关键字AS为新列取别名。

代码如下:

SELECT LENGTH('hello');
-- 显示结果
+----------------+
|LENGTH('hello') |
+----------------+
|              5 |
+----------------+

-- 对使用函数的新列取别名
SELECT LENGTH('hello') AS result;
-- 显示结果
+-------+
|result |
+-------+
|     5 |
+-------+

其余函数测试方法类似,不再赘述(有的不可以使用此方法测试,注意即可)。

8.1 文本处理函数

特别注意:MySQL中串下标从1开始而不是0。

本表格中函数参数省略。

函数 说明
Concat() 拼接串
Trim() 去掉串左右两边的空格
LTrim() 去掉串左边的空格
RTrim() 去掉串右边的空格
Upper() 将串转换为大写
SubString() 返回子串的字符
Locate() 找出串的一个子串
Length() 返回串的长度
Left() 返回串左边length长度的字符
Right() 返回串右边length长度的字符
Soundex() 返回串的soundex值
Reverse() 翻转串
  1. Concat()
SELECT CONCAT('col_name1=',col_name1,',col_name2=',col_name2) AS result
FROM tbl_name;
//输出形式
col_name1=col_name1的内容,col_name2=col_name2的内容
  1. Trim()LTrim()RTrim()
SELECT TRIM(col_name) AS result FROM tbl_name;
SELECT LTRIM(col_name) AS result FROM tbl_name;
SELECT RTRIM(col_name) AS result FROM tbl_name;
  1. Upper()
SELECT UPPER(col_name) AS result FROM tbl_name;
  1. SubString()
-- 从第n位开始,共截取m位
SELECT SUBSTRING(col_name,n,m) AS result FROM tbl_name;
-- 从第n位开始,截取到串尾
SELECT SUBSTRING(col_name,n) AS result FROM tbl_name;
  1. Locate()
-- 如果子串在主串(表的列值)中有匹配,返回在主串中第一个字符的下标
-- 如果不匹配则返回0
SELECT LOCATE(substring, string) AS result FROM tbl_name;

-- 从主串的pos位置开始往后匹配
SELECT LOCATE(substring, string, pos) AS result FROM tbl_name;

-- 常使用方式
-- 例如:从websites表中检索出网址的url列值中以‘https://’开头的行
SELECT * FROM websites
WHERE LACATE('https://', url) = 1  -- (如果‘=0’则表示不以‘https://’开头)

类似函数:

  • POSITION(substring IN string)

  • INSTR(string, substring)

不予详细介绍。

  1. Length()
SELECT LENGTH(col_name) AS result FROM tbl_name
  1. Left()Right()
-- 返回串左边length长度的字符
SELECT LEFT(string, length) AS result FROM tbl_name;
-- 返回串右边length长度的字符
SELECT LEFT(string, length) AS result FROM tbl_name;
  1. Soundex()
SELECT * FROM tbl_name
WHERE SOUNDEX(col_name) = SOUNDEX(string)

注意Soundex()函数是对串进行发音匹配比较而不是字母。

  1. Reverse()
-- 将串翻转
SELECT REVERSE(col_name) AS result FROM tbl_name;

8.2 时间日期处理函数

函数 说明
Now() 返回当前日期和时间
CurDate() 返回当前日期
CurTime() 返回当前时间
Date(date) 返回日期时间的日期部分
Time(date) 返回日期时间的时间部分
Year(date) 返回一个日期的年份部分
Month(date) 返回一个日期的月份部分
Day(date) 返回一个日期的天数部分
Hour(time) 返回一个时间的小时部分
Minute(time) 返回一个时间的分钟部分
Second(time) 返回一个时间的秒数部分
AddDate(date, INTERVAL expr unit) 增加一个间隔日期
Date_Add(date, INTERVAL expr unit) 增加一个间隔日期(高度灵活)
AddTime(date, datetime) 增加一个间隔时间
DateDiff(date1, date2) 计算两个日期之差(天数)
Date_Format(date, format) 返回格式化日期
DayOfWeek(date) 返回日期对应是星期几

参数说明:

  1. date为时间参数
  2. AddDate()Date_Add()中的参数
  • date:起始日期或者起始时间。

  • expr:指定的是一个间隔值,在起始时间中增加或者减少。expr是一个字符串,对于负值间隔,可以以"-"开头。

  • unit:表示的是一个单位(day/month/year),比如:加上的是1天还是一个小时。

  1. AddTime(date, datetime)中datetime格式如:‘1 2:3:0’(1天2小时3分钟0秒)

  2. Date_Format(date, format)中format可用格式:

格式 描述
%a 缩写星期名
%b 缩写月名
%c 月,数值
%D 带有英文前缀的月中的天
%d 月的天,数值(00-31)
%e 月的天,数值(0-31)
%f 微秒
%H 小时 (00-23)
%h 小时 (01-12)
%I 小时 (01-12)
%i 分钟,数值(00-59)
%j 年的天 (001-366)
%k 小时 (0-23)
%l 小时 (1-12)
%M 月名
%m 月,数值(00-12)
%p AM 或 PM
%r 时间,12-小时(hh:mm:ss AM 或 PM)
%S 秒(00-59)
%s 秒(00-59)
%T 时间, 24-小时 (hh:mm:ss)
%U 周 (00-53) 星期日是一周的第一天
%u 周 (00-53) 星期一是一周的第一天
%V 周 (01-53) 星期日是一周的第一天,与 %X 使用
%v 周 (01-53) 星期一是一周的第一天,与 %x 使用
%W 星期名
%w 周的天 (0=星期日, 6=星期六)
%X 年,其中的星期日是周的第一天,4 位,与 %V 使用
%x 年,其中的星期一是周的第一天,4 位,与 %v 使用
%Y 年,4 位
%y 年,2 位

例如:

8.3 数值处理函数

本表格中函数参数省略。

函数 说明
Abs() 返回一个数的绝对值
Exp() 返回一个数的指数
Sqrt() 返回一个数的平方根
Mod() 返回除操作的余数
Pi() 返回圆周率
Rand() 返回一个随机数
Sin() 返回一个角度的正弦
Cos() 返回一个角度的余弦
Tan() 返回一个角度的正切

8.4 聚集函数

本表格中函数参数省略。

函数 说明
COUNT() 返回某列的行数
SUM() 返回某列的和
AVG() 返回某列的平均值
MAX() 返回某列的最大值
MIN() 返回某列的最小值

注意

  1. 对NULL值是否忽略

上表格聚集函数都自动忽略NULL值,除了如下这种特殊情况:

  • 如果使用COUNT()时指定列名,即COUNT(col_name)时,此函数会忽略NULL值;
  • 如果使用COUNT(*)时,则不会忽略NULL值。
  1. 使用标准的算术操作符,所有的聚集函数都可以用来执行多个列上的计算。

如:

SELECT SUM(col1*col2) AS result FROM tbl_name;

8.5 函数应用位置

函数不仅可以使用在SELECT后面,也可以使用在WHERE子句后面进行过滤数据。

-- 检索出日期在2017-01-01到2020-01-01之间的所有行
SELECT * FROM tbl_name
WHERE DATE(col_name) = BETWEEN '2017-01-01' AND '2020-01-01'

其余用法类似,在此不再赘述。

9. 数据分组与排序

  1. 使用GROUP BY对数据分组
  • GROUP BY后跟的列必须在SELECT子句中给出,除了聚集函数。
  • GROUP BY不能使用别名。
  • 如果使用GROUP BY,那么聚集函数作用域是每个分组。
  • 使用HAVING对分组过滤。WHERE过滤行,HAVING过滤分组,除了关键字不同,语法都是一致的。
  1. 使用ORDER BY对数据排序
  • ORDER BY默认排序类型为:升序排列ASC,降序排列需要使用关键字:DESC。每个关键字只作用一列。
  • ORDER BY可以不使用SELECT语句后的列而使用表中其它列进行排序。
  • ORDER BY对多列进行排序时,只有当前一列值相同时,才会对后一列进行排序。
  • ORDER BY是对上述所有结果的排序,最多只允许出现一次,且在最末(但在LIMIT之上)。
  1. MySQL语句顺序
SELECT col_name [col_name2|...]
FROM tbl_name
WHERE condition_for_row
GROUP BY col_name [col_name2|...]
HAVING condition_for_group
ORDER BY col_name [ASC|DESC]
LIMIT n [,m]

注意:顺序错误将会导致错误信息。

10. 子查询、联结查询和组合查询

10.1 子查询

分为相关子查询和不相关子查询。(注意区别它们的检索的先后嵌套顺序)

  • 不相关子查询:子查询和外部查询无关,先进行子查询,然后再进行外部查询。

  • 相关子查询:涉及外部查询的子查询

-- 不相关子查询
SELECT col_name1
FROM tbl_name1
WHERE col_name2 IN (SELECT col_name2
					FROM tbl_name2
					WHERE col_name3 = 'example');

-- 相关子查询
SELECT col_name1
FROM tbl_name1 AS t1
WHERE col_name2 IN (SELECT col_name2
                    FROM tbl_name2 AS t2
                    WHERE t1.id = t2.id);

10.2 联结查询

将多个表联结起来查询,有自联结、内联结(也称等值联结)、外联结(左、右)。

(1)自联结

同一张表进行连接,通常需要为表取别名。

如下代码:

SELECT col_name1, col_name2
FROM tbl_name AS t1, tbl_name AS t2
WHERE t1.id = t2.id AND p2.num = '1001'

也可以使用子查询来代替自联结查询,但通常情况下要测试一下这两种方式哪种的性能更好。

使用子查询代替自联结的代码如下:

SELECT col_name1, col_name2
FROM tbl_name
WHERE tbl_name.id = (SELECT id
					 FROM tbl_name
					 WHERE num = '1001');

(2)内联结/等值联结:

SELECT col_name1, col_name2
FROM tbl_name1 INNER JOIN tbl_name2
ON tbl_name1.id = tbl_name2.id;
-- 等值联结使用where实现
SELECT col_name1, col_name2
FROM tbl_name1 AS t1, tbl_name2 AS t2
WHERE t1.id = t2.id;

自然连接为一种特殊的等值联结,它是等值联结后消除了相同的列。

(3)外联结

-- 左外联结,左表的内容全部显示
SELECT col_name1, col_name2
FROM tbl_name1 LEFT OUTER JOIN tbl_name2
ON tbl_name1.id = tbl_name2.id;
-- 右外联结,右表的内容全部显示
SELECT col_name1, col_name2
FROM tbl_name1 RIGHT OUTER JOIN tbl_name2
ON tbl_name1.id = tbl_name2.id;

(4)使用联结和联结条件

  • 注意所使用的联结类型。一般使用内部联结(等值联结),但使用外部联结也是有效的。
  • 始终给出联结条件,并保证联结条件的正确性。(如果不给出联结条件会返回笛卡尔积,如果联结条件错误会返回错误数据)
  • 分别测试每个联结,有助于排除故障。

10.3 组合查询

使用关键字UNION进行组合查,但是结果会自动去掉重复行,如果想保留重复行则需使用UNION ALL

其他注意地方:

  • UNION必须由两条或两条以上的SELECT语句组成,语句之间用UNION关键字分开。
  • UNION中的每个查询必须要包含相同的列、表达式或聚集函数(但是不要求顺序一致)。
  • 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含转换的类型(如不同的数值类型或不同的日期类型)

11.全文本搜索

11.1 定义全文本搜索

首先应确保将要使用全文本搜索的表引擎类型为:MyISAM类型。其次使用全文本搜索,必须索引被搜索的列,使用关键字FULLTEXT(col_name)指定可以全文本索引的列,如果需要也可以指定多个列。可以在创建表时指定FULLTEXT,也可以稍后指定,在定义之后,MySQL会自动维护该索引,在增加、更新或删除行时,索引会随之更新。

注意:不要在导入数据时使用FULLTEXT索引,因为每次导入都会更新索引会花费更多时间,应该先导入数据,然后再修改表来定义FULLTEXT

11.2 使用全文本搜索

对定义全文本搜索的列使用函数Match()Against()进行全文本搜索,Match()用于指定被搜索的列,Against()用于指定搜索表达式。

如:

SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('example')   -- 不区分搜索文本的大小写

分析:从表中可全文本搜索的列中搜索含有 ’ example ’ 值的文本,并返回数据行。MATCH(indexed_col) AGAINST('example')语句可以使用在WHERE子句中,也可以用作计算字段SELECT子句中 。

注意:传递给Match()的值必须与FULLTEXT()定义中相同,如果指定多个列,则必须以正确次序列出它们。

使用FULLTEXTLIKE的重要区别:

  • FULLTEXT按文本匹配程度返回数据行(匹配等级高→匹配等级低)。全文本搜索会对每个列值数据的匹配程度生成一个匹配等级值,匹配等级越高代表匹配程度越大,全文本搜索会把匹配结果排序,较高匹配等级的先返回,因为这些数据通常恰恰就是我们需要的。
  • 使用FULLTEXT数据是被索引的,因此全文本搜索速度更快。

11.3 扩展查询

扩展查询是在使用全文本搜索时,利用查询结果再进行查询,以获得可能相关的结果。使用关键字WITH QUERY EXPANSION进行扩展查询,如:

SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('example' WITH QUERY EXPANSION)  

使用查询的扩展时,当表中的数据行越多时,返回的结果越好。

11.4 布尔文本搜索

使用关键字IN BOOLEAN MODE对文本进行布尔搜索,当没有使用FULLTEXT索引时也可以使用布尔文本搜索,只是这时其速度极慢并且当数据量增加时性能会大大降低。

全文本布尔操作符

布尔操作符 说明
+ 包含,词必须存在
- 排除,词必须不出现
> 包含,而且增加等级值
< 包含,而且减少等级制
() 把词组成表达式(允许这些子表达式作为一个组被包含、排除、排列等)
~ 取消一个词的排序值
* 词尾的截断符(也可以看作是一个通配符)
“” 定义一个短语(它匹配整个短语以便包含或排除这个短语,不是单个词语)

(1)搜索匹配包含 yes 和 no 中至少一个词的行:

SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('yes no' IN BOOLEAN MODE )  

(2)搜索匹配包含 yes 但不包含 no 的行:

SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('+yes -no' IN BOOLEAN MODE )  

(3)搜索匹配包含 yes 和 no 中至少一个词的行,并增加 yes 的等级,降低 no 的等级

SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('>yes 

(4)搜索匹配短语"yes no"的行:

SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('"yes no"' IN BOOLEAN MODE )  

(5)搜索匹配词 yes 和 no,降低后者的等级:

SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('+yes +(

总结

以布尔方式,可以提供关于如下内容的细节:

  • 要匹配的词
  • 要排斥的词(如果某行包含这个词语,则不返回该行,即使它包含其他指定的词也是如此)
  • 调整等级(指定某些词比其他词更重要,更重要的词等级更高)
  • 表达式分组
  • 其他内容

全文本搜索的使用说明:

  • 仅在MyISAM数据库引擎中支持全文本搜索。
  • 许多词出现的频率很高,但实际用处很少。因此MySQL规定了一条50%规则,如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用于IN BOOLEAN MODE
  • 如果表中的行数少于3行,则全文本搜索不返回任何结果。
  • 在索引全文本数据时,短词(具有3个或3个以下字符的词)被忽略且从索引中排除,短语定义可以修改。
  • MySQL带有一个内建的非用词列表,这些词在索引全文本数据时总是被忽略。如果需要,可以覆盖这个列表。
  • 忽略词中的单引号。如:I’m索引为Im。
  • 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果。

12. 增删改查

12.1 插入数据

  1. 插入的方式
  • 插入完整的行
  • 插入行的一部分
  • 插入多行
  • 插入某些查询的结果

插入完整的行,不安全,如下:

insert into tbl_name values(v1, v2, ...);

编写insert语句的更安全的方法:将列名标出来,如下:

insert into customers(col1, col2, ...) values(v1, v2, ...);

如果表的定义允许,则可以在insert操作中省略某些列。省略的列必须满足以下某个条件:

  • 该列定义为允许NULL值
  • 在表定义中给出默认值。

如果对表中不允许null且没有默认值的列不给出值,则mysql将报错。

提高整体性能

数据库经常被多个客户访问,insert会很耗时,而且可能降低等待处理的select语句的性能。如果数据检索是重要的,可以通过在insert和into之间添加关键字LOW_PRIORITY,指示mysql降低insert语句的优先级。如下:

INSERT LOW_PRIORITY INTO ...

另外,LOW_PRORITY也适用于UPDATE和DELETE语句

  1. 插入多行

values后面直接跟多组数据,数据间用逗号隔开

insert into customers(col1, col2, ...) values(v1, v2, ...),
                                             (v3, v4, ...),
                                             (v5, v6, ...);
  1. 插入检索出来的数据

利用insert将一条select语句的结果插入表中,即所谓的insert select语句。由一条insert和一条select语句组成,如下:

INSERT INTO customers(col1, col2, ...)
SELECT col1, col2, ...
FROM tbl_name
WHERE ...
  1. 创建表时插入数据

利用已有的source表,创建新表时使用source表中的某些列创建,如下:

CREATE TABLE tbl_name AS
SELECT col1,col2, ...  FROM source_table;

其中:tbl_name是创建的新表的名称,col1col2等是已存在表source中的列名称。

12.2 更新数据(注意使用安全)

  1. 更新方式
  • 更新特定行(一定要where,where一定要正确筛选到)
  • 更新所有行
  1. 删除某个列

UPDATE还用于删除某个的值,即清空某一列的值,使用UPDATE而不是DELETE,如下:

UPDATE tbl_name
SET col = NULL
WHERE ...
  1. IGNORE关键字

如果用UPDATE语句更新多行,并且在其中一行出错,则会回退取消整个UPDATE操作,如果要求即使发生错误也继续进行更新,可使用IGNORE关键字,如下:

UPDATE IGNORE tbl_name ...

12.3 删除数据(注意使用安全)

  1. 删除方式
  • 删除特定行(一定要where,where一定要正确筛选到)
  • 删除所有行
  1. 更快的删除

如果想删除表中所有的行,可使用TRUNCATE TABLE语句,它完成删除表格相同的工作,但速度更快(删除原来的并重新建一个表,而不是逐行删除表中的数据)。

重要

为了保证UPDATE和DELETE操作不误伤(没有where或者where的效果不同于预期):

  1. 先测试WHERE子句对不对,确保它过滤的是正确的记录;
  2. 使用强制实施引用完整性的数据库,这样与其他表有关联的行也不能被删除。

13. 视图

视图是虚拟的表,是几个表联结查询的动态结果。
视图不存储数据,每次查看视图时,要重新执行查询底表语句,因此大型、复杂视图性能低。

13.1 为何使用视图

  • 重用SQL语句,简化复杂查询,不必重复编写查询联结细节;
  • 保护数据,可以给用户授权只能访问表的一部分数据;
  • 更改数据格式和表示,与底表可以不同。

13.2 视图的规则与限制

  • 视图名字必须唯一;
  • 视图数目无限制;
  • 创建视图需要有相应表的访问权限;
  • 视图可以嵌套,即联结其他视图来创建新视图;
  • 视图中order by作用,会被基表中的order by覆盖;
  • 视图不能有索引、触发器、默认值;
  • 视图可以和表一起使用,即连接查询。

13.3 使用视图

  1. 创建视图
CREATE VIEW view_name AS SELECT ...
  1. 查看创建视图的语句
SHOW CREATE VIEW view_name;
  1. 删除视图
DROP VIEW view_name;

如果指定的视图不存在,则DROP VIEW将产生一个错误。可以使用如下语句防止产生错误:

DROP VIEW IF EXISTS view_name;
  1. 更新视图
  • 先删除视图,再重新创建;
  • 使用create or replace view view_name,如果视图不存在就创建,视图存在就替换。

如果视图定义中有以下操作,则不能进行视图更新:

  • 分组(GROUP BY、HAVING);
  • 联结;
  • 子查询;
  • 并查询(组合查询UNION);
  • 聚集函数;
  • 唯一值(DISTINCT);
  • 计算列。

注意:一般应将视图用于检索,而非更新。对视图的增、删、改,实际是对底表数据进行操作。

14. 存储过程

存储过程,简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。

可将其视为批文件,虽然他们的作用不仅限于批处理。

14.1 优缺点

  • 优点

  • 执行效率非常快!存储过程是在数据库的服务器端执行

    • 简化复杂操作。因为把处理封装在容易使用的单元中;

    • 保证了数据的完整性。不要求反复建立一系列处理步骤(防止错误);

    • 简化对变动的管理。如果表名、列名或业务逻辑有变化,只需要修改存储过程的代码。使用它的人员甚至不需要知道这些变化(减少了数据讹误,确保了安全性);

    • 提高性能。存储过程比单独的SQL语句要快;

    • 代码更强更灵活。存在一些只能用在单个请求中的MySQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。

  • 缺点

    • 存储过程比SQL语句复杂得多;
    • 移植性很差,不同的数据库的存储过程是不能移植的;
    • 并不是所有人都有创建存储过程的安全访问权限。

14.2 创建存储过程

CREATE PROCEDURE proc_name([ [IN|INOUT|OUT] param_name TYPE|...])
BEGIN
    SELECT ...
    FROM tbl_name;
END;

注意

(1)BEGINEND用来限定存储过程体。

(2)默认的MySQL分隔符为;,但是存储过程中包含有;,这会使存储过程中的SQL语句出现句法错误。解决办法就是临时更改命令行实用程序的语句分隔符:

DELIMITER $
CREATE PROCEDURE proc_name([ [IN|INOUT|OUT] param_name TYPE| ... ])
BEGIN
    SELECT ...
    FROM tbl_name;
END $
DELIMITER ;

DELEMITER $ 告诉实用程序实用$作为新的语句结束分隔符,可以看到标志存储过程结束的END定义为END $。这样存储体内的;可以保持不变,正确地传递给引擎,最后再恢复为原来的语句分隔符;。除了\之外都可定义为分隔符,\一般用为转义符。

(3)没有参数的存储过程也不能省略(),它就相当于一个空参的函数,调用时也要遵守这一原则。

(4)如果有参数,要明确参数类型:数据类型和输入输出类型(IN/OUT/INOUT):

  • OUT:用来从存储过程传出一个值,返回给调用者;
  • IN:把参数传递给存储过程;
  • INOUT:对存储过程传入和传出。

如下代码所示:

DELIMITER $
CREATE PRODUCER proc_name(IN param1 INT, OUT param2 DECIMAL(8, 2))
BEGIN
   SELECT Min(col_name)
   FROM tbl_name
   WHERE id = param1
   INTO param2;
END $
DELIMITER ;

注意:IN类型参数和OUT类型参数的位置。

14.3 查看存储过程

(1)SHOW PROCEDURE STATUS列出所有存储过程,为了限制其显示某些特定的存储过程,可以用LIKE关键字指定一个过滤模式:

SHOW PROCEDURE STATUS LIKE 'proc_name'

(2)如果要获得存储过程的详细信息,可以使用SHOW语句进行显示:

SHOW CREATE PROCEDURE proc_name; -- 只给出存储过程名字

注意:此时只给出存储过程名字即可,不再加()

14.4 执行存储过程

MySQL中使用关键字CALL来执行存储过程,CALL接收存储过程的名字以及需要传递给它的任意参数(变量)

变量是内存中一个特定的位置,用来临时存储数据。

所有MySQL的变量都必须以@开始。

针对上述的带参存储过程,执行语句如下:

CALL proc_name(1001, @result);

其中的1001是传入给存储过程,变量@result是由存储过程传出的值。

一般情况下,带有输出变量的存储过程执行后并不显示结果,而是把结果返回给你指定的变量(如上述的@result),若要显示结果,则需另外执行SELECT语句显示返回结果,如下:

SELECT @result;

14.5 删除存储过程

DROP PROCEDURE proc_name;  

此时仍然只给出存储过程名字即可,不再加()。如果指定的存储过程不存在,则DROP PROCEDURE将产生一个错误。可以使用如下语句防止产生错误:

DROP PROCEDURE IF EXISTS proc_name;

14.6 建立复杂存储过程

复杂存储过程可能用到的关键字:

  • – : 注释

  • DECLARE:定义局部变量。形式如:DECLARE variable_name TYPE; 变量名前不用加@符号

  • IF:条件语句,还支持ELSEIF(使用THEN), ELSE(不使用THEN)语句

  • COMMENT:不是必需的,但是如果给出,将在SHOW PROCEDURE STATUS的结果中显示,

一个实例:

考虑这个场景:有一个订单表需要获得订单合计,但需要对合计增加营业税,不过只针对某些客户。

根据场景列出存储过程中应执行的事件:

  1. 获得合计;
  2. 把营业税有条件地添加到合计;
  3. 返回合计(带税或不带税)。

源代码如下:

-- Name:ordertotal
-- Parameters:onumber = order number
--            taxable = 0 if not taxable, 1 if taxable
--            ototal = order total variable

DELIMITER $
CREATE PROCEDURE ordertotal(IN onumber INT, IN taxable BOOLEAN,OUT ototal DECIMAL(8, 2)) 
COMMIT "obtain order total, optionally adding tex"
BEGIN
  -- Declare variable for total
  DECLARE total DECIMAL(8, 2);
  -- Declare tax percentage
  DECLARE taxrate INT DEFAULT 6;

  -- Get the order total
  SELECT Sum(item_price*quantity)
  FROM orderitems
  WHERE order_num = onumber
  INTO total;
  
  -- Is it taxable?
  IF taxable THEN
    --   Yes, so add taxrate to the total
    SELECT total+(total/100*taxrate) INTO total;
  END IF;
  -- And finally, save to out variable
  SELECT total INTO ototal;
END $
DELIMITER ;

执行存储过程并显示结果:

CALL orderototal(20005, 0, @total);
SELECT @total;

15. 触发器

MySQL中的触发器概念,和Java中的事件监听器有点相似。当你想要某条语句在某个事件发生时自动执行,就要用到触发器了。

触发器能响应如下三类语句:DELETE、INSERT和UPDATE。

15.1 创建触发器

创建须知

  • 只有表才支持触发器,视图不支持,临时表也不支持;
  • 每个表的每个事件每次只允许一个触发器;
  • 每个表最多支持6个触发器(即每个INSERT、UPDATE和DELETE可以选择使用BEFORE或AFTER修饰);
  • 单一触发器不能与多个事件或多个表关联,所以如果需要一个对INSERT和UPDATE操作执行的触发器,则应该定义两个触发器。

创建触发器时,需要给出4条信息:

  1. 唯一的触发器名
  2. 触发器关联的表
  3. 触发器应该响应的活动(DELETE、INSERT、UPDATE)
  4. 触发器何时执行(处理之前或之后)

创建代码如下:

CREATE TRIGGER tri_name
AFTER INSERT ON tbl_name FOR EACH ROW 
SELECT 'insert success';

分析:

CREATE TRIGGER用来创建名为tri_name的新触发器。触发器可在一个操作发生之前或之后执行,这里给出了AFTER INSERT,所以此触发器将在INSERT语句成功执行后执行。这个触发器还指定FOR EACH ROW,因此代码对每个插入行执行。在这个例子中,文本“insert success”将对每个插入的行显示一次。

15.2 INSERT触发器

INSERT触发器在INSERT语句执行之前或之后执行 :

  • 在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行;
  • 在BEFORE INSERT触发器中,NEW的值也可以被更新(允许更改被插入的值);
  • 对于AUTO_INCREMENT列,NEW在INSERT执行前包含0,在INSERT被执行后包含新的自动生成值。

如下代码:

CREATE TRIGGER tri_name
AFTER INSERT ON tbl_name FOR EACH ROW
SELECT NEW.col_name INTO @vari;

分析:

此代码创建一个名为tri_name的触发器,在插入新信息到tbl_name表并成功后,插入信息会保存在NEW表中,触发器从NEW表中取得col_name的值并赋给变量@vari,因为从MySQL 5以后不支持触发器返回结果集,可以执行SELECT @vari来显示它的值。

注意

  • 使用BEFORE还是AFTER:通常,将BEFORE用于对NEW表进行数据验证和净化(目的是保证插入表中的数据确实是需要的数据),此条也适用于UPDATE触发器。
  • 触发器失败:如果BEFORE触发器失败,则MySQL将不执行请求的操作。此外,如果BEFORE触发器或语句本身失败,MySQL将不执行AFTER触发器(如果有的话)。

15.3 DELETE触发器

DELETE触发器在DELETE语句执行之前或之后执行:

  • 在DELETE触发器代码内,可以引用一个名为OLD的虚拟表,访问被删除的行;
  • OLD中的值全部都是只能读的,不能更新

如下代码:

DELIMITER $
CREATE TRIGGER tri_name
BEFORE DELETE ON tbl_name FOR EACH ROW
BEGIN
    INSERT INTO archive_table(id, name, age) VALUES(OLD.id, OLD.name, OLD.age);
END $
DELIMITER ;

分析:

在任意订单被删除将执行此触发器。它使用一条INSERT语句将OLD中的值(要被删除的订单信息)保存到一个名为archive_table的存档表中(为实际使用这个例子,你需要建立一个和被删除信息表具有相同结构的archive_table表)。

★相对于AFTER DELETE触发器来说,使用BEFORE DELETE触发器的优点为:如果由于某种原因,订单不能存档,那么DELETE本身将被放弃,也即不再执行DELETE操作。

使用BEGIN END块的好处是触发器能容纳多条SQL语句。

15.4 UPDATE触发器

UPDATE触发器在UPDATE语句执行之前或之后执行:

  • 在UPDATE触发器代码中,对于更新前的旧值,可以引用OLD虚拟表访问;对于新值,可以引用NEW虚拟表访问;
  • 在BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改将要用于UPDATE语句中的值);
  • OLD中的值全都是只读的,不能更新。

代码如下:

CREATE TRIGGER tri_name
BEFORE UPDATE ON tbl_name FOR EACH ROW
SET NEW.name = Upper(NEW.name);

分析:此代码表示在执行更新前,把将要插入的数据中的name值全部转换为大写,以此来净化插入数据。

15.5 删除触发器

DROP TRIGGER [if exists] tri_name;

注意:触发器不能更新或覆盖。为了修改一个触发器,必须先删除它,然后再重新创建。

15.6 触发器进一步介绍

  • 与其他DBMS相比,MySQL 5中支持的触发器相当初级。未来的MySQL版本中有一些改进和增强触发器支持的计划。
  • 创建触发器可能需要特殊的安全访问权限,但是,触发器的执行是自动的。如果INSERT、UPDATE或DELETE语句能够执行,则相关的触发器也能执行。
  • 应该用触发器来保证数据的一致性(大小写、格式等)。在触发器 中执行这种类型的处理的优点是它总是进行这种处理,而且是透明地进行,与客户机应用无关。
  • 触发器的一种非常有意义的使用是创建审计跟踪。使用触发器,把更改(如果需要,甚至还有之前和之后的状态)记录到另一个表非常容易。
  • 遗憾的是,MySQL触发器中不支持CALL语句。这表示不能从触发器内调用存储过程。所需的存储过程代码需要复制到触发器内。

16.事务

16.1 什么是事务?

在JDBC中怎样将多个SQL语句组合成一个事务呢?在JDBC中,打开一个连接对象Connection时,缺省是auto-commit模式,每个SQL语句都被当作一个事务,即每次执行一个语句,都会自动的得到事务确认。为了能将多个SQL语句组合成一个事务,要将auto-commit模式屏蔽掉。在auto-commit模式屏蔽掉之后,如果不调用commit()方法,SQL语句不会得到事务确认。在最近一次commit()方法调用之后的所有SQL会在方法commit()调用时得到确认。

16.2 事务的ACID性质

  • 原子性( Atomicity):一组事务,要么全部执行,要么不执行。

  • 一致性 (Consistency):事务执行后,数据库状态与其他业务规则保持一致。如转账业务,无论事务执行成功否,参与转账的两个账号余额之和应该是不变的。

  • 隔离性(Isolation):事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。

  • 持久性(Durability):软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit 选项决定什么时候吧事务保存到日志里。

16.3 MySQL中的事务

在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。开启事务之后MySQL会关闭自动提交功能。

手动关闭自动提交,代码为:

set autocommit = 0;

开启事务:

start transaction;
-- OR
begin;

结束事务:

commit;
-- OR
rollback;

在执行SQL语句之前,先执行start transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所作出的影响会持久到数据库中,或者rollback,表示回滚到事务的起点,之前做的所有操作都被撤销了。

16.4 JDBC事务

在JDBC中处理事务,都是通过Connection完成的。同一事务中所有的操作,都在使用同一个Connection对象。

Connection的三个方法与事务有关:

  • setAutoCommit(boolean):设置是否为自动提交事务,如果true(默认值为true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置为false,那么相当于开启了事务了。

  • commit():提交结束事务。

  • rollback():回滚结束事务。

JDBC处理事务的代码格式:

try {
     
    con.setAutoCommit(false);//开启事务
    
    ......
    
    con.commit();//try的最后提交事务   

} catch(Exception e) {
     
    con.rollback();//回滚事务
}

17. ResultSet

ResultSet是一个游标,每次只能指向某一行,通过游标可以取当前行的列值。游标可以移动指向不同行。

17.1 创建支持滚动游标

Statement cmd =
conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
ResultSet rs = cmd.executeQuery(sql);
rs.first();//移到第一行
rs.last();//移到最后行
rs.next();//移到下一行
rs.previous();//移到上一行
rs.absolute(4); //移到第4行
rs.relative(2); //在当前行的位置向下2行,如果是负数则向上移动指定行数

17.2 创建支持更新的游标

Statement cmd =
con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet rs = cmd.executeQuery(sql);

  rs.deleteRow();                  // 删除当前行
  rs.first();                      // 移到第一行
  rs.updateString(2,"zhang san");  // 更新第2列
  rs.updateRow();                  // 刷新到数据库

18. MySQL数据类型

MySQL中定义数据字段的类型对你数据库的优化是非常重要的。

MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。

18.1 数值类型

MySQL支持所有标准SQL数值数据类型。

这些类型包括严格数值数据类型(INTEGERSMALLINTDECIMALNUMERIC),以及近似数值数据类型(FLOATREAL和DOUBLE PRECISION)。

关键字INTINTEGER的同义词,关键字DECDECIMAL的同义词。

BIT数据类型保存位字段值,并且支持MyISAMMEMORYInnoDBBDB表。

作为SQL标准的扩展,MySQL也支持整数类型TINYINTMEDIUMINTBIGINT。下面的表显示了需要的每个整数类型的存储和范围。

类型 大小 范围(有符号) 范围(无符号) 用途
TINYINT 1 byte (-128,127) (0,255) 小整数值
SMALLINT 2 bytes (-32 768,32 767) (0,65 535) 大整数值
MEDIUMINT 3 bytes (-8 388 608,8 388 607) (0,16 777 215) 大整数值
INTINTEGER 4 bytes (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值
BIGINT 8 bytes (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值
FLOAT 4 bytes (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 单精度 浮点数值
DOUBLE 8 bytes (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度 浮点数值
DECIMAL 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 依赖于M和D的值 依赖于M和D的值 小数值

18.2 日期和时间类型

表示时间值的日期和时间类型为DATETIMEDATETIMESTAMPTIMEYEAR

每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。

TIMESTAMP类型有专有的自动更新特性,将在后面描述。

类型 大小 ( bytes) 范围 格式 用途
DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 日期值
TIME 3 ‘-838 : 59 : 59’/‘838 : 59 : 59’ HH:MM:SS 时间值或持续时间
YEAR 1 1901/2155 YYYY 年份值
DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 混合日期和时间值
TIMESTAMP 4 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和时间值,时间戳

18.3 字符串类型

字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。

类型 大小 用途
CHAR 0-255 bytes 定长字符串
VARCHAR 0-65535 bytes 变长字符串
TINYBLOB 0-255 bytes 不超过 255 个字符的二进制字符串
TINYTEXT 0-255 bytes 短文本字符串
BLOB 0-65 535 bytes 二进制形式的长文本数据
TEXT 0-65 535 bytes 长文本数据
MEDIUMBLOB 0-16 777 215 bytes 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16 777 215 bytes 中等长度文本数据
LONGBLOB 0-4 294 967 295 bytes 二进制形式的极大文本数据
LONGTEXT 0-4 294 967 295 bytes 极大文本数据

注意

  • char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。

  • CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。

  • BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。

  • BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。

  • 有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。

关于 char、varchar 与 text 平时没有太在意,一般来说,可能现在大家都是用 varchar。但是当要存储的内容比较大时,究竟是选择 varchar 还是 text 呢?

这三种类型比较:

  1. char: char 不用多说了,它是定长格式的,但是长度范围是 0~255. 当你想要储存一个长度不足 255 的字符时,MySQL会用空格来填充剩下的字符。因此在读取数据时,char 类型的数据要进行处理,把后面的空格去除。
  2. varchar: 关于 varchar,有的说最大长度是 255,也有的说是 65535,查阅很多资料后发现是这样的:varchar 类型在 5.0.3 以下的版本中的最大长度限制为 255,而在 5.0.3 及以上的版本中,varchar 数据类型的长度支持到了 65535,也就是说可以存放 65532 个字节(注意是字节而不是字符!!!)的数据(起始位和结束位占去了3个字节),也就是说,在 5.0.3 以下版本中需要使用固定的 TEXT 或 BLOB 格式存放的数据可以在高版本中使用可变长的 varchar 来存放,这样就能有效的减少数据库文件的大小。
  3. text: 与 char 和 varchar 不同的是,text 不可以有默认值,其最大长度是 2 的 16 次方-1

总结起来,有几点:

  • 经常变化的字段用 varchar
  • 知道固定长度的用 char
  • 尽量用 varchar
  • 超过 255 字符的只能用 varchar 或者 text
  • 能用 varchar 的地方不用 text

19. NOT NULL 和 DEFAULT

MySQL在建表时,需要有字段名称字段类型约束条件,其中字段名称和字段类型是必填的,约束条件是选填的,约束条件主要有PRIMARY KEY、UNIQUE、NOT NULL、DEFAULT等, 一个完整的建表语句如下:

CREATE TABLE students
(    sno varchar(4) PRIMARY KEY,
     name VARCHAR(10) NOT NULL,
     score INT DEFAULT 0
);

19.1 NOT NULL

NOT NULL是非空的约束,即不能向表里插入空值。还是用students这个表,现在向表里插入数据: INTSERT INTO students VALUE("0002", NULL, 85);会报错,因为在建表时,姓名字段的约束条件是NOT NULL。

值得注意的是""空字符串不等同于NULL,我们向表里的姓名字段插入空字符串,INSERT INTO employees VALUE("0003","",18);是不会报错的,在MySQL里,""空字符串不是NULL,如果想要输入空值必须是NULL,另外空字符串是可以计算的,比如 SELECT length("");SELECT ""+1; 都是有结果输出的。

19.2 DEFAULT

DEFAULT是在不给字段输入值时,默认的值。我们在创建students表时,分数字段默认为0,向表插入数据:INSERT INTO students(sno,name) VALUE("0004","张三");,没有向分数字段插入数据,那么就会自动填充0作为默认分数。

当给分数字段插入数据,比如空值NULL,是不会触发default的,向表插入数据:INSERT INTO employees VALUE("0005", "李四", NULL);,那么李四的分数值就为NULL而不是0,DEFAULT只有在不给字段数据时才会使用

19.3 NOT NULL & DEFAULT

建表语句如下,我们给姓名字段的约束是非空,如果不给数据,默认为未知:

CREATE TABLE students2
(    sno VARCHAR(4) PRIMARY,
     name VARCHAR(10) NOT NULL DEFAULT "未知",
     score INT
);

根据上文对NOT NULL和DEFAULT的介绍,当向表插入数据时,如果给姓名字段具体值时不会报错;如果给了姓名字段空值NULL时,会触发NOT NULL约束,但不会触发DEFAULT约束,因为DEFAULT只有在不给字段数据时才会使用,所以此条语句报错(因使用了空值);如果不给姓名字段数据,INSERT INTO students2(sno,score) VALUE("0002",90);,则会触发DEFAULT,给姓名默认值"未知"。

所以NOT NULL和DEFAULT是两个独立的约束,可以用在一个字段上,但不会交互使用,是两个独立的约束条件。另外约束条件不仅是在插入数据时有用,当我们在对表数据进行修改时,也会受到约束条件的限制。

20. 事务处理

一个或多个数据库操作组成“事务”,也就是说,事务实际上是一组按顺序执行的操作单位。事务具有如下性质(ACID):

  • 原子性:整个事务为整体执行,要么全部执行,要么不执行。
  • 一致性:条件约束,如航班数据库,则“一个座位不能分配给两名不同的顾客”就是一种适当的一致性条件。
  • 隔离性:两个或更多事务并发执行时,作用效果必须相互独立,不能相互影响。
  • 持久性:事务一旦完成,即便系统出现故障,也要保证事务的结果不能丢失。

事务的开始用 START TRANSACTION,提交用 COMMIT,遇到故障要回滚使用 ROLLBACK(当COMMIT或ROLLBACK语句执行后,事务会自动关闭)。

如下:

SELECT * FROM tbl_name; 
START TRANSACTION;  -- 开始事务
DELETE FROM ordertotals;
...
COMMIT | ROLLBACK;  -- 提交或事务回退

对于ROLLBACK回滚来讲:

  • 只能在一个事务处理内使用;
  • 管理INSERT、UPDATE、DELETE,不能回退CREATE或DROP操作。

默认的MySQL行为是自动提交所有更改,也就是说,任何时候执行MySQL语句,实际上都是立即生效。可以设置不自动提交更改,代码如下:

SET autocommit = 0;

然后要使用COMMIT手动提交。

保留点(save point)

最后,简单提一下,复杂的事务处理可能需要部分提交或回滚,所以在事务处理中的合适位置是可以设置保留点的 ,如下:

SAVEPOINT pointFlagName;

回滚时给出保留点即可:

ROLLBACK TO pointFlagName;

保留点在事务处理完成会自动释放,也可以使用 RELEASE SAVEPOINT 明确地释放保留点。

21. 用户管理

21.1 管理用户

(1)查看用户

MySQL用户账号和信息存储在名为mysql的数据库中,mysql数据库中有一张user表,它包含所有用户账号。

SELECT user,host FROM mysql.user;

(2)创建用户

CREATE USER user_name IDENTIFIED BY 'pwd';

用户定义为user@host,即用户名@主机名,默认主机名为%

(3)更改用户名

RENAME USER old_user_name TO new_user_name;

(4)更改密码

SET PASSWORD = PASSWORD('new_pwd'); -- 设置当前用户密码
SET PASSWORD FOR another_user = PASSWORD('new_pwd');  -- 设置其他用户密码(要有权限)

(5)删除用户

DROP USER user_name;

21.2 权限设置

(1)查看权限

SHOW GRANTS FOR user_name;

(2)授予用户权限

GRANT 权限1,权限2 ON 数据库|表|列 TO 用户;

(3)收回用户权限

REVOKE 权限1,权限2 ON 数据库|表|列 FROM 用户;

GRANT和REVOKE可在几个层次上控制访问权限:

  • 整个服务器,使用GRANT ALLREVOKE ALL
  • 整个数据库,使用ON db_name.*
  • 特定的表,使用ON db_name.tbl_name
  • 特定的列;
  • 特定的存储过程。

更多内容,请微信搜索关注公众号【三朝猿老】,第一时间获取更多内容。

你可能感兴趣的:(MySQL数据库,mysql,数据库)