InnoDB存储引擎的锁的算法有三种:
- Record lock:单个行记录上的锁
- Gap lock:间隙锁,锁定一个范围,不包括记录本身
- Next-key lock:record+gap 锁定一个范围,包含记录本身
- innodb对于行的查询使用next-key lock
- Next-locking keying为了解决Phantom Problem幻读问题
- 当查询的索引含有唯一属性时,将next-key lock降级为record key
- Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
- 有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1
1. 限定数据的范围务必禁止不带任何限制数据范围条件的查询语句 。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
2. 读/写分离经典的数据库拆分方案,主库负责写,从库负责读;
3. 垂直分区根据数据库里面数据表的相关性进行拆分 。例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库 。
简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表 。如下图所示,这样来说大家应该就更容易理解了 。

文章插图
- 垂直拆分的优点: 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数 。此外,垂直分区可以简化表的结构,易于维护 。
- 垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决 。此外,垂直分区会让事务变得更加复杂;
水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放 。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响 。

文章插图
水平拆分可以支持非常大的数据量 。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库。
水平拆分能够 支持非常大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨节点Join性能较差,逻辑复杂 。《Java工程师修炼之道》的作者推荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的 。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O 。
下面补充一下数据库分片的两种常见方案:
- 客户端代理: 分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现 。当当网的 Sharding-JDBC 、阿里的TDDL是两种比较常用的实现 。
- 中间件代理: 在应用和数据中间加了一个代理层 。分片逻辑统一维护在中间件服务中 。我们现在谈的 Mycat 、360的Atlas、网易的DDB等等都是这种架构的实现 。
解释一下什么是池化设计思想 。什么是数据库连接池?为什么需要数据库连接池?池话设计应该不是一个新名词 。我们常见的如java线程池、jdbc连接池、redis连接池等就是这类设计的代表实现 。这种设计会初始预设资源,解决的问题就是抵消每次获取资源的消耗,如创建线程的开销,获取远程连接的开销等 。就好比你去食堂打饭,打饭的大妈会先把饭盛好几份放那里,你来了就直接拿着饭盒加菜即可,不用再临时又盛饭又打菜,效率就高了 。除了初始化资源,池化设计还包括如下这些特征:池子的初始值、池子的活跃值、池子的最大值等,这些特征可以直接映射到java线程池和数据库连接池的成员属性中 。——这篇文章对 池化设计思想 介绍的还不错,直接复制过来,避免重复造轮子了 。
推荐阅读
- 数据库分库分表最佳实践及说明
- 为什么数据库会丢失数据?
- html知识点实践经验总结
- mysql数据库备份及其恢复
- IT基础设施国产替代:依次为芯片、操作系统、中间件、数据库
- 在线yum安装 Linux中安装MySQL数据库下
- 玩转Docker:十分钟搞定MySQL的安装
- 三分钟学会如何找回mysql密码
- 学习前端需要掌握哪些知识点?
- mysql数据库13种常用函数方法总结
