1、DML 语言
数据操作语言
主要是 插入 insert、修改update、删除 delete
1.1 插入
1、基本语法格式
# 插入语法
INSERT INTO 表名 (字段名1,字段名2 ...) VALUES (值1, 值2 ...);
1.1 要求插入的值的类型与字段的类型要兼容
# 向beauty表插入一条数据
INSERT INTO beauty(id, `name`, sex, borndate, phone, photo, boyfriend_id)
VALUES(13, '完美','女', '1990-04-23', '18805558888', NULL, 2)
可以看到 已经插入成功了。上面photo字段是可以为null的,我们插入了一个null。
1.2 对于不想插入的数据可以不写,前提是这个字段可以为null。
# 向beauty表插入一条数据
INSERT INTO beauty(id, `name`, sex, borndate, phone, boyfriend_id)
VALUES(14, '完美2','女', '1991-04-23', '18866668888', 3)
那些字段是可以为空的?可以使用desc 表名来查看。
1.3 插入的时候,字段的顺序是可以任意的。但是值的顺序必须与字段的顺序一一对应。
INSERT INTO beauty(`name`, sex, id, phone)
VALUES('完美3','女', 15, '18866667777')
我们发现,并没有插入生日,但是数据里面却有,这是因为设置了默认值。
1.4 可以省略列名,则默认是所有列,列的顺序就是表中定义的顺序
INSERT INTO beauty VALUES(16, '完美4','女','1993-08-01', '13656561212', NULL, 4)
2、插入的方式2
基本语法
INSERT INTO beauty SET 字段名=值, 字段名=值, ...
例子:
INSERT INTO beauty SET id=19, `name`='完美5', phone='999'
同样,没有设置 sex字段和生日字段,都自动生成了。这是设计表格时设置了默认值。
3、2种方式对比
方式1支持多行插入,方式2不支持
INSERT INTO beauty(`name`, sex, id, phone)
VALUES('批量1','女', 20, '11'),('批量2','女', 21, '22'),('批量3','女', 22, '33')
方式1支持子查询,方式2不支持
INSERT INTO beauty(id, `name`, phone) SELECT 26,'完美6','10010'
1.2 修改
update 关键字
1、单表的修改
基本格式
UPDATE 表名 SET 字段名=新值,字段名=新值 ... 【WHERE 条件】
这里也是使用set关键字,只不过是和update关键字一起用
# 修改姓名有 批量 的人的电话为 10086
UPDATE beauty SET phone = 10086 WHERE `name` LIKE '%批量%'
# 修改 boys 表 id为2的记录 名称改为 张飞,魅力值为 10
UPDATE boys SET boyName='张飞', userCP=10 WHERE id=2
2、多表的修改
其实就是加上了连接条件而已。
基本格式
# 92语法
UPDATE 表1 别名1, 表2 别名2
SET 别名1.字段名=值,..., 别名2.字段名 = 值...
WHERE 连接条件
AND 筛选条件;
# 99语法
UPDATE 表1 别名1 连接类型 表2 别名2 ON 连接条件
SET 别名1.字段名=值,..., 别名2.字段名 = 值...
WHERE 筛选条件;
案例1
UPDATE boys bo JOIN beauty b ON bo.id = b.boyfriend_id
SET b.phone = 114
WHERE bo.boyName = '张无忌'
案例2
# 修改没有男朋友的女性的男朋友编号都为张飞
UPDATE boys bo RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
SET b.boyfriend_id = 2
WHERE b.id IS NULL
1.3 删除
1.3.1 删除方式1
DELETE FROM 表名 WHERE 筛选条件
删除是以行为基础的,如果不加筛选条件就会情况所有数据。
加上条件就是删除满足条件的部分行。
1、单表的删除
案例1:
# 删除手机号以9结尾的女性信息
DELETE FROM beauty WHERE phone LIKE '%9';
2、多表删除
# 92语法
DELETE 表1别名, 表2别名 FROM 表1 别名1, 表2 别名2 WHERE 连接条件 AND 筛选条件
# 99 语法
DELETE 表1别名, 表2别名 FROM 表1 别名1 连接方式 表2 别名2 ON 连接条件 WHERE 筛选条件
delete 后面如果只写一个表的别名,就是只删除这一个表的数据,都写了就是都删。
案例1:
# 删除张无忌的女朋友信息
DELETE b FROM beauty b, boys bo WHERE b.boyfriend_id = bo.id AND bo.id=1;
# 删除黄晓明以及他女朋友的信息
DELETE b,bo FROM beauty b JOIN boys bo ON b.boyfriend_id = bo.id
WHERE bo.`boyName`='黄晓明'
1.3.2 删除方式2
TRUNCATE table 表名;
truncate 关键字不能加筛选条件。因此truncate就是清空表。
truncate 清空表后,如果表中有自增字段,该字段会重新从1开始。而delete删除不会重置自增字段,会继续增长。
truncate 删除没有返回值,而delete删除会返回删除了几行。
2、DDL 语言
数据定义语言
主要是对库和表的管理。
创建 create、修改 alter、删除 drop
2.1 库的管理
1、库的创建
基本格式
CREATE DATABASE 库名
例子:
CREATE DATABASE books;
一般我们需要 如果存在就不创建,如果不存在才创建,加上 IF NOT EXISTS 关键字组合
CREATE DATABASE IF NOT EXISTS books;
2、库的修改
一般来说,库创建之后就不会修改。修改库很容易导致整个库不能使用。
在5.0之前有一个命令可以修改库名
RENAME DATABASE books TO newBooks;
后面这个关键字rename 被废弃了,因为不安全。
可以更改库的字符集
ALTER DATABASE books CHARACTER SET utf8mb4;
3、库的删除
DROP DATABASE books;
一般也是需要判断库是否存在,存在才删,不存在就什么都不做。这样才不会报错。
DROP DATABASE IF EXISTS books;
2.2 表的管理
2.2.1 表的创建
基本格式
列名就是字段名
CREATE TABLE 表名(
列名 列的类型【约束】,
列名 列的类型【约束】,
列名 列的类型【约束】,
...
列名 列的类型【约束】
)
CREATE TABLE book(
id INT COMMENT '编号',
bName VARCHAR(20) COMMENT '书名',
price DOUBLE COMMENT '价格',
authorId INT COMMENT '作者id',
publishDate DATETIME COMMENT '出版时间'
)
COMMENT 关键字后面 是字段的注释。
上面是我们自己写的简单创建表,实际上系统会这样给我们创建
CREATE TABLE `book` (
`id` int(11) DEFAULT NULL COMMENT '编号',
`bName` varchar(20) DEFAULT NULL COMMENT '书名',
`price` double DEFAULT NULL COMMENT '价格',
`authorId` int(11) DEFAULT NULL COMMENT '作者id',
`publishDate` datetime DEFAULT NULL COMMENT '出版时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
默认值,是否可以为 null,引擎,字符集这些都会自动加上。
例子2: 创建 作者表
CREATE TABLE author(
id INT COMMENT '作者编号',
au_name VARCHAR(20) COMMENT '作者名称',
nation VARCHAR(10) COMMENT '国籍'
)
2.2.2 表的修改
可以修改列名、列的类型或约束、列的增减、表名的修改
1、修改列名 使用 change 关键字
# 将book表的publishDate列改成pubDate
ALTER TABLE book CHANGE COLUMN publishDate pubDate DATETIME;
# column 关键字可以省略
ALTER TABLE book CHANGE publishDate pubDate DATETIME;
注意,修改列名时,必须加上列的类型。
2、修改列的类型或约束 使用 modify 关键字
ALTER TABLE book MODIFY COLUMN pubDate TIMESTAMP;
3、添加新列 add
ALTER TABLE author ADD COLUMN annual DOUBLE COMMENT '年薪';
4、删除列 drop
ALTER TABLE author DROP COLUMN annual;
5、修改表名 rename to
ALTER TABLE author RENAME TO book_author;
可以看到,一种操作一种关键词。change 可以不加上 column,其他的有的需要加上。建议都加上。
2.2.3 表的删除
DROP TABLE IF EXISTS book_author;
通用的一些语句:
DROP DATABASE IF EXISTS 旧库名;
CREATE DATABASE 新库名;
DROP TABLE IF EXISTS 旧表名;
CREATE TABLE 新表名(...);
2.2.4 表的复制
先创建一个表
DROP TABLE IF EXISTS author;
CREATE TABLE author(
id INT COMMENT '作者编号',
au_name VARCHAR(20) COMMENT '作者名称',
nation VARCHAR(10) COMMENT '国籍'
)
插入一些数据
INSERT INTO author VALUES
(1, '树上春树', '日本'),
(2, '莫言', '中国大陆'),
(1, '腾格尔', '俄罗斯'),
(1, '列夫托尔斯泰', '俄罗斯'),
(1, '金庸', '中国台湾');
1、仅仅复制表的结构
CREATE TABLE author_copy LIKE author;
特别简单, 使用 like 关键字就可以。
2、复制表的结构和数据
CREATE TABLE author_copy2 SELECT * FROM author;
使用子查询就可以完成。
你要是对子查询语句进行修改,就可以实现对部分数据的复制了。
CREATE TABLE author_copy3 SELECT * FROM author WHERE nation LIKE '%中国%';
还可以这样:
CREATE TABLE author_copy4 SELECT id, au_name FROM author WHERE 1=2;
设置一个谁都不满足的条件,就不会拷贝数据,同时select 后面的字段写自己需要的列名,就实现了 只拷贝部分字段而不拷贝数据的效果。
2.3 数据类型
1、数值型
整型
Tinyint、 占用1个字节 无符号0-255 有符号-128-127
Smallint、占用2个字节
Mediumint、占用3个字节
Int、Integer 占用4个字节
Bigint 占用8个字节
以上都分有符号和无符号。
如何设置是否有符号?
默认是有符号数。
CREATE TABLE int_test(
t1 INT COMMENT 't1默认是有符号数',
t2 INT UNSIGNED COMMENT 't2是无符号数'
)
如何插入负数给无符号字段,会出现警告,默认会插入最小临界值 0
如果插入的值超过了int的最大值呢?也会出现警告,默认插入int的最大临界值。
如果创建表格时,int的长度没有设置,会有默认值,有符号是 11,无符号是 10
这个长度并不是 int型的范围,而是显示的宽度,搭配 zerofill 关键字实现宽度不够 0填充,而一旦使用 0填充就不支持有符号。
DROP TABLE IF EXISTS int_test;
CREATE TABLE int_test(
t1 INT(8) ZEROFILL COMMENT '0填充自动变成无符号',
t2 INT UNSIGNED COMMENT 't2是无符号数'
);
INSERT INTO int_test VALUES(1,5);
小数: 定点数、浮点数
-
浮点数:
M, D 是可以省略的。
D的意思是小数点后保留几位
M的意思是总长度
超出范围会插入临界值
float(M, D) 占用 4个字节
double(M, D) 占用 8个字节
浮点数省略M和D 会根据插入的值来适应M和D的值。
-
定点型:
DEC(M, D) 占用 M+2 个字节 最大存储范围与double相同。
DECIMAL(M, D) 就是 dec的完整写法
定点型如果省略m和d,那么默认M为10,D为0
2、字符型
-
短文本 char、varchar
char(M) M为最多字符数,取值在0-255
char是固定长度的字符,如果字符数确定可以使用,效率比varchar高。默认M为1
varchar(M) M为最多字符数,取值在0-65535
varchar 是可变长度的字符,字符数不固定可以使用,相对占用空间低,M不可以省略,没有默认值
CREATE TABLE str_test(
sex CHAR(1) COMMENT '性别',
name VARCHAR(10) COMMENT '姓名'
)
-
长文本 text、blob(较长的二进制数据)
-
枚举 Enum
CREATE TABLE enum_test(
sex ENUM('0', '1', '2') COMMENT '枚举类型,取值0 男,1 女,2 第三性别'
);
INSERT INTO enum_test VALUES('1'),('0'),('2');
枚举类型只能插入指定的几个数。但是如果插入的 ‘3’ 会插入临界值 ‘2’,插入其他值会插入不成功。
-
Set 集合类型 和enum类似 可以保存 0-64个成员,可enum的区别是 set一次可以选取多个,而enum只能选择一个
set中成员个数不同所占字节也不同 ,不区分大小写
1-8 占用1个,8-16占用2个,17-24 占用 3个,25-32 占用 4个, 33-64 占用8个
CREATE TABLE set_test(
sex SET('0', '1', '2', '3', '4', '5') COMMENT '集合类型,有6种取值'
);
INSERT INTO set_test VALUES('0');
INSERT INTO set_test VALUES('0,1,4');
3、日期型
date 占用4个字节 最小值 1000-01-01 最大值 9999-12-31
datetime 占用8个字节 最小值1000-01-01 00:00:00 最大值 9999-12-31
timestamp 占用4个字节 最小值19700101080001 最大值 2038年某个时刻
time 占用3个字节 最小值-838:59:59 最大值 838:59:59
year 占用1个字节 最小值 1901 最大值 2155
timestamp 支持的时间范围较小,与实际时区有关,更能反应实际的日期,而datetime只能反映插入时当地时区
timestamp的属性受mysql的版本和sqlMode的影响很大
CREATE TABLE time_test(
date DATETIME COMMENT 'datetime类型',
time TIMESTAMP COMMENT '时间戳类型'
);
INSERT INTO time_test VALUES(NOW(), NOW());
查看当前时区:
SHOW VARIABLES LIKE 'time_zone';
哈哈 查出了系统时区。。。
更改时区:
SET time_zone = '+8:00';
再查看:
SHOW VARIABLES LIKE 'time_zone';
2.4 常见约束
约束就是对表中数据的一种限制,为了保证数据的可靠性,准确性。
一共有6大约束。
NOT NULL 非空约束,该字段的值不能为空。
default 默认约束 给该字段设置默认值,如果不主动插入数据,就会自动使用默认值
primary key 主键约束,保证 该字段的值唯一,并且非空
unique 唯一约束,但是可以为空
check 检查约束(mysql 不支持,语法上支持,但是没有效果)
foreign key 外键约束,用于限制2个表的关系,用于保证该字段的值必须来自主表的关联字段【从表添加外键约束,引用主表的值】
添加约束的时机,因为约束是对整个表起作用,因此在创建时就要添加约束。
1、创建表时
2、修改表时(创建了但是没有数据,可以修改)
如果有数据了,只有某些约束可以添加,修改。
约束分 列级约束和表级约束。
针对字段就是列级约束,针对整个表就是表级约束。
列级约束: 6个约束都能写,但是外键约束、检查约束没有效果
表级约束: 除了非空,默认,其他的都支持
2.4.1 添加约束
重新创建一个库来测试
CREATE DATABASE students CHARACTER SET 'utf8mb4';
先创建一张主修课程表
CREATE TABLE major(
id INT PRIMARY KEY COMMENT '主键',
majorName VARCHAR(20) COMMENT '专业名称'
)
再创建 学生表
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
id INT PRIMARY KEY COMMENT '主键',#主键
stuName VARCHAR(20) NOT NULL UNIQUE COMMENT '学生姓名 非空约束',#非空
gender CHAR(1) CHECK(gender='男' OR gender ='女') ,#检查
seat INT UNIQUE ,#唯一
age INT DEFAULT 18 ,#默认约束
majorId INT REFERENCES major(id) #外键
);
上面有些加上了注释 COMMENT ,有些没有加上,因为加上就会报错,不知道为啥。
查看索引:
SHOW INDEX FROM stuinfo;
主键、外键、唯一键 都会默认生成索引
上面创建的 stuinfo 表只有列级约束,下面来试试表级约束
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
id INT COMMENT '主键',
stuName VARCHAR(20) COMMENT '学生姓名',
seat INT COMMENT '座位号',
age INT COMMENT '年龄',
gender CHAR(1) COMMENT '性别',
majorid INT COMMENT '主修课程id',
# 表级约束(不支持非空、默认)
CONSTRAINT pk PRIMARY KEY(id),
CONSTRAINT uq UNIQUE(seat),
CONSTRAINT ck CHECK(gender ='男' OR gender = '女'),
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)
)
查看索引
SHOW INDEX FROM stuinfo;
可以看到,主键的别名起了没有作用。
表级约束基本格式:
# 在字段后面加上
【CONSTRAINT 约束名】 约束类型(字段名)
CONSTRAINT 可以不写,即不起约束名。
2.4.2 主键、唯一键、外键
主键和唯一的对比:
1、都能保证唯一性,但是主键必须非空,而唯一约束可以为null,但是null也最多只能有1个。
2、主键只能有1个,唯一键约束可以有多个。即多个字段可以用唯一键约束。
3、主键和唯一键运行组合。
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
id INT COMMENT '主键',
stuName VARCHAR(20) COMMENT '学生姓名',
seat INT COMMENT '座位号',
age INT COMMENT '年龄',
gender CHAR(1) COMMENT '性别',
majorid INT COMMENT '主修课程id',
# 表级约束(不支持非空、默认)
CONSTRAINT pk PRIMARY KEY(id, stuName), # 组合主键
CONSTRAINT uq UNIQUE(seat),
CONSTRAINT ck CHECK(gender ='男' OR gender = '女'),
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)
);
SHOW INDEX FROM stuinfo;
这里看起来是2个主键,实际上是一个。组合主键的意思是 这几个多个字段不能完全相同。不推荐使用组合主键。
外键:
1、要求在从表中设置外键关系
2、从表的外键列的类型和主表的关联列的类型要求一致或者兼容
3、要求主表的关联列必须是一个key(一般就是主键(唯一键、外键都可以))
4、要求插入数据时,要先插入主表、再插入从表,删除数据时,恰好相反,先从表再主表。
2.4.3 修改表时添加、删除约束
既然是修改表,就需要用到 alter table
1、添加非空约束
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
id INT,
stuname VARCHAR(20),
seat INT,
age INT,
major INT
);
# stuname添加非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;
删除非空约束?
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20);
2、添加默认约束
# age 添加默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;
删除默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT;
3、添加主键
# 添加主键
ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
# 第二种写法 因为主键支持 列级约束和表级约束 2种写法
ALTER TABLE stuinfo ADD PRIMARY KEY(id);
删除主键
ALTER TABLE stuinfo DROP PRIMARY KEY;
4、添加唯一键
# 添加唯一键
ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;
# 第二种写法 因为唯一键支持 列级约束和表级约束 2种写法
ALTER TABLE stuinfo ADD UNIQUE(seat);
删除唯一键
ALTER TABLE stuinfo DROP INDEX seat;
seat是唯一键的名字,可以通过 show index from 表名 查出来。删完之后再查一下确认
5、添加外键
ALTER TABLE stuinfo ADD FOREIGN KEY(major) REFERENCES major(id);
# 也可以加上名字
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(major) REFERENCES major(id);
删除外键
ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;
外键名也需要查出来。
添加的格式:
1、列级约束
ALTER TABLE 表名 MODIFY COLUMN 字段名 类型 新约束;
2、表级约束
ALTER TABLE 表名 ADD 【CONSTRAINT 约束名】新约束(字段名) 【外键的引用】;
2.4.4 标识列(自增列)
自增列 可以不用手动的插入值,系统提供默认的序列值
CREATE TABLE tab_identity(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
);
上面设置主键为 AUTO_INCREMENT 自增长,这样在插入数据时,可以不用写 id 这个字段的值。
INSERT INTO tab_identity VALUES(NULL, 'john');
查看一下系统变量
SHOW VARIABLES LIKE '%AUTO_INCREMENT%';
auto_increment_increment 是步长,auto_increment_offset 是偏移量即起始值。
设置 auto_increment_increment 步长
SET auto_increment_increment = 3;
但是mysql不支持设置 auto_increment_offset 。
虽然不支持直接设置,但是插入第一条数据时,指定id就可以了。后面的值就会在指定的值上进行增长。
或者说 中间某天数据指定id,后面的数据再使用 自动id。
标识列不一定是主键,但是一定是一个key
一个表只能有一个自增列,这个自增列的类型必须是数值型。
修改表时设置标识列
DROP TABLE IF EXISTS tab_identity;
CREATE TABLE tab_identity(
id INT,
name VARCHAR(20)
);
ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT;
删除
ALTER TABLE tab_identity MODIFY COLUMN id INT;
3、TCL 语言
transaction controller language
事务控制语言
3.1 事务
为什么需要事务?
当某些操作不是一步就能完成的时候,比如需要多条sql语句全部执行完才算是完成了一项操作,为了保证这项操作的一致性,即如果操作成功,这些sql应该是都成功的,如果有一条sql执行失败,说明这项操作失败,其他执行成功的sql应该也要回退,不应该执行成功。
即将多条sql的成功与失败绑定在一起,要么都成功,要么都失败。这就是一个事务。
最典型的实际问题就是转账了,A给B转500块钱,A要执行扣钱,B要执行加钱,如果B加钱失败了,A却扣钱成功了,那不是有问题了。即 A扣钱与B加钱这2个事必须全部成功或者全部失败,这样才合理。
存储引擎:在mysql中的数据用各种不同的技术存储到文件中。
show engines 可以查看mysql支持的存储引擎。
可以看到有很多。用的最多的就是InnoDB、myisam、memory等。但是只有InnoDB支持事务。默认存储引擎是InnoDB
3.1.1 事务的属性 acid
1、原子性 (Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发送,要么都不发送。
2、一致性 Consistency
事务必须使数据库从一个一致性状态变换到另一个一致性状态。
3、隔离性 Isolation
一个事务的执行不能被其他事务干扰,一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
4、持久性 durability
一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
3.1.2 事务的创建
隐式事务:没有明显的开启和结束的标记,自动提交功能是开启的
比如: insert、update、delete 等普通语句
显式事务:具有明显的开启、结束。
前提,关闭自动提交功能。 set autocomit=0
关闭自动提交只针对当前回话有效。
可以通过查看变量的方式查看自动提交是否开启,on代表开启,off代表关闭
SHOW VARIABLES LIKE 'autocommit';
步骤1:开启事务
SET autocommit = 0;
START TRANSACTION; # 可选
步骤2:编写事务中的sql语句(select、insert、update、delete)
事务中的sql语句是指对表数据的操作。对数据库的操作,对表的操作不存在事务。
步骤3:结束事务
COMMIT; # 提交事务
ROLLBACK; # 回滚事务
看例子:
先创建一个表来测试。
DROP TABLE IF EXISTS account;
CREATE TABLE account(
id INT PRIMARY KEY auto_increment,
username VARCHAR(20),
balance DOUBLE
);
INSERT INTO account VALUES(NULL, '张无忌', 1000),(NULL, '赵敏', 10000);
# 开启事务
SET autocommit = 0;
START TRANSACTION;
# 编写一组sql
UPDATE account SET balance = 2000 WHERE username = '张无忌';
UPDATE account SET balance = 9000 WHERE username = '赵敏';
# 结束事务
COMMIT;
试一试回滚
# 开启事务
SET autocommit = 0;
START TRANSACTION;
# 编写一组sql
UPDATE account SET balance = 1000 WHERE username = '张无忌';
UPDATE account SET balance = 10000 WHERE username = '赵敏';
# 结束事务
ROLLBACK;
结果发现数据库数据没有变。
其实在结束事务之前,对数据的修改只是保存在内存中,并没有合并到数据库文件内。只有commit才会进行数据同步,如果是rollback,那么这些内存中的数据全部作废,不合并就不会修改数据库。
思考一下:如果同时运行多个事务,当这些事务访问数据库的相同数据,会出现什么问题?
这意味着事务之间操作的数据没有隔离,也意味着数据不可靠了。
1、脏读: 对于两个事务T1,T2, T1 读取了T2
更新
而没有提交的数据,然后T2进行回滚了,说明T1之前读取的数据是无效数据。
2、不可重复读(同一个事务多次读取数据不一样): T1读取了一个字段,然后T2更新了这个字段之后,T1再次读取,值就不一样了。
3、幻读(针对插入): T1从一个表读取了一个字段,然后T2
插入
了新行,然后T1再次读取,就会多出几行
通过设置隔离级别来避免上面的情况。
Oracle 支持2种事务隔离级别: Read Commited(默认)、Serializable
mysql 支持4种:
read unCommited(读未提交) 出现脏读、不可重复读、幻读
Read Commited(读已提交),出现不可重复读、幻读
repeatabke read(可重复读、默认)、出现幻读
Serializable(串行化) 不会出现并发问题。
查询隔离级别
select @@tx_isolation;
设置当前回话的隔离级别
set session transaction isolation level read uncommitted;
Serializable串行化可以避免所有的并发问题,但是效率十分低下。
savepoint 节点名,可以保存节点。
SET autocommit=0;START TRANSACTION;DELETE FROM account WHERE id = 1;INSERT INTO account VALUES(null, 'aaa', 111111);SAVEPOINT a; # 设置保存点,搭配rollback使用DELETE FROM account WHERE id = 2;ROLLBACK TO a; # 回滚到保存点a
3.1.3 delete 和truncate
delete 和truncate 在事务使用时的区别
USE test;SET autocommit = 0;START TRANSACTION;DELETE FROM account;ROLLBACK;
使用delete 可以在事务中成功回滚。
USE test;SET autocommit = 0;START TRANSACTION;TRUNCATE TABLE account;ROLLBACK;
使用 TRUNCATE 在事务中无法回滚,即truncate不支持事务。
3.2 视图
视图 就是虚拟表,和普通表一样使用。通过普通表动态生成的数据。
视图:只保存sql逻辑,不保存查询结果。
多个地方用到了同样的查询结果,该查询结果使用的sql比较复杂。
案例:
# 查询姓张的学生名和专业名SELECT stuname,majorname FROM stuinfo s JOIN major m ON s.major=m.idWHERE s.stuName LIKE '张%';
通过视图的做法
#创建视图CREATE VIEW v1ASSELECT stuname,majorname FROM stuinfo s JOIN major m ON s.major=m.id;# 使用视图SELECT * FROM v1 WHERE stuname LIKE '张%';
查看视图
DESC 视图名;# 或者SHOW CREATE VIEW 视图名;
3.2.1 创建视图
CREATE VIEW 视图名 AS 查询语句;
例子
# 查询名字中包含a的员工名、部门名和工种信息SELECT e.last_name, d.department_name, j.job_titleFROM employees e JOIN departments d ON e.department_id = d.department_id JOIN jobs j ON j.job_id = e.job_id;
封装到视图中
#创建视图CREATE VIEW v1ASSELECT e.last_name, d.department_name, j.job_titleFROM employees e JOIN departments d ON e.department_id = d.department_id JOIN jobs j ON j.job_id = e.job_id;
使用
SELECT * FROM v1 WHERE last_name LIKE '%a%'
3.2.2 视图的修改
方式一: 如果实体存在就修改,如果不存在就创建
CREATE OR REPLACE VIEW 视图名 AS 查询语句;
方式二:
ALTER VIEW 视图名 AS 查询语句;
3.2.3 视图的删除
DROP VIEW 视图名,视图名,...,视图名;
上面的语句说明 一次可以删除多个视图。
3.2.4 视图的更新
#创建视图CREATE OR REPLACE VIEW myV1ASSELECT last_name,email FROMemployees;SELECT * FROM myV1;
更新视图,可以插入数据【修改,增加,删除都是一样】
对数据的修改操作【增删改】都叫做更新
INSERT INTO myV1 VALUES('aaaa', 'fasdf');
注意,并不是所有的视图都能更新。只有原始表字段也是存在的,才能进行更新。
更新视图的同时,会同步更新原始表。
具备以下特点的视图是不能更新的:
1、包含以下关键字的sql语句:分组函数、distinct、group by、having、union all
主要的原因是 这些sql生成的视图的内容是原表中不存在的,而视图本质上是不会存储数据,更新视图还是要更新原表中数据的,原表都没有,视图也就不能更新。
2、常量视图
3、select 中包含子查询
4、from 一个不能更新的视图
5、where 字句的子查询引用了from字句中的表
3.2.5 视图与表的对比
1、创建方式不一样
表使用 table 关键字,视图使用view
2、表是真实存在的。视图是虚拟的,视图只保存了逻辑。
3、视图一般不能增删改,而表可以。视图本质就是用来方便查询的。