Java面试题系列(三)——数据库

1. 数据库设计准则

  • 第一范式:列的原子性,列不可拆分。
  • 第二范式:1)表必须有一个主键;2)没有包含在主键的列必须完全依赖于主键,而不是部分依赖
  • 第三范式:非主键列必须直接依赖于主键,不能存在传递依赖。

2. MySQL数据库引擎

https://www.jianshu.com/p/4bb9f78b4f6d
InnoDB主要面向在线事务处理(OLTP)的应用。MyISAM主要面向一些联机分析处理OLAP的应用。

  • InnoDB存储引擎:InnoDB是默认的MySQL引擎,支持事务安全表(ACID),支持行锁定和外键,默认创建的是B+tree索引,提供了具有提交、回滚和崩溃恢复能力的事物安全(ACID兼容)存储引擎。
  • MyISAM存储引擎:拥有较高的插入、查询速度,但不支持事务。在 MyISAM 中,B+ 树索引的叶子节点并不存储数据,而是存储数据的文件地址。
  • MEMORY存储引擎:MEMORY存储引擎将表中的数据存储到内存中,为查询和引用其他表数据提供快速访问。也可以为B+tree索引(或者Hash索引)
  • Archive存储引擎:基本上用于数据归档;它的压缩比非常的高,它不支持事务,其设计目标只是提供高速的插入和压缩功能。


    image.png

3. 为什么MyISAM查询比Innodb快?

INNODB在做SELECT的时候,要维护的东西比MYISAM引擎多很多:

  • INNODB要缓存数据块,MYISAM只缓存索引块,这中间还有换进换出的减少;
  • INNODB寻址要先映射到块,再到行;MYISAM记录的直接是文件的OFFSET,定位比INNODB要快(注:MYISAM 更新频率低,所以索引变更少,所以允许每次更新,即更新主索引,也更新副索引,更新offset)
  • INNODB还需要维护MVCC一致;虽然你的场景没有,但他还是需要去检查和维护,MYISAM 表锁牺牲了写性能,提高了读性能。

4. 数据库保证并发性(MVCC)

https://www.jianshu.com/p/8845ddca3b23
  MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。

  • MVCC带来的好处是?
    多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为数据库解决以下问题
    • 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能
    • 同时还可以解决脏读,不可重复读,幻读等事务隔离问题,但不能解决更新丢失问题
  • 小结
    总之,MVCC就是为了解决数据库仅仅采用悲观锁这样性能不佳的形式去解决读-写冲突问题,所以在数据库中我们可以形成两个组合:
    • MVCC + 悲观锁:MVCC解决读-写冲突,悲观锁解决写-写冲突
    • MVCC + 乐观锁:MVCC解决读-写冲突,乐观锁解决写-写冲突
      这种组合的方式就可以最大程度的提高数据库并发性能,并解决读写冲突,和写写冲突导致的问题

5. mysql的主从复制

  MySQL主从复制是其最重要的功能之一。主从复制是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中。对于多级复制,数据库服务器即可充当主机,也可充当从机。MySQL主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器的二进制日志自动执行更新。MySQL主从复制的两种情况:同步复制和异步复制,实际复制架构中大部分为异步复制。

6. 索引

  • 定义:在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构。遵循最左匹配原则,不然索引失效
  • (https://blog.csdn.net/qq_42253147/article/details/90730573)
  • 目的:
    1)数据库索引其实就是为了使查询数据效率快:通过不断的缩小想要获得数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是我们总是通过同一种查找方式来锁定数据。
    2)创建唯一性索引,保证数据库表中每一行数据的唯一性;
    3)加速表和表之间的连接;
  • 缺点:
    1)索引需要占用数据表以外的物理存储空间
    2)创建索引和维护索引要花费一定的时间
    3)当对表进行更新操作时,索引需要被重建,这样降低了数据的维护速度。
  • 最左匹配原则:以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配,例如abc使用索引的为a、ab、abc、ac
  • 类型:
    1)聚集索引(主键索引):以主键作为 B+ 树索引的键值而构建的 B+ 树索引,一个表只能包含一个聚集索引。在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。在数据库里,所有行数都会按照主键索引进行排序。表在磁盘上的存储结构就由整齐排列的结构转变成了树状结构,类似整个表就变成了一个索引,也就是所谓的「聚集索引」。
    2)非聚集索引:以主键以外的列值作为键值构建的 B+ 树索引,通过聚集索引可以查到需要查找的数据,而通过非聚集索引可以查到记录对应的主键值 ,再使用主键的值通过聚集索引查找到需要的数据。非聚集索引与聚集索引的区别在于非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。
    3)联合索引:就是多个字段组成的索引,称为联合索引。联合索引(a,b,c),用到索引的有a,ab,abc,ac 因为优化器会自动调整and前后的顺序,所以ba,cba,bca,ca都会用到索引,其他的都不会用到该索引。ac这一组仅仅是a用到索引。
  • 底层实现方式:B+树
    聚簇索引:索引页+数据页组成的B+树,是 MySQL 基于主键索引结构创建的
  • 索引在 MySQL 数据库中分四类:B+ 树索引、Hash 索引、全文索引、R-Tree索引(GIS数据)
    哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可立刻定位到相应的位置,速度非常快。

7. Mysql索引分类

  • 从逻辑角度:主键索引、唯一索引、普通索引(单列)、联合索引(多列)、空间索引
  • 从数据结构角度:B+ 树索引、Hash 索引、全文索引、R-Tree索引(GIS数据)
  • 从物理存储角度:聚集索引和非聚集索引

8. Hash索引和B+树索引的区别

  • 如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;当然了,这个前提是,键值都是唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;
  • 如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;
  • 同理,哈希索引也没办法利用索引完成排序,以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);
  • 哈希索引也不支持多列联合索引的最左匹配规则;
  • B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题。

9. 回表和覆盖索引

  • 回表定义:数据库根据索引(非主键)找到了指定的记录所在行后,还需要根据主键再次到数据块里获取数据。
  • 如何避免回表:将需要的字段放在索引中去。查询的时候就能避免回表。
  • 覆盖索引定义:指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O、提高效率。 如表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。当我们通过SQL语句:select key2 from covering_index_sample where key1 = ‘keytest’;的时候,就可以通过覆盖索引查询,无需回表。

10. 索引创建原则

  • 经常被用来过滤记录的字段
    1)primary key 字段,系统自动创建主键的索引;
    2)unique key 字段,系统自动创建对应的索引;
    3)foreign key 约束所定义的作为外键的字段;
    4)在查询中用来连接表的字段;
    5)经常用来作为排序(order by 的字段)基准的字段;
  • 内容变动多的字段谨慎创建,索引维护消耗性能
  • 索引会额外占用磁盘空间,不是越多越好
  • 一个表中只能有一个主键,可以有多个unique key
  • 避免选择大型数据类型的列作为索引
  • 应该避免对具有较少值的字段进行索引

11. 索引失效的情况

  • 有or必全有索引:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
  • 复合索引未用左列字段;
  • like以%开头;
  • 需要类型转换;
  • where中索引列有运算;
  • where中索引列使用了函数;
  • 如果mysql觉得全表扫描更快时(数据少);

12. B+树

  • MySQL 中最常用的索引的数据结构是 B+ 树,有以下特点:
    1)在 B+ 树中,所有数据记录节点都是按照键值的大小存放在同一层的叶子节点上,而非叶子结点只存储key的信息,这样可以大大减少每个节点的存储的key的数量,降低B+ 树的高度
    2)B+ 树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。
  • B+树和B树的区别:
    1)B+ 树的层级更少:相较于 B 树 B+ 每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快
    2)B+ 树查询速度更稳定:B+ 所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
    3)B+ 树天然具备排序功能:B+ 树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
    4)B+ 树全节点遍历更快:B+ 树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像 B 树一样需要对每一层进行遍历,这有利于数据库做全表扫描。


    image.png

13. 为什么用B+树而不是B树?

  • http://www.liuzk.com/410.html
  • 在B树中,你可以将键和值存放在内部节点和叶子节点,但在B+树中,内部节点都是键,没有值。
  • B+树的叶子节点有一条链相连,而B树的叶子节点各自独立。
  • B树和B+树区别:
    • 关键字数量不同:B+树分支结点M个关键字,叶子节点也有M个;B树分支结点则存在 k-1 个关键码
    • 数据存储位置不同:B+树数据存储在叶子结点上,而且数据是按照顺序排列的;B树存储在每个结点上;
    • 查询不同:B+树是从根节点到叶子节点的路径;B树是只需要找到数据就可以
    • 分支节点存储信息不同:B+树存索引信息;B树存的是数据关键字

14. B树、B-树、B+树、B*树

https://www.jianshu.com/p/92d15df75027

  • B树:每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
  • B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整棵树中出现,且只出现一次,非叶子结点可以命中;
  • B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
  • B*树: 在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3;

15. 乐观锁和悲观锁

  • 悲观锁:假定会发生并发冲突,屏蔽一切违反数据完整性的操作。每次取数据的时候都会上锁,想要拿数据就会block直到拿到锁。适用于写多读少的场景。如synchorized就是悲观锁的一种实现,适用于写多读少场景。
    • 行锁、表锁、页锁
  • 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。只在提交更新时判断别人有没有更新数据。适用于读多写少的场景。乐观锁的实现方式一般包括使用版本号和时间戳。如CAS,实现方式:
    1)数据版本:需要乐观锁控制的table中增加一个字段version
    2)时间戳:需要乐观锁控制的table中增加一个字段timestamp

16. 事务

  • 定义:访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。
  • 事务的ACID特性:
    1)原子性Atomicity:一个事务时不可分割的单位,事务中的操作要么都做,要么都不做。
    2)一致性Consistency:事务操作前后数据库完整性一致。
    3)隔离性Isolation:一个事务的执行不能被其他事务干扰
    4)永久性Durability:事务完成后对数据库的改变是永久性的。
  • 事务隔离级别


    image.png

1)未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。
2)已提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)。
3)可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读,即后一次查询看到了前一次查询没有看到的行。
4)串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

17. 事务的实现原理

  • 原子性:使用 undo log ,从而达到回滚
  • 持久性:使用 redo log,从而达到故障后恢复
  • 隔离性:使用锁以及MVCC,运用的优化思想有读写分离,读读并行,读写并行
  • 一致性:通过回滚,以及恢复,和在并发环境下的隔离做到一致性。

18. 脏读、不可重复读、幻读

  • 脏读:脏读又称无效数据读出(读出了脏数据)。一个事务读取另外一个事务还没有提交的数据叫脏读。
  • 不可重复读:不可重复读是指在同一个事务内,两次相同的查询返回了不同的结果。例如:事务T1会读取两次数据,在第一次读取某一条数据后,事务T2修改了该数据并提交了事务,T1此时再次读取该数据,两次读取便得到了不同的结果。不可重复读的重点是修改
  • 幻读:幻觉读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。幻读的重点在于新增或者删除

19. 为什么实际开发中使用已提交读更多?

  • 在可重复读隔离级别下,存在间隙锁,导致出现死锁的几率比已提交读大的多!
  • 在可重复读隔离级别下,条件列未命中索引会锁表!而在已提交读隔离级别下,只锁行
  • 在已提交读隔离级别下,半一致性读(semi-consistent)特性增加了update操作的并发性!

20. 间隙锁(Gap)

  • 定义:一个在索引记录之间的间隙上的锁。
  • 作用:保证某个间隙内的数据在锁定情况下不会发生任何变化。比如mysql默认隔离级别下的可重复读(RR)。
  • 对主键索引或者唯一索引会使用间隙锁吗?
    • 如果where条件全部命中,则不会使用gap锁,只会加记录锁
    • 如果where条件部分命中或全不命中,则会加gap锁
  • Gap锁会用在非唯一索引或不走索引的当前读中

21. 快照读和当前读

  • 快照读:读取的是记录数据的可见版本(可能是过期的数据),不用加锁,第一次执行事务中select时生成快照。
  • 当前读:读取的是记录数据的最新版本,并且当前读返回的记录都会加上锁,保证其他事务不会再并发的修改这条记录,当你执行update、insert、delete这几个操作的时候默认会执行当前读。

22. 对象属性与数据库字段不一致

1)Sql语句起别名
2)Mapper.xml中的resultMap自定义映射,
3)配置文件中开启驼峰命名规则(对象属性为驼峰命名)

23. 数据库优化方法

(1)选取最适用的字段属性
  MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了。同样的,如果可以的话,我们应该使用MEDIUMINT而不是BIGIN来定义整型字段。另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为NOT NULL,这样在将来执行查询的时候,数据库不用去比较NULL值。
  对于某些文本字段,例如“省份”或者“性别”,我们可以将它们定义为ENUM类型。因为在MySQL中,ENUM类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,我们又可以提高数据库的性能。
(2)使用连接(JOIN)来代替子查询(Sub-Queries)
  MySQL从4.1开始支持SQL的子查询。这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。例如,我们要将客户基本信息表中没有任何订单的客户删除掉,就可以利用子查询先从销售信息表中将所有发出订单的客户ID取出来,然后将结果传递给主查询
(3)使用联合(UNION)来代替手动创建的临时表
  MySQL从4.0的版本开始支持union查询,它可以把需要使用临时表的两条或更多的select查询合并的一个查询中。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用union来创建查询的时候,我们只需要用UNION作为关键字把多个select语句连接起来就可以了,要注意的是所有select语句中的字段数目要想同。
(4)事务
  尽管我们可以使用子查询(Sub-Queries)、连接(JOIN)和联合(UNION)来创建各种各样的查询,但不是所有的数据库操作都可以只用一条或少数几条SQL语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是在这种情况下,当这个语句块中的某一条语句运行出错的时候,整个语句块的操作就会变得不确定起来。设想一下,要把某个数据同时插入两个相关联的表中,可能会出现这样的情况:第一个表中成功更新后,数据库突然出现意外状况,造成第二个表中的操作没有完成,这样,就会造成数据的不完整,甚至会破坏数据库中的数据。要避免这种情况,就应该使用事务,它的作用是:要么语句块中每条语句都操作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事物以BEGIN关键字开始,COMMIT关键字结束。在这之间的一条SQL操作失败,那么,ROLLBACK命令就可以把数据库恢复到BEGIN开始之前的状态。

24. 慢查询优化方式

https://blog.csdn.net/qq_35571554/article/details/82800463

  • 数据库中设置SQL慢查询

    • 方式一:修改配置文件 在 my.ini 增加几行: 主要是慢查询的定义时间(超过2秒就是慢查询),以及慢查询log日志记录( slow_query_log)
    • 方法二:通过MySQL数据库开启慢查询:
  • 分析慢查询日志
      直接分析mysql慢查询日志 ,利用explain关键字可以模拟优化器执行SQL查询语句,来分析sql慢查询语句,具体记录了:是哪条语句导致慢查询(sql_text),该慢查询语句的查询时间(query_time),锁表时间(Lock_time),以及扫描过的行数(rows_examined)等信息。


    image.png
  • 常见的慢查询优化

    • 索引没起作用的情况
    • 优化数据库结构
      • 将字段很多的表分解成多个表
      • 增加中间表
    • 分解关联查询
    • 优化LIMIT分页
      • 筛选字段加索引
      • 先查出主键ID
      • 关延迟联
      • 建立复合索引
    • 分析具体的SQL语句
  • 具体步骤

    • 第一步:根据慢日志定位慢查询SQL
      • 首先检查SQL中是否使用函数,隐式类型转换(字符串转数字),隐式函数或者传入的值超过索引长度
      • SQL中字段的字符集是否一致
      • 如果使用count计数,尽量使用count(*)或者count(1),count(字段)会涉及到回表操作,count(id)会全表扫描,并且count(字段)和count(id)都需要判空操作,也可以按照具体的业务选择MyISAM引擎,直接取值
      • 查看当前语句的状态,是否是在等MDL锁,数据页flush,其他线程占用了行锁
      • 如果是热点数据,需要控制访问资源的并发事务量,可以将一行数据改成逻辑上的多行数据
    • 第二步:使用explain等工具分析 SQL
      • 查看SQL是否按照理想的状态检索最少的数据行,如果没有则查看是否走了指定索引
      • 判断优化器是否选错索引,可以通过强行选择索引或者重新统计索引信息
    • 第三步:修改SQL或者尽量让SQL走索引
      • 在数据库空闲的时候,定期进行索引统计,防止优化器选错索引,造成索引失效
      • 优化手段:聚簇索引,覆盖索引,索引下推优化,联合索引
      • 字符串索引:前缀索引,倒序存储,hash索引
      • 如果需要业务字段做索引,必须确保是唯一索引,符合K-V结构,不需要考虑其他索引叶子节点的大小
      • 尽量使用自增主键索引,每次插入新的数据都是追加操作,可以防止数据页黑洞出现,保证索引的紧凑,不涉及挪动其他数据,也不会触动叶子节点的页分裂
      • 主键索引的长度不可以过长,造成其他索引树的叶子节点较大
      • 在建立联合索引的时候,如果可以通过顺序少建立一个索引,则调整顺序,同时需要考虑空间占用
      • 数据写多读少的时候选择普通索引,利用change buffer可以提高效率,合理设置change buffer大小,防止频繁merge
      • 如果sql语句出现锁操作,尽量让锁操作最后执行,防止影响其他SQL的执行
      • 如果使用长连接,在进行较大查询之后,需要重置链接,防止占用较大内存,造成数据库异常重启
      • 不要删除索引,删除索引可能会造成页分裂,导致数据页出现黑洞
      • 使用order by查询的时候,如果单行数据过大,会造成回表操作,可以使用联合索引,让字段本身有序

25. 数据库水平切分与垂直切分

  垂直拆分就是要把表按模块划分到不同数据库表中(当然原则还是不破坏第三范式),这种拆分在大型网站的演变过程中是很常见的。当一个网站还在很小的时候,只有小量的人来开发和维护,各模块和表都在一起,当网站不断丰富和壮大的时候,也会变成多个子系统来支撑,这时就有按模块和功能把表划分出来的需求。其实,相对于垂直切分更进一步的是服务化改造,说得简单就是要把原来强耦合的系统拆分成多个弱耦合的服务,通过服务间的调用来满足业务需求看,因此表拆出来后要通过服务的形式暴露出去,而不是直接调用不同模块的表,淘宝在架构不断演变过程,最重要的一环就是服务化改造,把用户、交易、店铺、宝贝这些核心的概念抽取成独立的服务,也非常有利于进行局部的优化和治理,保障核心模块的稳定性。垂直拆分:单表大数据量依然存在性能瓶颈
  水平拆分,上面谈到垂直切分只是把表按模块划分到不同数据库,但没有解决单表大数据量的问题,而水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。例如像计费系统,通过按时间来划分表就比较合适,因为系统都是处理某一时间段的数据。而像SaaS应用,通过按用户维度来划分数据比较合适,因为用户与用户之间的隔离的,一般不存在处理多个用户数据的情况,简单的按user_id范围来水平切分。
  通俗理解:水平拆分行,行数据拆分到不同表中,垂直拆分列,表数据拆分到不同表中。

26. Statement 和 PreparedStatement 的区别

与Statement相比,PreparedStatement接口代表预编译的语句,它主要的优势在于:

  • 可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);
  • PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;
  • 当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)。

27. MyBatis 中 #{} 和 ${} 的区别

  • ${} 拼接符,#{} 占位符
  • ${}:动态解析 -> 编译 -> 执行;#{}:动态解析 -> 预编译 -> 执行,#{} 能防止sql 注入
  • 变量替换后,#{} 对应的变量自动加上单引号 '';变量替换后,${} 对应的变量不会加上单引号 ''
  • 表名作参数时,必须用 ${}。如:
select * from ${tableName}
  • order by 时,必须用 ${}。如:
select * from t_user order by ${columnName}

28. select *缺点

  • 返回多余的列给客户端,造成网络压力过大,增加服务器压力。
  • 如果涉及多表查询,可能会使相同表名的列返回数据混乱。
  • select * from table where [列] …当我们对[列]添加索引后,返回数据时,都需要再次进行RID查找,获取列的全部信息,使索引效果减弱。
  • 由于需返回全部列,数据库返回数据时,都会从系统基础表中获取相关列信息,增加服务器系统表查询次数。

29. Mysql窗口函数

  • 专用窗口函数:rank(),dense_rank(),row_number()


    image.png
  • 汇总函数:max(),min(),count(),sum(),avg()

30. left join 、right join 、inner join之间的区别

  • left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
  • right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
  • inner join(等值连接) 只返回两个表中联结字段相等的行

31. 共享锁和独占锁的使用

  • 共享锁:在查询语句后面加上lock in share mode
  • 独占锁:for update

你可能感兴趣的:(Java面试题系列(三)——数据库)