数据库-MySQL

MySQL总结

  • 一、什么是MySQL?
  • 二、存储引擎
    • 1.InnoDB
    • 2.MyISAM
    • 3.两者的对比
  • 三、索引
  • 四、查询缓存的使用
  • 五、事务
    • 1.什么是事务
    • 2.事务的四大特性
    • 3.并发事务带来的问题
      • (1)丢失修改
      • (2)脏读
      • (3)不可重复读
      • (4)幻读
    • 4.事务的隔离级别
  • 六、锁机制与算法
    • 1.封锁粒度
    • 2.封锁类型
      • (1)读写锁
      • (2)意向锁
      • (3)InnoDB的锁机制兼容情况
    • 3.死锁
      • (1)MVCC
      • (2)2PL(Two-Phase Locking)
      • (3)死锁和避免死锁
  • 七、大表优化
  • 八、数据库连接池
  • 九、分库分表之后,id主键如何处理?

前言:

       MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。

一、什么是MySQL?

       MySQL 是⼀种关系型数据库,在Java企业级开发中⾮常常用,因为 MySQL 是开源免费的,并且方便扩展。阿里巴巴数据库系统也⼤量⽤到了 MySQL,因此它的稳定性是有保障的。MySQL是开放源代码的,因此任何⼈都可以在 GPL(General Public License) 的许可下下载并根据个性化的需要对其进行修改。MySQL的默认端⼝号是3306。

二、存储引擎

(1)查看 MySQL 提供的所有存储引擎

mysql> show engines;

数据库-MySQL_第1张图片
从上图我们可以查看出 MySQL 当前默认的存储引擎是 InnoDB,并且在5.7版本所有的存储引擎中只有InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。

(2)查看 MySQL 当前默认的存储引擎

mysql> show variables like '%storage_engine%';

数据库-MySQL_第2张图片

(3)查看表的存储引擎

mysql> show table status like "table_name";

数据库-MySQL_第3张图片

1.InnoDB

是 MySQL 默认的事务型存储引擎,只有在需要它不支持的特性时,才考虑使用其它存储引擎。

实现了四个标准的隔离级别,默认级别是可重复读(REPEATABLE READ)。在可重复读隔离级别下,通过多版本并发控制(MVCC)+ Next-Key Locking 防止幻影读。

主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。

内部做了很多优化,包括从磁盘读取数据时采用的可预测性读、能够加快读操作并且自动创建的自适应哈希索引、能够加速插入操作的插入缓冲区等。

支持真正的在线热备份。其它存储引擎不支持在线热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。

2.MyISAM

设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。

提供了大量的特性,包括压缩表、空间数据索引等。

不支持事务。

不支持行级锁,只能对整张表加锁,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。

可以手工或者自动执行检查和修复操作,但是和事务恢复以及崩溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的。

如果指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。

3.两者的对比

  1. 是否支持行级锁:MyISAM 只有表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking)和表级锁,默认行为行级锁。
  2. 是否支持事务和崩溃后的安全恢复:MyISAM 强调的是性能,每次查询具有原子性,其执行速度比 InnoDB 类型更快,但是不提供事务支持。但是 InnoDB 提供事务支持,外部键等高级数据库功能。具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
  3. 是否支持外键:MyISAM 不支持,而 InnoDB 支持。
  4. 是否支持MVCC:仅 InnoDB 支持。应对高并发事务,MVCC比单纯的加锁更高效;MVCC只在READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作;MVCC可以使用 乐观锁 和 悲观锁 来实现;各数据库中MVCC实现并不统一。
  5. 备份:InnoDB 支持在线热备份。
  6. 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。
  7. 其它特性:MyISAM 支持压缩表和空间数据索引。

《MySQL高性能》上面有一句话这样写到:

不要相信“MyISAM⽐InnoDB快”之类的经验之谈,这个结论往往不是绝对的。在很多我们已知场景中,InnoDB的速度都可以让MyISAM望尘莫及,尤其是⽤到了聚簇索引,或者需要访问的数据都可以放⼊内存的应⽤。

⼀般情况下我们选择 InnoDB 都是没有问题的,但是某些情况下你并不在乎可扩展能力和并发能力,也不需要事务支持,也不在乎崩溃后的安全恢复问题的话,选择MyISAM也是⼀个不错的选择。但是⼀般情况下,我们都是需要考虑到这些问题的。

三、索引

MySQL索引使⽤的数据结构主要有 BTree 索引 和 哈希 索引 。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝⼤多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余⼤部分场景,建议选择BTree索引。

MySQL的BTree索引使⽤的是B树中的B+Tree,但对于主要的两种存储引擎的实现⽅式是不同的

  • MyISAM: B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,⾸先按照 B+Tree 搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。
  • InnoDB: 其数据⽂件本身就是索引⽂件。相⽐MyISAM,索引⽂件和数据⽂件是分离的,其表数据⽂件本身就是按B+Tree组织的⼀个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”。而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。再根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再⾛⼀遍主索引。 因此,在设计表的时候,不建议使⽤过⻓的字段作为主键,也不建议使⽤非单调的字段作为主键,这样会造成主索引频繁分裂。

四、查询缓存的使用

执行查询语句的时候,会先查询缓存。不过,MySQL 8.0 版本后移除,因为这个功能不太实用

my.cnf 加入以下配置,重启 MySQL 开启查询缓存

query_cache_type=1
query_cache_size=60000

MySQL 执行以下命令也可以开启查询缓存

set global query_cache_type=1;
set global query_cache_size=600000;

如上,开启查询缓存后在同样的查询条件以及数据情况下,会直接在缓存中返回结果。这⾥的查询条件包括查询本身、当前要查询的数据库、客户端协议版本号等⼀些可能影响结果的信息。因此任何两个查询在任何字符上的不同都会导致缓存不命中。此外,如果查询中包含任何⽤户⾃定义函数、存储函数、⽤户变量、临时表、MySQL库中的系统表,其查询结果也不会被缓存。

缓存建⽴之后,MySQL的查询缓存系统会跟踪查询中涉及的每张表,如果这些表(数据或结构)发⽣变化,那么和这张表相关的所有缓存数据都将失效。

缓存虽然能够提升数据库的查询性能,但是缓存同时也带来了额外的开销,每次查询后都要做⼀次缓存操作,失效后还要销毁。 因此,开启缓存查询要谨慎,尤其对于写密集的应⽤来说更是如此。如果开启,要注意合理控制缓存空间大小,⼀般来说其大小设置为几十MB比较合适。此外,还可以通过 sql_cache 和 sql_no_cache 来控制某个查询语句是否需要缓存:

select sql_no_cache count(*) from usr;

五、事务

1.什么是事务

事务是逻辑上的⼀组操作,要么都执行,要么都不执行。

事务最经典也经常被拿出来说例⼦就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万⼀在这两个操作之间突然出现错误比如银⾏系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。

2.事务的四大特性

数据库-MySQL_第4张图片

  • 原子性(Atomicity):事务是最小的执⾏单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作⽤;
  • 一致性(Consistency):执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;
  • 隔离性(Isolation):并发访问数据库时,⼀个用户的事务不被其他事务所干扰,各并发事务之间数据库是独⽴的;
  • 持久性(Durability):⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不应该对其有任何影响。

3.并发事务带来的问题

在并发环境下,事务的隔离性很难保证,因此会出现很多并发一致性问题。

(1)丢失修改

数据库-MySQL_第5张图片
指在⼀个事务读取⼀个数据时,另外⼀个事务也访问了该数据,那么在第⼀个事务中修改了这个数据后,第⼆个事务也修改了这个数据。这样第⼀个事务内的修改结果就被丢失,因此称为丢失修改。例如:事务A读取某表中的数据T=100,事务B也读取T=100,事务A修改T=T-10,事务B也修改T=T-10,最终结果T=90,事务A的修改被丢失。

(2)脏读

数据库-MySQL_第6张图片
读脏数据指在不同的事务下,当前事务可以读到另外事务未提交的数据。例如:事务A修改一个数据但未提交,事务B随后读取这个数据。如果 事务A撤销了这次修改,那么事务B读取的数据是脏数据。

(3)不可重复读

数据库-MySQL_第7张图片
不可重复读指在一个事务内多次读取同一数据集合。在这一事务还未结束前,另一事务也访问了该同一数据集合并做了修改,由于第二个事务的修改,第一次事务的两次读取的数据可能不一致。例如:事务B 读取一个数据,事务A 对该数据做了修改。如果 事务B 再次读取这个数据,此时读取的结果和第一次读取的结果不同。

(4)幻读

数据库-MySQL_第8张图片
幻读与不可重复读类似。例如:⼀个 事务A 读取了几行数据,接着另⼀个并发 事务B 插⼊了⼀些数据时。在随后的查询中, 事务A 就会发现多了⼀些原本不存在的记录,就好像发生了幻觉⼀样,所以称为幻读。

不可重复读和幻读区别:
不可重复读的重点是修改,比如多次读取⼀条记录发现其中某些列的值被修改。
幻读的重点在于新增或者删除,比如多次读取⼀条记录发现记录增多或减少了。

4.事务的隔离级别

SQL 标准定义了四个隔离级别

  • 读取未提交(READ-UNCOMMITTED): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • 读取已提交(READ-COMMITTED): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发⽣。
  • 可重复读(REPEATABLE-READ): 对同⼀字段的多次读取结果都是⼀致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发⽣。
  • 可串行化(SERIALIZABLE): 最⾼的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产⽣干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

隔离级别 脏读 不可重复读 幻读
读取未提交(READ-UNCOMMITTED)
读取已提交(READ-COMMITTED) ×
可重复读(REPEATABLE-READ) × ×
可串行化(SERIALIZABLE) × × ×

MySQL InnoDB 存储引擎的默认支持的隔离级别是 可重复读(REPEATABLE-READ)

mysql> SELECT @@tx_isolation;

数据库-MySQL_第9张图片

这里需要注意的是:与 SQL 标准不同的地方在于 InnoDB 存储引擎在 可重复读(REPEATABLE-READ) 事务隔离级别下使用的是 Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其它数据库系统(如 SQL Server)是不同的。所以说 InnoDB 存储引擎默认支持的隔离级别是 可重复读(REPEATABLE-READ) 已经可以完全保证事务的隔离性要求,即达到了 SQL 标准的 可串行化(SERIALIZABLE) 隔离级别。因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 读取已提交(READ-COMMITTED),但是你要知道的是 InnoDB 存储引擎默认使用 可重复读(REPEATABLE-READ) 并不会有任何性能损失。

InnoDB 存储引擎在 分布式事务 的情况下一般会用到 可串行化(SERIALIZABLE) 隔离级别。

六、锁机制与算法

1.封锁粒度

  • 表级锁
    MySQL 中锁定粒度最大的一种锁,对当前操作的整张表加锁,实现简单 ,资源消耗也比较少,加锁快,不会出现死锁 。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。

  • 行级锁
    MySQL 中锁定粒度最小的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。 InnoDB 支持的行级锁,包括如下几种。

    • Record Lock: 对索引项加锁,锁定符合条件的行。其他事务不能修改和删除加锁项;
    • Gap Lock: 对索引项之间的 “间隙” 加锁,锁定记录的范围(对第一条记录前的间隙或最后一条将记录后的间隙加锁),不包含索引项本身。其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行。
    • Next-key Lock: 锁定索引项本身和索引范围。即 Record Lock 和 Gap Lock 的结合。可解决幻读问题。

虽然使用行级锁具有粒度小、并发高等特点,但是表级锁有时候也是非常有必要的:

  • 事务更新大表中的大部分数据直接使用表级锁效率更高。
  • 事务比较复杂,使用行级锁很可能引起死锁导致回滚。

2.封锁类型

(1)读写锁

  • 共享锁(S)
    共享锁(Share Lock,简记为S)又被称为读锁,其他用户可以并发读取数据,但任何事务都不能获取数据上的排他锁,直到已释放所有共享锁。

    共享锁(S锁)又称为读锁,若事务T对数据对象A加上S锁,则事务T只能读A;其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其它事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

  • 排它锁(X)
    排它锁(Exclusive Lock,简记为X)又被称为写锁,若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。在更新操作(INSERT、UPDATE 或 DELETE)过程中始终应用排它锁。

两者之间的区别:

  1. 共享锁(S锁):如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不 能加排他锁。获取共享锁的事务只能读数据,不能修改数据。
  2. 排它锁(X锁):如果事务T对数据A加上排它锁后,则其他事务不能再对A加任何类型的封锁。获取排它锁的事务既能读数据,又能修改数据。

(2)意向锁

当一个事务需要给自己需要的某个资源加锁的时候,如果遇到一个共享锁正锁定着自己需要的资源的时候,自己可以再加一个共享锁,不过不能加排它锁。但是,如果遇到自己需要锁定的资源已经被一个排它锁占有之后,则只能等待该锁定释放资源之后自己才能获取锁定资源并添加自己的锁定。

而意向锁的作用就是当一个事务在需要获取资源锁定的时候,如果遇到自己需要的资源已经被排它锁占用的时候,该事务可以需要锁定行的表上面添加一个合适的意向锁。如果自己需要一个共享锁,那么就在表上面添加一个意向共享锁。而如果自己需要的是某行(或者某些行)上面添加一个排它锁的话,则先在表上面添加一个意向排它锁。意向共享锁可以同时并存多个,但是意向排它锁同时只能有一个存在。

InnoDB另外的两个表级锁:

  • 意向共享锁(IS): 表示事务准备给数据行记入共享锁,事务在一个数据行加共享锁前必须先取得该表的IS锁。
  • 意向排他锁(IX): 表示事务准备给数据行加入排它锁,事务在一个数据行加排他锁前必须先取得该表的IX锁。

注意:

  1. 这里的意向锁是表级锁,表示的是一种意向,仅仅表示事务正在读或写某一行记录,在真正加行锁时才会判断是否冲突。意向锁是InnoDB自动加的,不需要用户干预。
  2. IX,IS是表级锁,不会和行级的X,S锁发生冲突,只会和表级的X,S发生冲突。

(3)InnoDB的锁机制兼容情况

数据库-MySQL_第10张图片

数据库-MySQL_第11张图片

当一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之如果请求不兼容,则该事物就等待锁释放。

3.死锁

(1)MVCC

MySQL InnoDB存储引擎,实现的是基于多版本并发控制协议—MVCC(Multi-Version Concurrency Control) MVCC最大的好处,相信也是耳熟能详:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,这也是为什么现阶段,几乎所有的RDBMS,都支持了MVCC。

(2)2PL(Two-Phase Locking)

传统RDBMS(关系数据库管理系统)加锁的一个原则,就是2PL (二阶段锁):Two-Phase Locking。相对而言,2PL比较容易理解,说的是锁操作分为两个阶段:加锁阶段与解锁阶段,并且保证加锁阶段与解锁阶段不相交。下面,仍旧以MySQL为例,来简单看看2PL在MySQL中的实现。

transaction mysql
begin 加锁阶段
insert into 加insert对应的锁
update table 加update对应的锁
delete from 加delete对应的锁
commit 解锁阶段
end 将insert、update、delete的锁全部解开

(3)死锁和避免死锁

MyISAM中是不会产生死锁的,因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么全部等待。而在InnoDB中,锁是逐步获得的,就造成了死锁的可能。(不过现在一般都是InnoDB引擎,关于MyISAM不做考虑)

​在InnoDB中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。

当两个事务同时执行,一个锁住了主键索引,在等待其他相关索引。另一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。

避免死锁,这里只介绍常见的三种:

  1. 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;
  2. 如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
  3. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;

七、大表优化

当MySQL单表记录数过⼤时,数据库的CRUD性能会明显下降,⼀些常⻅的优化措施如下:

  1. 限定数据的范围
    务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在⼀个月的范围内;

  2. 读/写分离
    经典的数据库拆分⽅案,主库负责写,从库负责读;

  3. 垂直分区
    根据数据库里面数据表的相关性进⾏拆分。 例如,用户表中既有用户的登录信息⼜有用户的基本信息,可以将用户表拆分成两个单独的表,甚⾄放到单独的库做分库。

    简单来说垂直拆分是指数据表列的拆分,把⼀张列⽐较多的表拆分为多张表。 如下图所示,这样来说⼤家应该就更容易理解了。
    数据库-MySQL_第12张图片
    垂直拆分的优点: 可以使得列数据变⼩,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。

    垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应⽤层进行Join来解决。此外,垂直分区会让事务变得更加复杂。

  4. 水平分区

    保持数据表结构不变,通过某种策略存储数据分⽚。这样每⼀⽚数据分散到不同的表或者库中,达到了分布式的⽬的。 水平拆分可以⽀撑非常大的数据量。

    水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把⼀张的表的数据拆成多张表来存放。举个例⼦:我们可以将⽤户信息表拆分成多个⽤户信息表,这样就可以避免单⼀表数据量过⼤对性能造成影响。

数据库-MySQL_第13张图片
水平拆分可以⽀持非常大的数据量。需要注意的⼀点是:分表仅仅是解决了单⼀表数据过大的问题,但
由于表的数据还是在同⼀台机器上,其实对于提升MySQL并发能力没有什么意义,所以水平拆分最好分
库 。

水平拆分能够支持非常大的数据量存储,应用端改造也少,但分片事务难以解决 ,跨节点Join性能较差,逻辑复杂。《Java⼯程师修炼之道》的作者推荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,⼀般的数据表在优化得当的情况下⽀撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分⽚架构,这样可以减少⼀次和中间件的网络I/O。

数据库分片的两种常见方案:

  • 客户端代理:分片逻辑在应⽤端,封装在jar包中,通过修改或者封装JDBC层来实现。 当当网的Sharding-JDBC 、阿⾥的TDDL是两种比较常用的实现。
  • 中间件代理:在应用和数据中间加了⼀个代理层。分片逻辑统⼀维护在中间件服务中。 我们现在谈的 MyCat 、360的Atlas、网易的DDB等等都是这种架构的实现。

八、数据库连接池

  1. 池化设计思想
    池化设计应该不是⼀个新名词。我们常见的如 java线程池、jdbc连接池、redis连接池 等就是这类设计的代表实现。这种设计会初始预设资源,解决的问题就是抵消每次获取资源的消耗,如创建线程的开销,获取远程连接的开销等。就好比你去⻝堂打饭,打饭的大妈会先把饭盛好几份放那⾥,你来了就直接拿着饭盒加菜即可,不用再临时又盛饭又打菜,效率就⾼了。除了初始化资源,池化设计还包括如下这些特征:池子的初始值、池子的活跃值、池子的最⼤值等,这些特征可以直接映射到java线程池和数据库连接池的成员属性中。

  2. 什么是数据库连接池
    数据库连接本质就是⼀个 socket 的连接。数据库服务端还要维护⼀些缓存和用户权限信息之类的 所以占用了⼀些内存。我们可以把数据库连接池是看做是维护的数据库连接的缓存,以便将来需要对数据库的请求时可以重用这些连接。

  3. 为什么需要数据库连接池
    为每个用户打开和维护数据库连接,尤其是对动态数据库驱动的网站应⽤程序的请求,既昂贵⼜浪费资源。在连接池中,创建连接后,将其放置在池中,并再次使用它,因此不必建⽴新的连接。如果使⽤了所有连接,则会建⽴⼀个新连接并将其添加到池中。 连接池还减少了⽤户必须等待建⽴与数据库的连接的时间。

九、分库分表之后,id主键如何处理?

因为要是分成多个表之后,每个表都是从 1 开始累加,这样是不对的,我们需要⼀个全局唯⼀的 id 来⽀持。

  • UUID: 不适合作为主键,因为太长了,并且无序不可读,查询效率低。比较适合用于生成唯一的名字的标志,比如文件的名字。
  • 数据库自增 id: 两台数据库分别设置不同步长,生成不重复ID的策略来实现⾼可用。这种方式生成的 id 有序,但是需要独立部署数据库实例,成本⾼,还会有性能瓶颈。
  • 利用 redis 生成 id: 性能比较好,灵活方便,不依赖于数据库。但是,引入了新的组件造成系统更加复杂,可用性降低,编码更加复杂,增加了系统成本。
  • Twitter 的 snowflake 算法: Github 地址:https://github.com/twitter-archive/snowflake
  • 美团的 Leaf 分布式 ID 生成系统: Leaf 是美团开源的分布式ID生成器,能保证全局唯⼀性、趋势递增、单调递增、信息安全,里面也提到了几种分布式⽅案的对比,但也需要依赖关系数据库、Zookeeper等中间件。感觉还不错。美团技术团队的⼀篇⽂章:https://tech.meituan.com/2017/04/21/mt-leaf.html 。

参考:吴一尘、JavaGuide面试突击

你可能感兴趣的:(面试)