方法三:create table 创建表时指定存储引擎
use 库名; create table 表名(字段1 数据类型,...) engine=存储引擎名称; 复制代码
示例:
use school; create table teacher(id int,name varchar(10)) engine=MyISAM; #指定存储引擎为MyISAM 复制代码
六、InnoDB行锁与索引的关系
准备一个数据表t1:
create table t1(id int primary key,name char(10),age int); insert into t1 values(1,'aaa',22); insert into t1 values(2,'bbb',23); insert into t1 values(3,'aaa',24); insert into t1 values(4,'bbb',25); insert into t1 values(5,'ccc',26); insert into t1 values(6,'zzz',27); alter table t1 add index name_index(name); #对name字段创建普通索引 复制代码
6.1 行级锁定与表级锁定
InnoDB行锁是通过给索引项加锁来实现的,如果没有索引,InnoDB将通过隐藏的聚簇索引来对记录加锁。
1)delete from t1 where id=1;
因为id字段是主键,Innodb对于主键使用了聚簇索引,删除过程中会直接锁住整行记录。行级锁定。
2)delete from t1 where name='aaa';
因为name字段是普通索引,会先锁住索引的两行(因为aaa有两行),接着会锁住相应主键对应的记录。行级锁定。
3)delete from t1 where age=23;
因为age字段没有索引,会使用全表扫描过滤,这时表上的各个记录都将加上锁。表级锁定。
6.2 死锁
死锁一般是事务相互等待对方资源,最后形成环路造成的。
session1 | session2 |
begin; | begin; |
delete from t1 where id=5;#事务结束前,id=5的行会被锁定 | |
select * from t1 where id=1 for update; #加排他锁,模拟并发情况,锁定id=1的行 | |
delete from t1 where id=1; #死锁产生 | |
update t1 set name='abc' where id=5; #死锁产生。因为会话1中id=5的行还在删除过程中,该行已被锁定 | |
rollback; #回滚,结束事务。id=5的行被解锁 | |
update t1 set name='abc' where id=5; #成功更新数据 |
for update: 可以为数据库中的行上一个排它锁。当一个事务的操作未完成时,其他事务可以读取该行数据,但是不能写入、更新或删除。
死锁演示:
会话1:
会话2:
会话1:
会话2:
会话1:
会话2:
6.3 如何尽可能避免死锁
1、使用更合理的业务逻辑,以固定的顺序访问表和行。
2、大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
3、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
4、降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。
5、为表添加合理的索引。如果不使用索引将会为表的每一行记录添加上锁,死锁的概率大大增加。
总结:
MyISAM和InnoDB的区别:
MyISAM: 不支持事务和外键约束,占用空间较小,访问速度快,表级锁定,适用于不需要事务处理、单独写入或查询的应用场景。(写入和查询不一起使用的场景)
InnoDB: 支持事务处理、外键约束、占用空间比MyISAM 大,支持行级锁定,读写开发能力较好,适用于需要事务处理、读写频繁的应用场景。
查看系统支持的存储引擎:
show engines;
查看表使用的存储引擎:
方法一:show table status from 库名 where name='表名'\G
方法二:show create table 表名;
修改存储引擎:
方法一:修改已存在的表使用的存储引擎
alter table 表名 engine=存储引擎名称;
方法二:修改配置文件,指定默认存储引擎
vim /etc/my.cnf
[mysqld]
default-storage-engine=InnoDB #修改这一行,指定默认存储引擎为InnoDB
systemctl restart mysqld #重启服务
方法三:创建表时指定存储引擎
create table 表名(字段1 数据类型,...) engine=存储引擎名称;