本文中 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命令行里输入的路径如果有空格,可用如下解决方法:
- 给路径名上加上双引号(" ")然后cd执行即可;
- 用缩写。比如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;
- 绕过去,创建一个镜像。
例如在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. 常用引擎类型
- InnoDB:一个可靠的事务处理引擎,它不支持全文本搜索(默认);
- MyISAM:一个性能极高的引擎,支持全文本搜索,但是不支持事务处理。
- MEMORY:在功能上等同于MyISAM,但是数据存储在内存中,速度很快(特别适用于临时表)。
使用方法:
CREATE TABLE tbl_name
( ...
...
) ENGINE=InnoDB;
CREATE TABLE tbl_name
( ...
...
) ENGINE=MyISAM;
注意:引擎类型可以混用,即不同的表可以使用不用的引擎类型。但是外键不能跨引擎,也就是使用一个引擎的表不能引用使用不同引擎表的外键。
5. ALTER修改表和约束
- 更改表的名字
alter table old_tbl_name rename to new_tbl_name;
- 增加列
ALTER TABLE tbl_name ADD col_name char(20);
- 修改列的字段
-- 修改字段名称
alter table tbl_name change old_col_name new_col_name type;
-- 修改字段类型
ALTER TABLE tbl_name MODIFY col_name char(20);
- 删除列
ALTER TABLE tbl_name DROP COLUMN col_name;
比较常用的Alter用法是对表添加约束,主要约束有主键约束、外键约束、check约束、unique约束、not null约束。
- 定义主键约束
ALTER TABLE tbl_name1 ADD CONSTRAINT pk_name PRIMARY KEY(col_name, ...);
- 定义外键约束
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)
);
- 定义check约束
ALTER TABLE student ADD CONSTRAINT ck_student_sex CHECK(sex = '男' or sex = '女');
- 定义unique约束
ALTER TABLE tbl_name ADD CONSTRAINT uq_name UNIQUE(col_name);
- 定义not null约束
ALTER TABLE tbl_name MODIFY col_name NOT NULL;
-- 取消not null约束
ALTER TABLE tbl_name MODIFY col_name NULL;
- 删除约束
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匹配
- 使用
|
符号
|
为正则表达式中的OR操作符,它表示匹配其中之一。如下代码将匹配1或2或3:
REGEXP '1|2|3'
- 使用
[]
符号
[]
是另一种形式的OR语句。上述代码可改写成:
REGEXP '[123]'
使用^
符号可以对字符集合进行否定,如下代码表示匹配除1、2、3外的其它任何东西:
REGEXP '[^123]'
- 使用
-
定义范围
集合可用来定义要匹配的一个或多个字符,也可以定义一个要匹配的集合范围,为了简化这种范围的表示,可以使用-
来定义集合的范围。如下:
REGEXP '[1-9]' < = > REGEXP '[123456789]'
REGEXP '[a-z]' -- 匹配任意字母字符(如果数据库配置为不区分大小写)
7.3 匹配特殊字符
正则表达式中包含了许多特殊的字符,如上述我们学到的.
、[]
、|
、-
等,如果我们要匹配的正好是这些特殊字符,该怎么办呢?
⭐️ 为了匹配正则表达式中的特殊字符,在MySQL中必须使用\\
进行转义。多数正则表达式实现用一个\
,但在MySQL中要用两个,MySQL解释一个,正则表达式库解释另一个。
如:
REGEXP '\\.' -- 匹配.字符
REGEXP '\\|' -- 匹配|字符
REGEXP '\\\' -- 匹配\字符
空白元字符的转义:
元字符 | 说明 |
| 换页 |
| 换行 |
| 回车 |
| 制表 |
| 纵向制表 |
7.4 匹配字符类
为了更方便的工作,可以使用预定义的字符集,称为字符类。
Posix字符类:
类 | 说明 |
| 任意字符(同 |
| 任意小写字母(同 |
| 任意大写字母(同 |
| 任意数字(同 |
| 任意字母和数字(同 |
| ASCII控制字符(ASCII 0到31和127) |
| 不在 |
| 空格和制表(同 |
| 包括空格在内的任意空白字符(同 |
| 任意十六进制数字(同 |
| 任意可打印字符 |
| 与[: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 定位符
为了匹配特定位置的文本,需要使用定位符。
定位符:
元字符 | 说明 |
^ | 文本的开始 |
$ | 文本的结尾 |
[[:<:]] | 词的开始 |
[[:>:]] | 词的结尾 |
-
^
的双重用途
在上述7.2中的第2个例子中,我们使用了正则表达式[^123]
用来匹配除1、2、3外的其他字符,如果我们把正则表达式改为^[123]
则表示匹配开始字符为数字1或2或3的文本。
总结:^
符号用在[]
外边,用来指串的开始处;用在[]
里边,用来否定该集合。
- 使用
^
和$
匹配整个数据串,此时发挥和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。
本表格中函数参数省略。
函数 | 说明 |
| 拼接串 |
| 去掉串左右两边的空格 |
| 去掉串左边的空格 |
| 去掉串右边的空格 |
| 将串转换为大写 |
| 返回子串的字符 |
| 找出串的一个子串 |
| 返回串的长度 |
| 返回串左边length长度的字符 |
| 返回串右边length长度的字符 |
| 返回串的soundex值 |
| 翻转串 |
Concat()
SELECT CONCAT('col_name1=',col_name1,',col_name2=',col_name2) AS result
FROM tbl_name;
//输出形式
col_name1=col_name1的内容,col_name2=col_name2的内容
-
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;
Upper()
SELECT UPPER(col_name) AS result FROM tbl_name;
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;
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)
不予详细介绍。
Length()
SELECT LENGTH(col_name) AS result FROM tbl_name
-
Left()
、Right()
-- 返回串左边length长度的字符
SELECT LEFT(string, length) AS result FROM tbl_name;
-- 返回串右边length长度的字符
SELECT LEFT(string, length) AS result FROM tbl_name;
Soundex()
SELECT * FROM tbl_name
WHERE SOUNDEX(col_name) = SOUNDEX(string)
注意:Soundex()
函数是对串进行发音匹配比较而不是字母。
Reverse()
-- 将串翻转
SELECT REVERSE(col_name) AS result FROM tbl_name;
8.2 时间日期处理函数
函数 | 说明 |
| 返回当前日期和时间 |
| 返回当前日期 |
| 返回当前时间 |
| 返回日期时间的日期部分 |
| 返回日期时间的时间部分 |
| 返回一个日期的年份部分 |
| 返回一个日期的月份部分 |
| 返回一个日期的天数部分 |
| 返回一个时间的小时部分 |
| 返回一个时间的分钟部分 |
| 返回一个时间的秒数部分 |
| 增加一个间隔日期 |
| 增加一个间隔日期(高度灵活) |
| 增加一个间隔时间 |
| 计算两个日期之差(天数) |
| 返回格式化日期 |
| 返回日期对应是星期几 |
参数说明:
- date为时间参数
-
AddDate()
和Date_Add()
中的参数
- date:起始日期或者起始时间。
- expr:指定的是一个间隔值,在起始时间中增加或者减少。
expr
是一个字符串,对于负值间隔,可以以"-"开头。 - unit:表示的是一个单位(day/month/year),比如:加上的是1天还是一个小时。
AddTime(date, datetime)
中datetime格式如:‘1 2:3:0’(1天2小时3分钟0秒)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 数值处理函数
本表格中函数参数省略。
函数 | 说明 |
| 返回一个数的绝对值 |
| 返回一个数的指数 |
| 返回一个数的平方根 |
| 返回除操作的余数 |
| 返回圆周率 |
| 返回一个随机数 |
| 返回一个角度的正弦 |
| 返回一个角度的余弦 |
| 返回一个角度的正切 |
8.4 聚集函数
本表格中函数参数省略。
函数 | 说明 |
COUNT() | 返回某列的行数 |
SUM() | 返回某列的和 |
AVG() | 返回某列的平均值 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
注意:
- 对NULL值是否忽略
上表格聚集函数都自动忽略NULL值,除了如下这种特殊情况:
- 如果使用COUNT()时指定列名,即
COUNT(col_name)
时,此函数会忽略NULL值; - 如果使用COUNT(*)时,则不会忽略NULL值。
- 使用标准的算术操作符,所有的聚集函数都可以用来执行多个列上的计算。
如:
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. 数据分组与排序
- 使用
GROUP BY
对数据分组
- GROUP BY后跟的列必须在SELECT子句中给出,除了聚集函数。
- GROUP BY不能使用别名。
- 如果使用GROUP BY,那么聚集函数作用域是每个分组。
- 使用
HAVING
对分组过滤。WHERE过滤行,HAVING过滤分组,除了关键字不同,语法都是一致的。
- 使用
ORDER BY
对数据排序
- ORDER BY默认排序类型为:升序排列
ASC
,降序排列需要使用关键字:DESC
。每个关键字只作用一列。 - ORDER BY可以不使用SELECT语句后的列而使用表中其它列进行排序。
- ORDER BY对多列进行排序时,只有当前一列值相同时,才会对后一列进行排序。
- ORDER BY是对上述所有结果的排序,最多只允许出现一次,且在最末(但在LIMIT之上)。
- 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()
定义中相同,如果指定多个列,则必须以正确次序列出它们。
使用FULLTEXT
和LIKE
的重要区别:
-
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 <no' IN BOOLEAN MODE )
(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 +(<no)' IN BOOLEAN MODE )
总结:
以布尔方式,可以提供关于如下内容的细节:
- 要匹配的词
- 要排斥的词(如果某行包含这个词语,则不返回该行,即使它包含其他指定的词也是如此)
- 调整等级(指定某些词比其他词更重要,更重要的词等级更高)
- 表达式分组
- 其他内容
全文本搜索的使用说明:
- 仅在
MyISAM
数据库引擎中支持全文本搜索。 - 许多词出现的频率很高,但实际用处很少。因此MySQL规定了一条50%规则,如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用于
IN BOOLEAN MODE
。 - 如果表中的行数少于3行,则全文本搜索不返回任何结果。
- 在索引全文本数据时,短词(具有3个或3个以下字符的词)被忽略且从索引中排除,短语定义可以修改。
- MySQL带有一个内建的非用词列表,这些词在索引全文本数据时总是被忽略。如果需要,可以覆盖这个列表。
- 忽略词中的单引号。如:I’m索引为Im。
- 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果。
12. 增删改查
12.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语句
- 插入多行
values后面直接跟多组数据,数据间用逗号隔开
insert into customers(col1, col2, ...) values(v1, v2, ...),
(v3, v4, ...),
(v5, v6, ...);
- 插入检索出来的数据
利用insert将一条select语句的结果插入表中,即所谓的insert select语句。由一条insert和一条select语句组成,如下:
INSERT INTO customers(col1, col2, ...)
SELECT col1, col2, ...
FROM tbl_name
WHERE ...
- 创建表时插入数据
利用已有的source表,创建新表时使用source表中的某些列创建,如下:
CREATE TABLE tbl_name AS
SELECT col1,col2, ... FROM source_table;
其中:tbl_name
是创建的新表的名称,col1
、col2
等是已存在表source中的列名称。
12.2 更新数据(注意使用安全)
- 更新方式
- 更新特定行(一定要where,where一定要正确筛选到)
- 更新所有行
- 删除某个列
UPDATE还用于删除某个列的值,即清空某一列的值,使用UPDATE而不是DELETE,如下:
UPDATE tbl_name
SET col = NULL
WHERE ...
- IGNORE关键字
如果用UPDATE语句更新多行,并且在其中一行出错,则会回退取消整个UPDATE操作,如果要求即使发生错误也继续进行更新,可使用IGNORE关键字,如下:
UPDATE IGNORE tbl_name ...
12.3 删除数据(注意使用安全)
- 删除方式
- 删除特定行(一定要where,where一定要正确筛选到)
- 删除所有行
- 更快的删除
如果想删除表中所有的行,可使用TRUNCATE TABLE
语句,它完成删除表格相同的工作,但速度更快(删除原来的并重新建一个表,而不是逐行删除表中的数据)。
重要:
为了保证UPDATE和DELETE操作不误伤(没有where或者where的效果不同于预期):
- 先测试WHERE子句对不对,确保它过滤的是正确的记录;
- 使用强制实施引用完整性的数据库,这样与其他表有关联的行也不能被删除。
13. 视图
视图是虚拟的表,是几个表联结查询的动态结果。
视图不存储数据,每次查看视图时,要重新执行查询底表语句,因此大型、复杂视图性能低。
13.1 为何使用视图
- 重用SQL语句,简化复杂查询,不必重复编写查询联结细节;
- 保护数据,可以给用户授权只能访问表的一部分数据;
- 更改数据格式和表示,与底表可以不同。
13.2 视图的规则与限制
- 视图名字必须唯一;
- 视图数目无限制;
- 创建视图需要有相应表的访问权限;
- 视图可以嵌套,即联结其他视图来创建新视图;
- 视图中order by作用,会被基表中的order by覆盖;
- 视图不能有索引、触发器、默认值;
- 视图可以和表一起使用,即连接查询。
13.3 使用视图
- 创建视图
CREATE VIEW view_name AS SELECT ...
- 查看创建视图的语句
SHOW CREATE VIEW view_name;
- 删除视图
DROP VIEW view_name;
如果指定的视图不存在,则DROP VIEW将产生一个错误。可以使用如下语句防止产生错误:
DROP VIEW IF EXISTS view_name;
- 更新视图
- 先删除视图,再重新创建;
- 使用
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)BEGIN
和END
用来限定存储过程体。
(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
的结果中显示,
一个实例:
考虑这个场景:有一个订单表需要获得订单合计,但需要对合计增加营业税,不过只针对某些客户。
根据场景列出存储过程中应执行的事件:
- 获得合计;
- 把营业税有条件地添加到合计;
- 返回合计(带税或不带税)。
源代码如下:
-- 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条信息:
- 唯一的触发器名
- 触发器关联的表
- 触发器应该响应的活动(DELETE、INSERT、UPDATE)
- 触发器何时执行(处理之前或之后)
创建代码如下:
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数值数据类型。
这些类型包括严格数值数据类型(INTEGER
、SMALLINT
、DECIMAL
和NUMERIC
),以及近似数值数据类型(FLOAT
、REAL
和DOUBLE PRECISION)。
关键字INT
是INTEGER
的同义词,关键字DEC
是DECIMAL
的同义词。
BIT数据类型保存位字段值,并且支持MyISAM
、MEMORY
、InnoDB
和BDB
表。
作为SQL标准的扩展,MySQL也支持整数类型TINYINT
、MEDIUMINT
和BIGINT
。下面的表显示了需要的每个整数类型的存储和范围。
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
| 1 byte | (-128,127) | (0,255) | 小整数值 |
| 2 bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
| 3 bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
| 4 bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
| 8 bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
| 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) | 单精度 浮点数值 |
| 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(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
18.2 日期和时间类型
表示时间值的日期和时间类型为DATETIME
、DATE
、TIMESTAMP
、TIME
和YEAR
。
每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
TIMESTAMP
类型有专有的自动更新特性,将在后面描述。
类型 | 大小 ( bytes) | 范围 | 格式 | 用途 |
| 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
| 3 | ‘-838 : 59 : 59’/‘838 : 59 : 59’ | HH:MM:SS | 时间值或持续时间 |
| 1 | 1901/2155 | YYYY | 年份值 |
| 8 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
| 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 呢?
这三种类型比较:
- char: char 不用多说了,它是定长格式的,但是长度范围是 0~255. 当你想要储存一个长度不足 255 的字符时,MySQL会用空格来填充剩下的字符。因此在读取数据时,char 类型的数据要进行处理,把后面的空格去除。
- varchar: 关于 varchar,有的说最大长度是 255,也有的说是 65535,查阅很多资料后发现是这样的:varchar 类型在 5.0.3 以下的版本中的最大长度限制为 255,而在 5.0.3 及以上的版本中,varchar 数据类型的长度支持到了 65535,也就是说可以存放 65532 个字节(注意是字节而不是字符!!!)的数据(起始位和结束位占去了3个字节),也就是说,在 5.0.3 以下版本中需要使用固定的 TEXT 或 BLOB 格式存放的数据可以在高版本中使用可变长的 varchar 来存放,这样就能有效的减少数据库文件的大小。
- 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 ALL
和REVOKE ALL
; - 整个数据库,使用
ON db_name.*
; - 特定的表,使用
ON db_name.tbl_name
; - 特定的列;
- 特定的存储过程。