事务:start transaction;、commit; 、rollback;
事务的四大特性
原子性:事务是一组不可分割的单位,要么同时成功要么同时不成功一致性:事务前后的数据完整性应该保持一致,隔离性:多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰持久性:一个事务一旦被提交,对数据库中的数据的改变就是永久性的,即使数据库发生故障也不应该对其有任何影响。读的种类
脏读:一个事务读取到另一个事务未提交的数据不可重复读:一个事务多次读取同一条记录,读取的结果不相同虚读(幻读):一个事务多次查询整表的数据,由于其他事务新增(删除)记录造成多次查询出的记录条数不同。四大隔离级别
隔离级别脏读(Dirty Read)不可重复读(NonRepeatable Read)幻读(Phantom Read)读未提交(Read uncommitted)可能可能可能不可重复读(Read committed)不可能可能可能可重复读(Repeatable read)不可能不可能可能可串行化(SERIALIZABLE)不可能不可能不可能注:mysql 默认是repeatable read 级别!
使用步骤
注册驱动:Class.forName(“com.mysql.jdbc.Driver”);建立连接:Connection conn = DriverManager.getConnection(URL, user, password);执行SQL语句:PreparedStatement ps = conn.prepareStatement(sql);PreparedStatement 可用预编译的sql、sql缓存区、有效防止sql注入(OR 1=1 )执行处理结果:ResultSet rs = ps.executeQuery();常用组件
BeanUtils:对象的拷贝、注册日期类型转换器DbUtils:定义了所有的与数据库操作的方法,简化编码量C3P0连接池:new ComboPooledDataSource();建立索引的目的是加快对表中记录的查找或排序,但索引是占用空间的,影响速度。索引类型:主键索引、唯一索引、普通索引、全文索引(FULLTEXT ),而主键索引是特殊的唯一性索引。
MySQL支持MyISAM、InnoDB、MEMORY、MERGE、ARCHIVE多种存储引擎,而默认是InnoDB
MyISAM:独立于操作系统,表锁,不支持外键、事务。存储格式分为静态、动态、压缩表,适合以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性,并发性要求不是很高的情况
InnoDB:默认,行级锁定、外键约束、自动灾难恢复、支持事务。对事物的完整性有比较高的要求,在并发条件下要求数据的一致性,包含很多操作。InnoDB只有通过索引进行检索的时候才会使用行级锁,否则会使用表级锁。
MEMORY:存在内存,为得到最快的响应时间;MERGE:一组MyISAM表的组合;ARCHIVE:归档后仅支持插入和查询。
实现方式:
MyISAM:使用B+ Tree作为索引结构,叶节点存放的是数据记录的地址,索引和实际的数据是分开的,只不过是用索引指向了实际的数据,即非聚集索引。InnoDB:数据本身就是按B+ Tree组织的一个索引结构,叶节点存放的是完整的数据记录,即聚集索引,主键是InnoDB表记录的”逻辑地址“,所以InnoDB要求表必须有主键,MyISAM可以没有。几种索引结构的区别:
B tree:适合在磁盘等直接存储设备上组织动态查找表,因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少,这时若要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低;Hash:虽然可以快速定位,但是没有顺序,IO复杂度高。并存在散列冲突问题,一般利用率仅为50%,当存储比例达到一定程度时hash表必须进行扩容才能维持之后的操作。二叉树:树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高。红黑树:树的高度随着数据量增加而增加,IO代价高。数据结构作为索引的优劣指标:索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数,因为影响MySQL查找性能的主要是磁盘IO次数,大部分是磁头移动到指定磁道的时间花费。
从物理存储结构上说,B-Tree和B+Tree都以页(4K)来划分节点的大小,但是由于B+Tree中中间节点不存储数据,因此B+Tree能够在同样大小的节点中,存储更多的key,提高查找效率。
B+树可以对叶子结点顺序查找,因为叶子结点存放了数据结点且有序
自增主键若是无符号整型,存储范围约43亿!若自增id达到最大值,数据继续插入时会报一个主键冲突异常。解决方法:将Int类型改为BigInt
怎么在线上修改列的数据类型?
使用mysql5.6+提供的在线修改功能:不支持并发的DML,会导致这张表无法进行更新类操作。借助第三方工具:pt-osc、gh-ost等。改从库表结构,然后主从切换。终极答案:自增主键达到最大值前,进行分库分表。
如何拆分?
水平拆分:将一个表的数据分别保存到多个库的多个表中,但是每个库的表结构都一样,只不过每个库表放的数据是不同的,所有库表的数据加起来就是全部数据。垂直拆分:将一个有很多字段的表给拆分成多个表或多个库。每个库表的结构都不一样,每个库表都包含部分字段。分库分表的方式?
hash取模:数据分布均匀,扩容麻烦。range:方便扩容,容易产生热点问题,即大部分的请求都是访问最新的数据。分库分表后的主键id怎么生成?
数据库的自增ID:简单、高效,但高并发、分布式情况下性能比较低。Flicker:充分借助数据库的自增ID机制,提供高可靠性,生成的ID有序。但占用两个独立的MySQL实例,成本较高。Redis的原子操作INCR和INCRBY:id有序,但增加了系统复杂度。UUID:扩展性好,但无法保证趋势递增,作为主键性能差。Snowflake算法:高性能、低延迟。 但依赖机器的时钟,如果服务器时钟回拨,会导致重复ID生成,分布式环境的每个服务器的时钟不可能完全同步,所以可能会出现非全局递增的情况。拆分后的查询过程?
分库分表后利用一主多从或多主多从解决读写压力
InnoDB一棵B+树可以存放多少行数据?
约2千万, InnoDB存储引擎的最小存储单元是页,页可以用于存放数据也可以用于存放键值+指针,在B+树中叶子节点存放数据,非叶子节点存放键值+指针。索引组织表通过非叶子节点的二分查找法以及指针确定数据在哪个页中,进而在去数据页中查找到需要的数据;一条SQL执行慢的原因?
概率很慢:数据库在刷新脏页,例如 redo log 写满了需要同步到磁盘,或是执行的时候,遇到锁,如表锁、行锁。一直很慢:数据库选错了索引,或是没有用到索引,例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引。MySQL中乐观锁与悲观锁的实现?
乐观锁通过记录数据版本来实现,即通过在表中添加版本号字段来作为是否可以成功提交的关键因素。悲观锁可以通过select * for update加上排它锁。主键索引和普通索引的区别?
主键索引的叶子结点存放了整行记录,普通索引的叶子结点存放了主键ID,查询的时候需要做一次回表查询;不一定要回表查询,当查询的字段刚好是索引的字段或者索引的一部分,就可以不用回表,这也是索引覆盖的原理。为什么官方建议使用自增长主键作为索引?
结合B+Tree的特点,自增主键是连续的,在插入过程中尽量减少页分裂,即使要进行页分裂,也只会分裂很少一部分。并且能减少数据的移动,每次插入都是插入到最后。总之就是减少分裂和移动的频率。若主索引不是自增的(id作主键),那么每次插入新的数据,都很可能对B+Tree的主索引进行重整,影响性能。因此,尽量以自增id作为InnoDB的主索引。MySQL如何实现Rollback?
数据库在写入数据之前是先对数据的改动写入redolog和undolog,然后在操作数据,如果成功提交事务就会讲操作写入磁盘;如果失败就会根据redolog和undolog逆向还原到事务操作之前的状态。redolog记录物理日志,记录的是数据页的物理修改,用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。undolog记录逻辑日志,它的作用是提供回滚和多个行版本控制(MVCC)。MRR、ICP和BKA是什么?
MRR(Multi-Range Read)是优化器将随机 IO 转化为顺序 IO 以降低查询过程中 IO 开销的一种手段。ICP(Index Condition Pushdown)是mysql使用索引从表中检索行数据的一种优化方式,并会大大减少行锁的个数。ICP的目标是减少从基表中全纪录读取操作的数量,从而降低IO操作。对于InnoDB表,ICP只适用于辅助索引。BKA(Batched Key Access)是提高表join性能的算法。当被join的表能够使用索引时,就先好顺序,然后再去检索被join的表。对这些行按照索引字段进行排序,因此减少了随机IO。如果被Join的表上没有索引,则使用老版本的BNL(Block Nested Loop)策略。本人才疏学浅,若有错,请指出,谢谢! 如果你有更好的建议,可以留言我们一起讨论,共同进步! 衷心的感谢您能耐心的读完本篇博文!