MySQL第三部分


SQL 的四种连接查询

1.内连接
2.外连接
-左连接
-右连接
-完全外连接

创建两个表格

peson表格

–person表

id,name,cardID
create table person(
id int,
name varchar(20),
cardID int);

card表格

–card表
id ,name
create table card(
id int,
name varchar(20));

插入数据

card数据

insert into card values(1,’饭卡’);
insert into card values(2,’建行卡’);
insert into card values(3,’农行卡’);
insert into card values(4,’工商卡’);
insert into card values(5,’邮政卡’);

person数据

insert into person values(1,’张三’,1);
insert into person values(2,’李四’,3);
insert into person values(3,’王五’,6);

“连接”实战

select * from person;
+——+——–+——–+
| id | name | cardID |
+——+——–+——–+
| 1 | 张三 | 1 |
| 2 | 李四 | 3 |
| 3 | 王五 | 6 |
+——+——–+——–+

–并没有创建外键,

内连接

inner join
内联查询,就是两张表中的数据通过某个字段相对,查询出相关记录数据
– inner join 查询

select * from person inner join card on person.cardId=card.id;
+——+——–+——–+——+———–+
| id | name | cardID | id | name |
+——+——–+——–+——+———–+
| 1 | 张三 | 1 | 1 | 饭卡 |
| 2 | 李四 | 3 | 3 | 农行卡 |
+——+——–+——–+——+———–+

外连接

1.左外连接

left join或者left outer join
select * from person left join card on person.cardId=card.id;

左外连接,会把左边表里面的所有数据取出来,而右边表中的数据,如果有相等的,就会显示出来
如果没有,就会补NULL

+——+——–+——–+——+———–+
| id | name | cardID | id | name |
+——+——–+——–+——+———–+
| 1 | 张三 | 1 | 1 | 饭卡 |
| 2 | 李四 | 3 | 3 | 农行卡 |
| 3 | 王五 | 6 | NULL | NULL |
+——+——–+——–+——+———–+

2.右外连接

right或者right outer join
select * from person right join card on person.cardId=card.id;
右外连接,会把右边表里面的所有数据取出来,而左边表中的数据,如果有相等的,就显示出来
如果没有,就会补NULL
select * from person right outer join card on person.cardId=card.id;

+——+——–+——–+——+———–+
| id | name | cardID | id | name |
+——+——–+——–+——+———–+
| 1 | 张三 | 1 | 1 | 饭卡 |
| NULL | NULL | NULL | 2 | 建行卡 |
| 2 | 李四 | 3 | 3 | 农行卡 |
| NULL | NULL | NULL | 4 | 工商卡 |
| NULL | NULL | NULL | 5 | 邮政卡 |
+——+——–+——–+——+———–+

2.完全外连接

full join或者full outer join
select * from person full join card on person.cardId=card.id;

mysql> select * from person full join card on person.cardId=card.id;
ERROR 1054 (42S22): Unknown column ‘person.cardId’ in ‘on clause’

mysql不支持全外连接,原因不知,下节课再议
集合考虑:
全外连接=左连接union右连接
select * from person left join card on person.cardId=card.id
union
select * from person right join card on person.cardId=card.id;

+——+——–+——–+——+———–+
| id | name | cardID | id | name |
+——+——–+——–+——+———–+
| 1 | 张三 | 1 | 1 | 饭卡 |
| 2 | 李四 | 3 | 3 | 农行卡 |
| 3 | 王五 | 6 | NULL | NULL |
| NULL | NULL | NULL | 2 | 建行卡 |
| NULL | NULL | NULL | 4 | 工商卡 |
| NULL | NULL | NULL | 5 | 邮政卡 |
+——+——–+——–+——+———–+

mysql事务

mysql中,事务其实是一个最小的不可分割的工作单元。事务能够保证一个业务的完整性
比如我们的银行转账:
a->100
update user set money =money-100 where name=’a’
b->
update user set money=money+100 where name=’b’
–实际的程序中,如果只有一条语句执行成功了,而另外一条没有执行成功?
–出现数据前后不一致
update user set money =money-100 where name=’a’
update user set money=money+100 where name=’b’
–多条sql语句,可能会有同时成功的要求,要么就同时失败
–mysql如何控制事务

mysql默认是开启事务的(自动提交)

mysql> select @@autocommit;
+————–+
| @@autocommit |
+————–+
| 1 |
+————–+
–默认事务开启的作用是什么?
–当我们区执行sql语句的时候,效果就会立即体现出来,且不能回滚
create database bank;
create table user(
id int primary key,
name varchar(20),
money int);

insert into user values(1,’a’,1000);

–事务回滚:撤销sql语句

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1000 |
+—-+——+——-+
1 row in set (0.00 sec)

–设置自动提交为false

set @@autocommit=0

mysql> select @@autocommit;
+————–+
| @@autocommit |
+————–+
| 0 |
+————–+

–上面的操作关闭了mysql的自动提交(commit)
insert into user values(2,’b’,1000);

mysql> insert into user values(2,’b’,1000);
Query OK, 1 row affected (0.00 sec)

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1000 |
| 2 | b | 1000 |
+—-+——+——-+
2 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1000 |
+—-+——+——-+
1 row in set (0.00 sec)

–再一次插入数据
mysql> insert into user values(2,’b’,1000);
Query OK, 1 row affected (0.00 sec)
–手动提交数据
mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1000 |
| 2 | b | 1000 |
+—-+——+——-+
2 rows in set (0.01 sec)
–再撤销,是不可以撤销的(持久性)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1000 |
| 2 | b | 1000 |
+—-+——+——-+
2 rows in set (0.00 sec)

–自动提交?
@@autocommit=1
–手动提交?
commit;
–事务回滚?
rollback;
–如果说这个时候转账

转账实际操作

如果要执行成功撤销操作 需要@@autocommit=0

mysql> set @@autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@autocommit;
+————–+
| @@autocommit |
+————–+
| 0 |
+————–+

update user set money =money+100 where name=’a’;
update user set money=money-100 where name=’b’;

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
+—-+——+——-+
2 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1000 |
| 2 | b | 1000 |
+—-+——+——-+

–事务给我们提供了一个反悔的机会

begin;
–或者
start transaction;
–都可以帮我们手动开启一个事务

手动开启事务1

begin;
update user set money =money+100 where name=’a’;
update user set money=money-100 where name=’b’;

mysql> update user set money=money-100 where name=’b’;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> update user set money =money+100 where name=’a’;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1200 |
| 2 | b | 800 |
+—-+——+——-+
2 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from user;
+—-+——+——-+
| id | name | money |
+—-+——+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
+—-+——+——-+

####手动开启事务2
start transaction
update user set money =money+100 where name=’a’;
update user set money=money-100 where name=’b’;

与上述同理
begin
start transaction
这两条命令相当于小开关手动开启事务
@@autocommit属于总开关

事务的四大特性

A 原子性:事务是最小的单位,不可以再分割
B 一致性:事务要求,同一事务中的sql语句u,必须保证同时成功或者同时失败
C 隔离性:事务1和事务2 之间具有隔离性
D 持久性:事务一旦结束(commit,rollback),就不可以返回

事务开启:
1.修改默认提交 set @@autocommit=0;
2.begin
3.start transaction

事务手动提交:
commit;

事务手动回滚:
rollback;

事务的隔离性

1.read uncommitted;—读未提交的
2.read committed;—读已经提交的
3.repeatable read;—可以重复读
4.serializable;—-串行化

1-read uncommitted

如果存在事务a和事务b
a 事务对数据进行操作,在操作过程中,事务没有被提交,但b可以看见a

bank数据库user表
insert into user values(3,’小明’,1000);
insert into user values(4,’淘宝店’,1000);

mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
+—-+———–+——-+

–如何查看数据库的隔离级别
–系统级别
select @@global.transaction_isolation;
–会话级别
select @@transaction_isolation;

//查看数据库隔离级别需要退回到最初的databases

mysql> select @@global.transaction_isolation;
+——————————–+
| @@global.transaction_isolation |
+——————————–+
| REPEATABLE-READ |
+——————————–+
–如何修改隔离级别
set global transaction isolation level read uncommitted;

mysql> select @@global.transaction_isolation;
+——————————–+
| @@global.transaction_isolation |
+——————————–+
| READ-UNCOMMITTED |
+——————————–+

–转账: 小明在淘宝店买鞋子:800块
小明-》成都
淘宝点-》广州
start transaction;
update user set money=money-800 where name=’小明’;
update user set money=money+800 where name=’淘宝店’;

mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 200 |
| 4 | 淘宝店 | 1800 |
+—-+———–+——-+
–给淘宝店打电话,说你去查一下是不是到账了
–淘宝店在广州查账

mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 200 |
| 4 | 淘宝店 | 1800 |
+—-+———–+——-+

–发货
–晚上请女朋友吃好吃的(呸!)
–1800

–小明-》成都

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
+—-+———–+——-+

–结帐的时候发现钱不够

mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 200 |
| 4 | 淘宝店 | 1800 |
+—-+———–+——-+

–如果两个不同的地方都在进行操作,如果事务a开启以后,他的数据可以被其他事务读取到
–这样就会出现“脏读”
–脏读:一个事务读到另外一个事务没有提交的数据,就叫做脏读
–实际开发是不允许脏读出现的

2.read committed; 读已经提交的

set global transaction isolation level read committed;

bank 数据库 user表
小张:银行的会计
start transaction;
select * from user;

+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
+—-+———–+——-+
小张出去了。

小王:
start transaction;
insert into user values(5,’c’,100);

–小张回来了
select avg(money) from user;

mysql> select avg(money) from user;
+————+
| avg(money) |
+————+
| 820.0000 |
+————+

–money的平均值不是1000,变少了?
–虽然我只能读到另一个事务提交的数据,但还是会出现问题,就是
–读取同一个表中的数据,发现前后不一致
–不可重复读现象:read committed

3.repeatable read

可以重复读,数据库默认也是这个
set global transaction isolation level repeatable read;

–在repeatable-read隔离级别下会出现什么问题
select * from user;
mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
| 5 | c | 100 |
+—-+———–+——-+

–张全蛋-成都

start transaction;

–王尼玛-北京

start transaction;

–张全蛋-成都
insert into user values(6,’d’,1000);

mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
| 5 | c | 100 |
| 6 | d | 1000 |
+—-+———–+——-+

–王尼玛-北京
insert into user values(6,’d’,1000);

mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
| 5 | c | 100 |
+—-+———–+——-+
mysql> insert into user values(6,’d’,1000);
ERROR 1062 (23000): Duplicate entry ‘6’ for key ‘user.PRIMARY’

–这种现象叫做幻读
–事务a和事务b同时操作一张表,事务a提交的数据,也不能被事务b读到
意思就是两人操作同一个表格的时候,操作的数据并不会实时更新,所以王尼玛当时看不到d的数据,
如果重新查看可以查看到。在不知道d的数据已经被插入的情况下再次插入d的数据就会出现错误!

4.serializable read

//
这个示例如果想实际操作演示的话,需要同时开启两个终端窗口
然后进行视频中的操作
//

串行化
set global transaction isolation level serializable;
修改成功

mysql> select @@global.transaction_isolation;
+——————————–+
| @@global.transaction_isolation |
+——————————–+
| SERIALIZABLE |
+——————————–+

mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
| 5 | c | 100 |
| 6 | d | 1000 |
+—-+———–+——-+

–小张-成都
start transaction;

insert into user values(7,’小赵’,1000);
mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
| 5 | c | 100 |
| 6 | d | 1000 |
| 7 | 小赵 | 1000 |
+—-+———–+——-+

–小王-北京

–小王查询信息发现小赵的信息已经存在
mysql> select * from user;
+—-+———–+——-+
| id | name | money |
+—-+———–+——-+
| 1 | a | 1100 |
| 2 | b | 900 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
| 5 | c | 100 |
| 6 | d | 1000 |
| 7 | 小赵 | 1000 |
+—-+———–+——-+

–小张
start transaction;
insert into user values(8,’小王’,1000);

–sql语句卡住?
这个时候小张进行操作想要输入新的数据发现卡住
–当user表被另外一个事务操作的时候,其他事务写操作,是不可以被进行的
(银行效率低的原因发现!!)
–进入排队状态(串行化),指导小王那边的事务结束之后(commit)之后
小张的写入操作才会执行
–在没有等待超时的情况下。

小王:
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

小张:
Query OK, 1 row affected (25.70 sec)

mysql>
mysql>
mysql>
mysql>
mysql>

–串行化问题是,性能特差
read—committed>read committed>repeatable read>serializable;
–隔离级别越高,性能越查
mysql语句默认隔离级别是repeatable


完结散花!!!
小希同学加油!
正好一周
2021.2.7


评论
  目录