1.Mysql锁
行级锁又分共享锁和排他锁。
共享锁:名词解释:共享锁又叫做读锁,所有的事务只能对其进行读操作不能写操作,加上共享锁后在事务结束之前其他事务只能再加共享锁,除此之外其他任何类型的锁都不能再加了。
用法: select * from user where id >1 lock in share mode ; 显示加锁
排他锁(X锁):允若某个事物对某一行加上了排他锁,只能这个事务对其进行读写,在此事务结束之前,其他事务不能对其进行加任何锁,其他进程可以读取,不能进行写操作,需等待其释放。也叫做写锁:写锁是排他的,写锁会阻塞其他的写锁和读锁。
用法: select * from user where id >1 for update;显示加锁
死锁:死锁一般是事务之间相互等待对方资源,最后形成环路造成的。
死锁产生的四个必要条件:互斥条件、环路条件、请求保持、不可剥夺,缺一不可,相对应的只要破坏其中一种条件死锁就不会产生。
MyISAM表锁是deadlock free的,这是因为MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。
解决死锁:让不同事物加锁有次序。
2.mysql 存储引擎:主要是MyISAM和InnoDB
参考:https://www.cnblogs.com/wcwen1990/p/6655416.html
可以通过show engines查询
MyISAM:该存储引擎不支持事务,也不支持外键,所以访问速度最快,适合以select 和 Insert 操作为主的表。支持的存储格式:静态表(默认,但是注意数据末尾d不能有空格,会被去掉)、动态表、压缩表。支持大文件存储
MyISAM是没有死锁问题的,因为他会一次性获得所有的锁。
InnoDB:Mysql 5.5版本以上默认的存储引擎。并默认是使用行级锁,采用 MVCC 来支持高并发、支持事务 、支持外键、支持崩溃后的安全恢复、不支持全文索引。
对于 UPDATE、 DELETE 和 INSERT 语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通 SELECT 语句,InnoDB不会加任何锁。
区别:
1.InnoDB支持事务
2.MyISAM只支持标所,InnoDB支持表锁和行锁,默认行锁
3.MyISAM引擎不支持外键,InnoDB支持外键
4、MyISAM引擎的表在大量高并发的读写下会经常出现表损坏的情况
5、对于count()查询来说MyISAM更有优势。因为MyISAM存储了表中的行数记录,执行SELECT COUNT() 的时候可以直接获取到结果,而InnoDB需要扫描全部数据后得到结果。对于带有where条件语句的都一样。
6、 InnoDB是为处理巨大数据量时的最大性能设计,它的CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。
7、MyISAM支持全文索引(FULLTEXT),InnoDB不支持
8、MyISAM引擎的表的查询、更新、插入的效率要比InnoDB高
3.索引
唯一索引:unique index 与普通索引类似,不同的就是索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
用法:create unique index 索引名 on 表名(列名)或 drop unique index 索引名 on 表名 或者alter table 表名add unique index on 表名(列名)
主键索引:primary key ,特殊的唯一索引,不允许空值
用法:alter table 表名add primary key(列名) 或 alter table 表名 drop primary key
普通索引:index 最基本的索引,它没有任何限制
用法:create index 索引名 on 表名(列名)或 drop index 索引名 on 表名
全文索引:仅支持MyISAM存储引擎的表中。fulltext
索引最左前缀匹配原则。 组合索引时使用比如a,b组合索引,要求是a、ab单独b不走
= in mysql会自动优化顺序 例子:
如有索引(a, b, c, d),查询条件c > 3 and b = 2 and a = 1 and d < 4与a = 1 and c > 3 and b = 2 and d < 4等顺序都是可以的,MySQL会自动优化为a = 1 and b = 2 and c > 3 and d < 4,依次命中a、b、c。
索引优化:
1.索引字段要尽量的小。我们知道IO次数取决于b+数的高度h,假设当前数据表的数据为N,每个磁盘块的数据项的数量是m,则有h=㏒(m+1)N,当数据量N一定的情况下,m越大,h越小;而m = 磁盘块的大小 / 数据项的大小,磁盘块的大小也就是一个数据页的大小,是固定的,如果数据项占的空间越小,数据项的数量越多,树的高度越低。
2、最左前缀匹配原则,非常重要的原则。组合索引时使用比如a,b组合索引,要求是a、ab单独b不走
3、like语句:一般情况下不鼓励使用like操作,like ‘%aaa%'不会使用索引,而like ‘aaa%'可以使用索引。
4、不要在索引列上进行运算
5、不使用NOT IN 、<>、!=操作,但是索引是整数类型<,<=,=,>,>=,BETWEEN,IN是可以用到索引的
6、尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),
表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1
7、对于那些定义为text、image和bit数据类型的列不应该增加索引。因为这些列的数据量要么相当大,要么取值很少。
8.索引列排序:mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作,尽量不要包含多个列的排序,如果需要最好给这些列建复合索引。
排序条件为索引,则select字段必须也是索引字段。但是之间索引会走排序
select name from s1 order by email desc; 不走 索引
9 别使用or select*fromt b1 wheren id =1 or name ='seven';
特别的:当or条件中有未建立索引的列才失效,以下会走索引
10.组合索引代替多个单列索引(经常使用多个条件查询时)
4.B+Tree结构(InnoDB索引的结构)
B+Tree树结构,特点是:
1.所有非叶节点不存储data,只存储键值信息
2.只有叶节点存储data
3所有叶子节点之间都有一个链指针,这样就提高了区间访问性能:如果要查询key为从17到35的所有数据记录,当找到17后,只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点,极大提到了区间查询效率(无需返回上层父节点重复遍历查找减少IO操作)。
拓展:B-Tree结构:每个节点都是一个二元数组[key,data]
插入删除新的数据记录会破坏B-Tree的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持B-Tree性质
为什么使用B+Tree:
1.文件很大,不可能全部存储在内存中,故要存储到磁盘上
2.索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数(为什么使用B-/+Tree,还跟磁盘存取原理有关。)
3.局部性原理与磁盘预读,预读的长度一般为页(page)的整倍数,(在许多操作系统中,页得大小通常为4k)
4.数据库系统巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入,(由于节点中有两个数组,所以地址连续)。而红黑树这种结构,明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性。B-Tree每一个包括key和data,这样每一页存储的key就很少,B-Tree的深度就很大,增加了I/O次数
拓展:红黑树,变色:红黑变色。左旋转和右旋转
(1)每个结点要么是红的要么是黑的。
(2)根结点是黑的。
(3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。
(4)如果一个结点是红的,那么它的两个儿子都是黑的。
(5)对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。
5.数据库事务
事务四大特性ACID,四大特性:
原子性:原子性是指事务是一个不可再分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性:一致性是指事务使得系统从一个一致的状态转换到另一个一致状态。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。比如扣费:总和要是一致
隔离性:多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。
持久性:事务一旦提交,则持久化保存在数据库中。
几个问题:
脏读:脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
不可重复读:重点是值被修改。指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
幻读:幻读的重点在于新增或者删除 (数据条数变化)。幻读发生在当两个完全相同的查询执行时,第二次查询所返回的结果集跟第一个查询不相同。
事物的隔离级别,从低到高四个:Read uncommitted 、Read committed 、Repeatable read(mysql的默认级别)、Serializable
实现原理,参考:https://www.cnblogs.com/heyboom/p/9167394.html
1. Read UnCommitted(读未提交):读未加锁,事务修改增加行共享锁。
最低的隔离级别。一个事务可以读取另一个事务并未提交的更新结果。
2. Read Committed(读提交):读加共享锁,读完释放。更新加行排他锁,事务提交才释放。
大部分数据库采用的默认隔离级别。一个事务的更新操作结果只有在该事务提交之后,另一个事务才可以的读取到同一笔数据更新后的结果。
3. Repeatable Read(重复读):读加行共享锁,更新增加行排他锁,都在事务结束才释放。
mysql的默认级别。整个事务过程中,对同一笔数据的读取结果是相同的,不管其他事务是否在对共享数据进行更新,也不管更新提交与否。
4. Serializable(序列化):事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。
最高隔离级别。所有事务操作依次顺序执行。注意这会导致并发度下降,性能最差。通常会用其他并发级别加上相应的并发锁机制来取代它。
PROPAGATION(事务传播属性)
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。也就是说业务方法需要在一个事务中运行,如果业务方法被调用时,调用业务方法的行为(方法)已经处在一个事务中,那么就加入到该事务,否则为自己创建一个新的事务。(默认传播属性)
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。也就是说如果业务方法在某个事务范围内被调用,则该方法成为该事务的一部分。如果业务方法在事务范围外被调用,则该方法在没有事务的环境下执行。
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。也就是说业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下被调用,容器就会抛出例外。
PROPAGATION_REQUIRESNEW:新建事务,如果当前存在事务,把当前事务挂起。也就是说业务方法被调用时,不管是否已经存在事务,业务方法总会为自己发起一个新的事务。如果调用业务方法的行为(方法)已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到业务方法执行结束,新事务才算结束,原先的事务才会恢复执行。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,就把当前事务挂起。也就是说业务方法不需要事务。如果方法没有被关联到一个事务中,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。也就是说业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行。
PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按REQUIRED属性执行。它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只DataSourceTransactionManager事务管理器起效。