Mysql基础02-DML-DDL-TCL语言 【2021-10-20】

  • Post author:
  • Post category:mysql


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、视图一般不能增删改,而表可以。视图本质就是用来方便查询的。



版权声明:本文为AI_study原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。