文章目录
表/库结构修改
想要修改什么结构,就先查查所创建的表/库的结构,然后按照结构规则修改即可 ,比如想要修改库的字符集先 show create database xiaoge;
,然后看出字符集设置是default character set 字符集名
,按这样修改就可以了,其实 default 可以省略,直接用 character set utf8
也可以
如果是修改表的,就先show create table table1;
,同样这样做,同样 default 可以省略
修改表名:alter table 原表名 rename to 新表名;
alter table college rename to coll;
修改字段
- 修改字段名:alter table student change 原字段名 新字段名 data_type(字段类型);
alter table student change id num varchar(8);
- 修改字段类型:
alter table student modify id varchar(4);
#强烈建议不要这样用 - 添加字段:
alter table student add hobby varchar(64);
- 删除字段:
alter table student drop hobby;
约束条件
- 约束条件一般用在创建表的时候,一个字段可以设置多个约束条件
- 如果创建表时忘记了,可以通过 alter table 表名 modify 字段名…(注:字段名前可加可不加 column),也是可以设置多个约束条件
- 默认约束:default,插入数据时,没有赋值,自动赋予默认值,没默认值,默认为null,
alter table student add hobby enum("xiaoge","dalong") default "xiaoge";
- 非空约束:not null,限制一个字段的值不能为空,insert时必须为该字段赋值,特别的是enum(a,b)被修饰时默认是a,非空字符不能与null合用,一般与default配合使用
alter table student add addr varchar(128) not null default "zhaodong";
- 唯一约束:限制一个字段的值不能重复,确保字段中的值唯一
alter table student modify id int unique key;
或者alter table students add unique(name);
- 删除唯一约束:
alter table stus drop index name;
- 删除唯一约束:
- 主键:primary key,通常每张表都需要一个主键来体现唯一性,每张表里只有一个主键,主键=非空+唯一
alter table student modify id int primary key;
或者alter table student add primary key(id);
- 删除主键:
alter table students drop primary key;
- 联合主键:可以设置多个主键,只要不是所有的主键都相同,就可以存在
- 联合主键中每个主键的数据都不能为 null
- 删除主键:
mysql> create table test2( id int, name varchar(12), age int, primary key(id, name) );
Query OK, 0 rows affected (0.03 sec)
mysql> desc test2;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(12) | NO | PRI | NULL | |
| age | int(11) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> insert into test2 values( 1,'xiaoge',15), (2, 'xiaoge', 15);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from test2;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | xiaoge | 15 |
| 2 | xiaoge | 15 |
+----+--------+------+
2 rows in set (0.00 sec)
mysql> insert into test2 value(1,'xiaoge',14);
ERROR 1062 (23000): Duplicate entry '1-xiaoge' for key 'PRIMARY'
- 联合主键作用:用这个主键包含的字段作为主键,这个组合在数据表中是唯一,且加了主键索引
- 联合主键就是确定一条记录的唯一性,比如这种时候:
商品品牌 | 商品型号 |
---|---|
诺基亚 | 920 |
三星 | NOTE2 |
诺基亚 | 8088 |
- 比如这样商品品牌可能有重复,都是诺基亚,但是诺基亚厂商生产的商品型号是不会重复的,也比如,可能好多品牌都有920这个型号,但是一个品牌只有一个920的型号,所以就靠这样的联合主键来确定这条记录的唯一性
————————————————
版权声明:本文为优快云博主「温景_winka」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/hewenjing8168/article/details/80182775 - 自增长:auto_increment要求用在主键上,自动编号,和主键组合使用,一个表只能有一个自增长,被删掉的不会自动添加
alter table score modify id int primary key auto_increment;
外键
- 外键:foreign key,保证多表数据的一致性,外键能关联另一张表的主键
- 外键表有的,主键表一定有;主键表没有的,外键表一定没有;主键表有的,外键表未必有
- 外键表的外键已经插了数据,该外键关联的主键表的主键对应的数据无法删除
mysql> desc course;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| cid | int(11) | NO | PRI | NULL | |
| name | varchar(10) | YES | | NULL | |
| tnum | int(11) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> desc teacher;
+----------+--------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------------+------+-----+---------+-------+
| tid | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
| gender | enum('girl','boy') | NO | | girl | |
| birthday | date | YES | | NULL | |
| job_name | varchar(10) | YES | | NULL | |
+----------+--------------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
mysql> alter table teacher add primary key(tid);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table course add foreign key(tnum) references teacher(tid);
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
//增加外键,course 中的 tnum 外键关联 teacher 中的 tid 主键
----------------------------------------------------------------------
mysql> select * from class;
+----+---------+
| id | name |
+----+---------+
| 1 | math |
| 2 | english |
| 3 | chinese |
+----+---------+
3 rows in set (0.00 sec)
mysql> select * from test;
+-------+--------+----------+
| id | name | class_id |
+-------+--------+----------+
| 20002 | yang | 1 |
| 20101 | na | 2 |
| 20201 | jingyi | 3 |
+-------+--------+----------+
3 rows in set (0.00 sec)
mysql> delete from class where id=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`xiaoge`.`test`, CONSTRAINT `test_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
//删除失败,因为学生表中班级1有同学 yang,所以班级表中的班级1无法删除
mysql> delete from test where class_id=1;
Query OK, 1 row affected (0.00 sec)
mysql> select * from test;
+-------+--------+----------+
| id | name | class_id |
+-------+--------+----------+
| 20101 | na | 2 |
| 20201 | jingyi | 3 |
+-------+--------+----------+
2 rows in set (0.00 sec)
mysql> delete from class where id=1;
Query OK, 1 row affected (0.00 sec)
//学生表中班级1中的学生都删除了,班级表中的班级1就可以删除了
mysql> select * from class;
+----+---------+
| id | name |
+----+---------+
| 2 | english |
| 3 | chinese |
+----+---------+
2 rows in set (0.00 sec)
mysql> insert into test value(20301, 'xiaoge', 1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`xiaoge`.`test`, CONSTRAINT `test_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
mysql> insert into test value(20301, 'xiaoge', 2);
Query OK, 1 row affected (0.00 sec)
//因为班级表中的班级1已经删除了,所以学生表中无法插入班级1的学生
添加约束条件
- 创建表时添加
比如create table stu(id int primary key auto_increment, name varchar(20) unique, gender enum('girl', 'boy') default 'girl' not null);
或者create table stus( id int, name varchar(20), gender enum('girl', 'boy') ,primary key(id), unique(name));
# default 和 not null 用这种方式没发现 - 创建表后增加/修改
比如alter table studs modify gender enum('girl', 'boy') default 'girl' not null;
或者alter table studs change gender gender enum('girl', 'boy') default 'girl' not null;
或者alter table studs add date date default '2020/01/01';
#add 用于目前不存在的字段
删除约束条件
- drop:
- 删除主键:
alter table students drop primary key;
- 删除唯一约束:
alter table stus drop index name;
- 删除主键:
- modify:
alter table studs modify gender enum('girl', 'boy') default 'girl';
- change:
alter table studs change gender gender enum('girl', 'boy');
查询约束条件
show keys from 表名
//这个很全面
describe 表名
或者desc 表名
注
- 如果发现语法没错,但约束条件无法添加时,可能是因为和已经存在的数据有冲突,比如给某个字段加 not null 失败,发现数据中该字段有 null,或者想要给某个字段加 unique,发现该字段中的数据存在重复的
事务
- 为了保证操作的一致性,(例如:转账,减少A的钱增加B的钱等),要么都成功,要么都不成功
- 事务是一个最小的不可分割的工作单元,事务能够保证一个业务的完整性
- mysql默认开启事务物(自动提交),事务只支持数据库引擎
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)
- 当我们执行 sql 语句时,效果会立即体现出来,并且不支持回滚
- 回滚:撤销 sql 语句执行效果
mysql事物的两种方式:
1.直接用set来改变mysql的自动提交模式- set autocommit = 0 #禁止自动提交
- set autocommit = 1 #开启自动提交
2.用begin,rollback,commit来实现 - 步骤:
1.begin开始一个事物,检测是否都成功
if 都成功了:
commit #提交
else:
rollback #回滚
mysql> create table bank(
-> id int,
-> name varchar(20),
-> money int
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into bank value(1,'xiaoge',500000);
Query OK, 1 row affected (0.00 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
+------+--------+--------+
1 row in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
//执行完 rollback 后,刚才添加的数据会撤销
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
+------+--------+--------+
1 row in set (0.00 sec)
//取消自动提交(可以回滚了)
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 0 |
+--------------+
1 row in set (0.00 sec)
mysql> insert into bank value(2,'jingyi',500000);
Query OK, 1 row affected (0.00 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
+------+--------+--------+
2 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
//回滚成功
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
+------+--------+--------+
1 row in set (0.00 sec)
mysql> insert into bank value(2,'jingyi',500000);
Query OK, 1 row affected (0.00 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
+------+--------+--------+
2 rows in set (0.00 sec)
//不自动提交,可以手动提交,这样也不能 rollback
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
+------+--------+--------+
2 rows in set (0.00 sec)
//手动开启事务1:begin
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into bank value(3,'jiao',500000);
Query OK, 1 row affected (0.00 sec)
mysql> insert into bank value(4,'ling',30000);
Query OK, 1 row affected (0.00 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
| 3 | jiao | 500000 |
| 4 | ling | 30000 |
+------+--------+--------+
4 rows in set (0.00 sec)
//即使目前 autocommit 已经开启,但是手动开启事务,如果不 commit,还是可以 rollback,start transaction 同理
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)
//rollback 成功
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
+------+--------+--------+
2 rows in set (0.00 sec)
//手动开启事务2:start transaction
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into bank value(3,'jiao',500000);
Query OK, 1 row affected (0.00 sec)
mysql> insert into bank value(4,'ling',30000);
Query OK, 1 row affected (0.00 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
| 3 | jiao | 500000 |
| 4 | ling | 30000 |
+------+--------+--------+
4 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
+------+--------+--------+
2 rows in set (0.00 sec)
//手动开启事务(begin 或者 start transaction) 开启后一旦回滚一次,该事务就失效了,回滚会回到开启事务时的状态,因为没有提交(包括隐形提交)和加保存点(savepoint)
mysql> insert into bank value(3,'jiao',500000);
Query OK, 1 row affected (0.01 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
| 3 | jiao | 500000 |
+------+--------+--------+
3 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from bank;
+------+--------+--------+
| id | name | money |
+------+--------+--------+
| 1 | xiaoge | 500000 |
| 2 | jingyi | 500000 |
| 3 | jiao | 500000 |
+------+--------+--------+
3 rows in set (0.00 sec)
事务隔离性
- read uncommitted:读未提交的
- read committed:读已提交的
- repeatable read:重复读
- serializable:串行化
- session和global
- 默认行为(不带 session 和 global)是为下一个(未连接)会话设置隔离级别。
- 如果使用 global 关键字,此命令语句在全局中对从那时刻开始创建的所有新连接设置事务级别
- 使用 session 关键字为当前连接上执行的事务设置默认事务级别。
- 任何客户端在任何时候都能自由改变会话/全局隔离级别(甚至在事务的中间),或者为下一个事务设置隔离级别。
- 性能排比:read uncommitted > read committed > repeatable read > serializable
- 隔离级别和性能刚好相反,隔离级别越高,性能越差
- mysql 默认隔离级别是 repeatable read
隔离性导致的问题
- 脏读:一个事务读到另一个事务没有提交的数据,就叫脏读,脏读在实际开发中几乎是不允许的,即不允许出现 read uncommitted,比如事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读:read committed导致的,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读,比如事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读(不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表)
- 串行化(排队):当一张表被一个事务操作时,其他事务想要对此表操作(除了查 select)是不能进行的(进入排队),直到第一个事务结束,下一个事务的操作(除了查 select)才能执行(在没有等待超时的情况下)
//read uncommitted:如果有事务a 和事务b,a 事务对数据进行操作,在操作过程中,a 事务没有被提交,但是 b 可以看见 a 的操作结果,这样会产生脏读,因为 b 看到没提交的 a 之后 a 可能 rollback,这样 b 看到错误的数据
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
//默认是重复读:repeatable read
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
//更改会话事务隔离性
mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.01 sec)
mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)
//更改全局事务隔离性
mysql> set global transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| READ-UNCOMMITTED |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
mysql> set global transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
事务隔离性测试
//mysql 8.0+
//查看系统级别
select @@global.transaction_isolation;
//查看会话级别
select @@transaction_isolation;
//mysql 5.x
//查看系统级别
select @@global.tx_isolation;
//查看会话级别
select @@tx_isolation;
//我的是 5.x
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
- 新测试20201007(两个都是 autocommit=0,root 用户删除一行数据后,ubuntu 用户查到的还是修改前的表的快照,所以仍能查到这行数据,但是无法修改、删除,可以再增加一个相同主键的数据,因为该行数据在数据库中已经删除了)
- 注意:实验时要都要开启事务,保证不在同一事务中,否则没意义
- 用户 root
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();//查看当前事务id
Empty set (0.00 sec)//因为开启事务后什么都没做(包括查询),还没有事务id
mysql> select * from table1;
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 桌姣 | 18 | 小哥 |
| 灵超 | 12 | 小哥 |
| 王洋 | 14 | 小哥 |
| 闫红 | 9 | 小哥 |
+--------+------+--------+
7 rows in set (0.00 sec)
mysql> SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();//经过查询后就有 事务id 了
+-----------------+
| TRX_ID |
+-----------------+
| 421131883024016 |
+-----------------+
1 row in set (0.00 sec)
mysql> delete from table1 where name='灵超';
Query OK, 1 row affected (0.00 sec)
mysql> SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();//进行操作后 事务id 会随之改变,当然,查询操作不会改变 事务id
+--------+
| TRX_ID |
+--------+
| 10162 |
+--------+
1 row in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();
Empty set (0.00 sec)
- 用户 ubuntu
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from table1;//此时 root 用户已经删除了 name='灵超',这里还能查到该行数据
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 桌姣 | 18 | 小哥 |
| 灵超 | 12 | 小哥 |
| 王洋 | 14 | 小哥 |
| 闫红 | 9 | 小哥 |
+--------+------+--------+
7 rows in set (0.00 sec)
mysql> update table1 set age=11 where name='灵超';//虽然能查到该行数据,但是无法修改、删除
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> update table1 set age=11 where name='灵超';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
mysql>
mysql> delete from table1 where name='灵超';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> select * from table1;
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 桌姣 | 18 | 小哥 |
| 灵超 | 12 | 小哥 |
| 王洋 | 14 | 小哥 |
| 闫红 | 9 | 小哥 |
+--------+------+--------+
7 rows in set (0.00 sec)
mysql> insert into table1 value('灵超',0,'小哥');//虽然表中还能查到该主键的数据,但是还能插入,因为在数据库中该主键已经删除了
Query OK, 1 row affected (0.00 sec)
事务隐式提交
ddl 会引起隐式提交
参考
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from table1;
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 王洋 | 14 | 小哥 |
+--------+------+--------+
4 rows in set (0.00 sec)
mysql> insert into table1 value('桌姣',18,'小哥');
Query OK, 1 row affected (0.00 sec)
mysql> create table table2(id tinyint primary key,
-> name varchar(8),
-> hobby varchar(3));
Query OK, 0 rows affected (0.04 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from table1;
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 桌姣 | 18 | 小哥 |
| 王洋 | 14 | 小哥 |
+--------+------+--------+
5 rows in set (0.00 sec)
savepoint 保存点
- 打保存点:
savepoint 保存点名
- 回滚到保存点:
rollback to 保存点名
- 注:回到保存点如果想回到事务开始时还可以 rollback
mysql> select * from table1;
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 桌姣 | 18 | 小哥 |
| 王洋 | 14 | 小哥 |
+--------+------+--------+
5 rows in set (0.00 sec)
mysql> insert into table1 value('闫红',9,'小哥');
Query OK, 1 row affected (0.00 sec)
mysql> savepoint 闫红;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into table1 value('吴艳',14,'小哥');
Query OK, 1 row affected (0.00 sec)
mysql> select * from table1;
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 吴艳 | 14 | 小哥 |
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 桌姣 | 18 | 小哥 |
| 王洋 | 14 | 小哥 |
| 闫红 | 9 | 小哥 |
+--------+------+--------+
7 rows in set (0.00 sec)
mysql> rollback to 闫红
Query OK, 0 rows affected (0.00 sec)
mysql> select * from table1;
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 桌姣 | 18 | 小哥 |
| 王洋 | 14 | 小哥 |
| 闫红 | 9 | 小哥 |
+--------+------+--------+
6 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from table1;
+--------+------+--------+
| name | age | hobby |
+--------+------+--------+
| 婧怡 | 19 | 小哥 |
| 文文 | 25 | 小哥 |
| 李娜 | 16 | 小哥 |
| 桌姣 | 18 | 小哥 |
| 王洋 | 14 | 小哥 |
+--------+------+--------+
5 rows in set (0.00 sec)
事务四大特征
- ACID
- A:原子性,事务是最小的工作单元,不可分割,要么成功,要么失败,不存在中间状态,事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样
- C:一致性,同一事务的 sql 语句,必须保证同时成功或者同时失败,比如转账,转出和转入金额一致,同时完成
- I:隔离性,事务之间是有隔离性的,同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账
- D:持久性,事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚
数据库表关系
- MySQL精髓是操作表,表中存储的是有关系的数据,表和表也有关联
- 1.一对一:A表中一条数据和B表中一条数据有关系
- 2.多对一(一对多):A表中多条数据和B表中一条数据有关系
- 3.多对多:A表中多条数据和B表中多条数据有关系
- 多对多在mysql中会用一个中间表C,A表和C表是一对多,B表和C表是一对多,所以A表和C表形成多对多
- 用于保持数据一致性,完整性
- MySQL用外键来实现这个约束
案例:
- 1.学院表,2.学生表,3.课程表,4.选课表
学院:python,java,c++
学生:zs,ls,ww,zl,hmm
学科:python_web,python_spider,python_analysis,jzee,qt
选课:zs:python_web,python_spider,python_analysis
ls:python_web
ww:python_spider
zl:jzee
hmm:qt
1.学院表: create table college(id int primary key auto_increment,name varchar(32)); 创建学院表
insert into college(name) values(“python”),(“java”),(“c++”);
2.学生表: create table student( id int primary key auto_increment, name varchar(32), c_id int, foreign key(c_id) references college(id));
insert into student(name,c_id) values (“zs”,1),(“ls”,1),(“ww”,1),(“zl”,2),(“hmm”,3);
#此处用到外键关联学院表的主键,1,2,3,分别对应学院表python,java,c++
3.课程表:create table course(id int primary key auto_increment, name varchar(32),c_id int,foreign key(c_id) references college(id));
insert into course(name,c_id) values (“python_web”,1),(“python_spider”,1),(“python_analysis”,1),(“jzee”,2),(“qt”,3);
4.选课表:create table enroll( stu_id int, cou_id int, primary key(stu_id,cou_id), foreign key(stu_id) references student(id), foreign key(cou_id) references course(id));
insert into enroll(stu_id,cou_id) values(1,1),(1,2),(1,3),(2,1),(3,2),(4,4),(5,5);
select s.id,s.name,c.name,cl.name from student as s,course as c,enroll as e,college as cl where e.stu_id=s.id and e.cou_id=c.id and s.c_id=cl.id;
#用一张表,内容是:学生id,学生姓名,报名课程名称
数据库三大设计范式
- 范式设计的越详细,对于某些实际操作可能更好,但不一定都是好处
第一范式 1NF
- 数据表中所有的字段都是不可分割的原子值
mysql> select * from studen;
+--------+---------+--------------+-----------+--------------------------+
| name | country | province | city | detail_addr |
+--------+---------+--------------+-----------+--------------------------+
| 小哥 | 中国 | 黑龙江省 | 肇东市 | 紫龙镇通肇路108号 |
+--------+---------+--------------+-----------+--------------------------+
1 row in set (0.00 sec)
//非第一范式
mysql> select * from stud;
+--------+-----------------------------------------------+
| name | addr |
+--------+-----------------------------------------------+
| xiaoge | 黑龙江省肇东市紫龙镇通肇路108号 |
+--------+-----------------------------------------------+
1 row in set (0.00 sec)
//第一范式
第二范式
- 满足第一范式条件下,第二范式要求:除主键外的每一列都必须完全依赖于主键,如果要出现不完全依赖,只可能发生在联合主键情况下
mysql> desc aorder;
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| product_id | int(11) | NO | PRI | NULL | |
| product_name | varchar(20) | YES | | NULL | |
| costumer_id | int(11) | NO | PRI | NULL | |
| costumer_name | varchar(20) | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
//不满足第二范式
mysql> desc product;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> desc customer;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> desc myorder;
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| product_id | int(11) | YES | | NULL | |
| customer_id | int(11) | YES | | NULL | |
+-------------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
//分成三个表后满足第二范式
第三范式
- 满足第二范式条件下,除主键列的其他列之间不能有传递依赖关系
mysql> desc product;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> desc customer;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> desc myorder;
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| product_id | int(11) | YES | | NULL | |
| customer_id | int(11) | YES | | NULL | |
| product_phone | varchar(11) | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
//不满足第三范式,product_id 依赖于 id,product_phone 依赖于 product_id,这就是传递依赖
---------------------------------------------------------------------
mysql> desc myorder;
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| product_id | int(11) | YES | | NULL | |
| customer_id | int(11) | YES | | NULL | |
+-------------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> desc customer;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> desc product;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
| phone | varchar(11) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
//满足第三范式
练习
mysql> desc student;
+----------+--------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------------+------+-----+---------+-------+
| sid | int(11) | NO | PRI | NULL | |
| name | varchar(10) | YES | | NULL | |
| gender | enum('girl','boy') | NO | | girl | |
| birthday | date | YES | | NULL | |
| class | varchar(10) | YES | | NULL | |
+----------+--------------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
mysql> desc course;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| cid | int(11) | NO | PRI | NULL | |
| name | varchar(10) | YES | | NULL | |
| tnum | int(11) | YES | MUL | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> desc teacher;
+----------+--------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------------+------+-----+---------+-------+
| tid | int(11) | NO | PRI | NULL | |
| name | varchar(10) | YES | | NULL | |
| gender | enum('girl','boy') | NO | | girl | |
| birthday | date | YES | | NULL | |
| job_name | varchar(10) | YES | | NULL | |
| depart | varchar(20) | NO | | NULL | |
+----------+--------------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
mysql> desc score;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| sid | int(11) | NO | PRI | NULL | |
| cid | int(11) | NO | PRI | NULL | |
| score | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
//查询 student 表中所有数据
mysql> select * from student;
+-------+--------+--------+------------+---------+
| sid | name | gender | birthday | class |
+-------+--------+--------+------------+---------+
| 10001 | xiaoge | boy | 1993-02-04 | math |
| 10002 | hong | girl | 1991-02-24 | math |
| 10003 | yang | girl | 1994-03-05 | math |
| 10004 | na | girl | 1992-12-19 | chinese |
| 10005 | ling | girl | 1992-02-15 | english |
| 10006 | yan | girl | 1992-03-20 | huaxue |
| 10007 | jingyi | girl | 1994-10-09 | huaxue |
| 10008 | wen | girl | 1991-10-29 | wuli |
| 10009 | long | boy | 1990-10-01 | chinese |
| 10010 | jiao | girl | 1994-11-18 | math |
+-------+--------+--------+------------+---------+
10 rows in set (0.00 sec)
mysql> select * from course;
+-----+---------+------+
| cid | name | tnum |
+-----+---------+------+
| 101 | huaxue | 1 |
| 102 | math | 2 |
| 103 | english | 3 |
| 104 | chinese | 4 |
| 105 | wuli | 5 |
+-----+---------+------+
5 rows in set (0.00 sec)
//查询 course 表中的所有记录的 name 和 tnum 列
mysql> select name,tnum from course;
+---------+------+
| name | tnum |
+---------+------+
| huaxue | 1 |
| math | 2 |
| english | 3 |
| chinese | 4 |
| wuli | 5 |
+---------+------+
5 rows in set (0.00 sec)
mysql> select * from teacher;
+-----+----------+--------+------------+-----------------+---------+
| tid | name | gender | birthday | job_name | depart |
+-----+----------+--------+------------+-----------------+---------+
| 1 | xiaoge | boy | 1993-02-04 | 博士生导师 | huaxue |
| 2 | xiaohong | girl | 1993-02-04 | 高级教师 | math |
| 3 | xiaojiao | girl | 1993-02-04 | 高级教师 | english |
| 4 | xiaona | girl | 1992-12-19 | 教师 | chinese |
| 5 | xiaoyi | girl | 1994-10-09 | 研究生导师 | wuli |
+-----+----------+--------+------------+-----------------+---------+
5 rows in set (0.00 sec)
//查询所有的教师不重复的 depart
mysql> select distinct job_name from teacher;
+-----------------+
| job_name |
+-----------------+
| 博士生导师 |
| 高级教师 |
| 教师 |
| 研究生导师 |
+-----------------+
4 rows in set (0.00 sec)
//distinct:查询字段不重复的数据
mysql> select * from score;
+-------+-----+-------+
| sid | cid | score |
+-------+-----+-------+
| 10001 | 101 | 150 |
| 10002 | 101 | 149 |
| 10003 | 101 | 148 |
+-------+-----+-------+
3 rows in set (0.00 sec)
函数
concat
CONCAT(str1,str2,…) ,返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。或许有一个或多个参数