(PDF资源:https://download.csdn.net/download/qq_36254699/11577742 )
1、SQL 基础
2、有一组合索引(A,B,C) ,会出现哪几种查询方式?tag:sql 语句
考察点: sql 语句
参考回答:
优: select * from test where a=10 and b>50
差: select * from test where b = 50
优: select * from test order by a
差: select * from test order by b
差: select * from test order by c
优: select * from test where a=10 order by a
优: select * from test where a=10 order by b
差: select * from test where a=10 order by c
优: select * from test where a>10 order by a
差: select * from test where a>10 order by b
差: select * from test where a>10 order by c
优: select * from test where a=10 and b=10 order by a
优: select * from test where a=10 and b=10 order by b
优: select * from test where a=10 and b=10 order by c
优: select * from test where a=10 and b=10 order by a
优: select * from test where a=10 and b>10 order by b
差: select * from test where a=10 and b>10 order by c
2、JDBC 基础
①数据库
1、数据库水平切分,垂直切分
考察点:数据库
参考回答:
垂直拆分就是要把表按模块划分到不同数据库表中 (当然原则还是不破坏第三范式) , 这种拆分在大型网站的演变过程中是很常见的。 当一个网站还在很小的时候, 只有小量的人来开发和维护,各模块和表都在一起,当网站不断丰富和壮大的时候,也会变成多个子系统来支撑,这时就有按模块和功能把表划分出来的需求。 其实,相对于垂直切分更进一步的是服务化改造, 说得简单就是要把原来强耦合的系统拆分成多个弱耦合的服务, 通过服务间的调用来满足业务需求看,因此表拆出来后要通过服务的形式暴露出去, 而不是直接调用不同模块的表, 淘宝在架构不断演变过程,最重要的一环就是服务化改造,把用户、交易、店铺、宝贝这些核心的概念抽取成独立的服务,也非常有利于进行局部的优化和治理,保障核心模块的稳定性。
垂直拆分:单表大数据量依然存在性能瓶颈
水平拆分, 上面谈到垂直切分只是把表按模块划分到不同数据库, 但没有解决单表大数据量的问题, 而水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。 例如像计费系统, 通过按时间来划分表就比较合适,因为系统都是处理某一时间段的数据。 而像 SaaS 应用,通过按用户维度来划分数据比较合适, 因为用户与用户之间的隔离的, 一般不存在处理多个用户数据的情况,简单的按 user_id 范围来水平切分。
通俗理解:水平拆分行,行数据拆分到不同表中, 垂直拆分列,表数据拆分到不同表中。
案例
以mysql为例,简单购物系统暂设涉及如下表:
(1)产品表(数据量10w,稳定)
(2)订单表(数据量200w,且有增长趋势)
(3)用户表 (数据量100w,且有增长趋势)
垂直拆分:
解决问题:表与表之间的io竞争
不解决问题:单表中数据量增长出现的压力
方案:
把产品表和用户表放到一个server上
订单表单独放到一个server上
水平拆分:
解决问题:单表中数据量增长出现的压力
不解决问题:表与表之间的io争夺
方案:
用户表通过性别拆分为男用户表和女用户表
订单表通过已完成和完成中拆分为已完成订单和未完成订单
产品表 未完成订单放一个server上
已完成订单表盒男用户表放一个server上
女用户表放一个server上(女的爱购物)
2、数据库索引介绍一下。介绍一下什么时候用 Innodb 什么时候用 MyISAM。
考察点:数据库
参考回答:
存储引擎
索引是对数据库表中一列或多列的值进行排序的一种结构, 使用索引可快速访问数据库表中的特定信息。 如果想按特定职员的姓来查找他或她, 则与在表中搜索所有的行相比, 索引有助于更快地获取信息。 索引的一个主要目的就是加快检索表中数据的方法, 亦即能协助信息搜索者尽快的找到符合限制条件的记录 ID 的辅助数据结构。
InnoDB 主要面向在线事务处理(OLTP)的应用。MyISAM 主要面向一些 OLAP 的应用。
3、数据库两种引擎
考察点:数据库存储引擎
参考回答:
InnoDB 是聚集索引,支持事务,支持行级锁;
MyISAM 是非聚集索引,不支持事务,只支持表级锁。
4、索引底层怎么实现的,什么时候会失效
考察点:数据库索引
参考回答:
B+树实现的。
没有遵循最左匹配原则一些关键字会导致索引失效,例如 or, != , not in,is null ,is not unll,like查询是以%开头
隐式转换会导致索引失效
对索引应用内部函数,索引字段进行了运算会失效
5、数据库的隔离级别
考察点:事务的隔离级别
参考回答:
未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。
提交读(Read Committed):只能读取到已经提交的数据。Oracle 等多数数据库默认都是该级别 (不重复读)。
可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB 默认级别。在 SQL 标准中,该隔离级别消除了不可重复读,但是还存在幻象读。
串行读(Serializable): 完全串行化的读, 每次读都需要获得表级共享锁, 读写相互都会阻塞。
6、数据库乐观锁和悲观锁
考察点:数据库
参考回答:
悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改, 所以每次在拿数据的时候都会上锁, 这样别人想拿这个数据就会 block 直到它拿到锁。 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。Java synchronized 就属于悲观锁的一种实现,每次线程要修改数据时都先获得锁,保证同一时刻只有一个线程能操作数据,其他线程则会被 block。
乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改, 所以不会上锁, 但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景,这样可以提高吞吐量。乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
乐观锁一般来说有以下 2 种方式:
使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将 version 字段的值一同读出,数据每更新一次,对此 version 值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的 version值进行比对, 如果数据库表当前版本号与第一次取出来的 version 值相等,则予以更新,否则认为是过期数据。
使用时间戳(timestamp)。乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的 table 中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的 version 类似, 也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则 OK,否则就是版本冲突。
7、数据库的三范式?
考察点:数据库
参考回答:
第一范式(1NF)
强调的是列的原子性,即列不能够再分成其他几列。
第二范式(2NF)
首先是 1NF, 另外包含两部分内容, 一是表必须有一个主键; 二是没有包含在主键中的列必
须完全依赖于主键,而不能只依赖于主键的一部分。在 1NF 基础上,任何非主属性不依赖于其它非主属性[在 2NF 基础上消除传递依赖]。
第三范式(3NF)
第三范式(3NF)是第二范式(2NF)的一个子集,即满足第三范式(3NF)必须满足第二范
式(2NF)。首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键
列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
8、讲一下数据库 ACID 的特性?
考察点:数据库
参考回答:
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。一致性指事务前后数据的完整性必须保持一致。
隔离性指多个用户并发访问数据库时, 一个用户的事务不能被其他用户的事务所干扰, 多个并发事务之间数据要相互隔离。
持久性是指一个事务一旦提交, 它对数据库中数据的改变就是永久性的, 即便数据库发生故障也不应该对其有任何影响。
9、mysql 主从复制?
考察点:数据库
参考回答:
MySQL 主从复制是其最重要的功能之一。主从复制是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器, 主服务器中的数据自动复制到从服务器之中。 对于多级复制,数据库服务器即可充当主机,也可充当从机。MySQL 主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器的二进制日志自动执行更新。
MySQL 主从复制的两种情况:同步复制和异步复制,实际复制架构中大部分为异步复制。
复制的基本过程如下:
Slave 上面的 IO 进程连接上 Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容。
Master 接收到来自 Slave 的 IO 进程的请求后,负责复制的 IO 进程会根据请求信息读取日志指定位置之后的日志信息, 返回给 Slave 的 IO 进程。 返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到 Master 端的 bin-log 文件的名称以及 bin-log 的位置。Slave 的 IO 进程接收到信息后,将接收到的日志内容依次添加到 Slave 端的 relay-log 文件的最末端,并将读取到的 Master 端的 bin-log 的文件名和位置记录到 master-info 文件中,以便在下一次读取的时候能够清楚的告诉 Master“我需要从某个 bin-log 的哪个位置开始往后的日志内容,请发给我”。Slave 的 Sql 进程检测到 relay-log 中新增加了内容后, 会马上解析 relay-log 的内容成为在 Master 端真实执行时候的那些可执行的内容,并在自身执行。
10、leftjoin 和 rightjoin 的区别?
考察点:表结构
参考回答:
left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
比如:
表 A 记录如下:
aID aNum
1 a20050111
2 a20050112
3 a20050113
4 a20050114
5 a20050115
表 B 记录如下:
bID bName
1 2006032401
2 2006032402
3 2006032403
4 2006032404
8 2006032408
left join 是以 A 表的记录为基础的,A 可以看成左表,B 可以看成右表,left join 是以左表为准的.
换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为:A.aID = B.bID).
B 表记录不足的地方均为 NULL.
11、数据库优化方法
考察点:数据库
参考回答:
(1)选取最适用的字段属性
MySQL 可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。
例如,在定义邮政编码这个字段时,如果将其设置为 CHAR(255),显然给数据库增加了不必要的空间,甚至使用 VARCHAR 这种类型也是多余的,因为 CHAR(6)就可以很好的完成任务了。同样的,如果可以的话,我们应该使用 MEDIUMINT 而不是 BIGIN 来定义整型字段。
另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为 NOTNULL,这样在将来执行查询的时候,数据库不用去比较 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开始之前的状态。
12、谈一下你对继承映射的理解。
考察点:映射
参考回答:
继承关系的映射策略有三种:
① 每个继承结构一张表(table per class hierarchy),不管多少个子类都用一张表。
② 每个子类一张表(table per subclass),公共信息放一张表,特有信息放单独的表。
③ 每个具体类一张表(table per concrete class),有多少个子类就有多少张表。
第一种方式属于单表策略, 其优点在于查询子类对象的时候无需表连接, 查询速度快, 适合多态查询;缺点是可能导致表很大。后两种方式属于多表策略,其优点在于数据存储紧凑,其缺点是需要进行连接查询,不适合多态查询。
②数据库连接池
1、说出数据连接池的工作机制是什么?
考察点:连接池
参考回答:
J2EE 服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。客户端程序需要连接时, 池驱动程序会返回一个未使用的池连接并将其表记为忙。 如果当前没有空闲连接, 池驱动程序就新建一定数量的连接,新建连接的数量由配置参数决定。当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。
③事物管理,批处理
1、事务的 ACID 是指什么?
考察点:数据库
参考回答:
关于事务, 在面试中被问到的概率是很高的, 可以问的问题也是很多的。 首先需要知道的是,只有存在并发数据访问时才需要事务。 当多个事务访问同一数据时,可能会存在 5 类问题, 包括3 类数据读取问题(脏读、不可重复读和幻读)和 2 类数据更新问题(第 1 类丢失更新和第 2 类丢失更新)。
2、JDBC 中如何进行事务处理?
考察点:数据库
参考回答:
Connection 提供了事务处理的方法,通过调用 setAutoCommit(false)可以设置手动提交事务; 当事务完成后用 commit()显式提交事务; 如果在事务处理过程中发生异常则通过 rollback()进行事务回滚。除此之外,从 JDBC 3.0 中还引入了 **Savepoint(保存点)**的概念,允许通过代码设置保存点并让事务回滚到指定的保存点。
3、JDBC 进阶
1、JDBC 的反射,反射都是什么?
考察点: jdbc
参考回答:
通过反射 com.mysql.jdbc.Driver 类, 实例化该类的时候会执行该类内部的静态代码块, 该代码块会在 Java 实现的 DriverManager 类中注册自己,DriverManager 管理所有已经注册的驱动类,当调用 DriverManager.geConnection 方法时会遍历这些驱动类,并尝试去连接数据库,只要有一个能连接成功,就返回 Connection 对象,否则则报异常。
2、Jdo 是什么?
考察点: JAVA API
参考回答:
**JDO 是 Java 对象持久化的新的规范,**为 java data object 的简称,也是一个用于存取某种数据仓库中的对象的标准化 API。JDO 提供了透明的对象存储,因此对开发人员来说,存储数据对象完全不需要额外的代码(如 JDBC API 的使用)。这些繁琐的例行工作已经转移到 JDO 产品提供商身上,使开发人员解脱出来,从而集中时间和精力在业务逻辑上。另外,JDO 很灵活,因
为它可以在任何数据底层上运行。JDBC 只是面向关系数据库(RDBMS)JDO 更通用,提供到任何数据底层的存储功能,比如关系数据库、文件、XML 以及对象数据库(ODBMS)等等,使得应用可移植性更强。
3、Statement 和 PreparedStatement 有什么区别?哪个性能更好?
考察点: Statement
参考回答:
与 Statement 相比,①PreparedStatement 接口代表预编译的语句,它主要的优势在于可以减少 SQL 的编译错误并增加 SQL 的安全性 (减少 SQL 注射攻击的可能性) ; ②PreparedStatement中的 SQL 语句是可以带参数的, 避免了用字符串连接拼接 SQL 语句的麻烦和不安全; ③当批量处理 SQL 或频繁执行相同的查询时,PreparedStatement 有明显的性能上的优势,由于数据库可以将编译优化后的 SQL 语句缓存起来, 下次执行相同结构的语句时就会很快 (不用再次编译和生成执行计划)。为了提供对存储过程的调用,JDBC API 中还提供了 CallableStatement 接口。存储过程(Stored Procedure)是数据库中一组为了完成特定功能的 SQL 语句的集合,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。虽然调用存储过程会在网络开销、 安全性、 性能上获得很多好处, 但是存在如果底层数据库发生迁移时就会有很多麻烦,因为每种数据库的存储过程在书写上存在不少的差别。
4、 使用 JDBC 操作数据库时, 如何提升读取数据的性能?如何提升更新数据的性
能?
考察点: JDBC 优化
参考回答:
要提升读取数据的性能,可以指定通过结果集(ResultSet)对象的 setFetchSize()方法指定每次抓取的记录数(典型的空间换时间策略);要提升更新数据的性能可以使用PreparedStatement 语句构建批处理,将若干 SQL 语句置于一个批处理中执行。