⏰数据库面试宝典(更新中)

文章目录

  • 1 事务ACID
  • 2 隔离级别
  • 3 MYSQL的两种存储引擎
  • 4 索引
    • 4.1 四大分类
    • 4.2 索引的优缺点⭐
    • 4.3 聚集索引和非聚集索引
    • 4.4 底层实现
    • 4.5 索引的底层实现(B+树,为何不采用红黑树,B树)⭐
    • 4.6 使用索引
      • alter语句
      • create语句
    • 4.7 索引失效的sql语句
  • 5 分库分表,主写从读,读写分离
  • 6 数据库三范式
  • 7 关系型数据库Mysql和非关系型数据库Redis
    • 7.1 关系型
      • 优点
      • 缺点
    • 7.2 非关系型
      • 优点
      • 缺点
  • 8 有哪些锁,select时怎么加排它锁
  • 9 Mysql语法
    • 9.1 DQL:select、where、order by、连接查询、limit、union
    • 9.2 DML:insert into..values/set ..、update..set、delete..from..、truncate table..
    • 9.3 DDL : create、drop、alter
    • 9.4 TCL:commit、rollback
  • 10 六大约束
  • 11 Redis
    • 11.1 持久化
    • 11.2 redis中原生批命令(mset, mget)与Pipeline对比
    • 11.3 Redis中共有下面八种内存淘汰策略:
  • 12 Redis语法
    • 11.1 基础
      • select db、dbsize、keys *、flushdb、flushall、config get *
    • 11.2 string
        • set key value (设值)
        • get key(得值)
        • append key value(加值)
        • strlen key(键中值长)
        • incr key、decr key(加减一)
        • incrby key offset、decrby key offset(加减量)
        • getrange key startIndex endIndex(得索引的子字符串)
        • setrange key offsetIndex value(覆盖值)
        • setex key seconds value(生存时间)
        • setnx key value(没有设值)
        • mset key value [key value…]、mget key [key …](多设、得)
        • msetnx key value[key value…](没有多设)
    • list
        • lpush key value [value…]、rpush key value [value…](左、右设值)
        • lrange key startIndex endIndex(范围取值)
        • lpop key、rpop key(左、右弹值)
        • lindex key index(查询元素)
        • llen key(获取值的长度,个数)
        • lrem key count value(删除)
        • ltrim key startIndex endIndex(截取覆盖)
        • lset key index value(单设值)
        • linsert key before/after pivot value(pivot之前/后插入)
    • set
        • sadd key member [member…](添加)
        • smembers key(显示所有)
        • sismember key member(单值是否存在)
        • scard key(显示个数)
        • srem key member [member…](删除元素)
        • srandmember key[count](随机返回count个元素)
        • spop key[count](随机删除count个)
        • smove src dest member(member从scr移到dest)
        • sdiff key key [key…](作差)
        • sinter key key [key…](交集)
        • sunion key key [key…](并集)
    • hash
        • hset key field value [field value …](存键值对)
        • hget key field(拿值)
        • hmset key field value [field value…](设值覆盖)
        • hmget key field [field…](获取多值)
        • hgetall key(获取所有域和值)
        • hdel key field [field…](删除指定域)
        • hlen key(域个数)
        • hexists key field(域是否存在)
        • hkeys key(所有域列表)
        • hvals key(所有值列表)
        • hincrby key field int(域中增int)
        • hincrbyfloat key field float(域中增float)
        • hsetnx key field value(没有时初始化)
    • zset
        • zrange key startIndex endIndex [WITHSCORES](索引范围查询)
        • zrangebyscore key min max [WITHSCORES ] [LIMIT offset count](分数范围查询)
        • zrem key member [member…](删除)
        • zcard key(个数)
        • zcount key min max(分数内个数)
        • zrank key member(单值排名)
        • zscore key member(单值分数)
        • zrevrank key member(倒序排名)
        • zrevrange key startIndex endIndex [WITHSCORES](范围倒叙取值)
        • zrevrangebyscore key max min [WITHSCORES ] [LIMIT offset count](分数范围倒叙取值)
  • 13 JDBC
    • 什么是jdbc?
    • 使用步骤
    • 注册驱动的三种方式
    • Statement 和PreparedStatement的区别?
    • 为什么PreparedStatement能防止sql注入呢?
    • Java中如何进行事务的处理?

1 事务ACID

  • 原子性(Atomicity),要么执行,要么不执行。
  • 隔离性(Isolation),所有操作全部执行完以前其它会话不能看到过程。
  • 一致性(Consistency),事务前后,数据总额一致。
  • 持久性(Durability),一旦事务提交,对数据的改变就是永久的。

2 隔离级别

  • 脏读:事务B读取事务A还没有提交的数据,太脏了!
  • 不可重复读:一行被检索两次,并且该行中的值在不同的读取之间不同时
  • 幻读:当在事务处理过程中执行两个相同的查询,并且第二个查询返回的行集合与第一个查询不同时

这两个区别在于,不可重复读重点在一行,幻读的重点 ,返回的集合不一样

事务的隔离级别和InnoDB的隔离级别
⏰数据库面试宝典(更新中)_第1张图片

不可重复读重点在于update和delete,而幻读的重点在于insert。

innoDB可重复读怎么实现的?
详情

  • 数据的可见性规则就是基于数据的row trx_id和一致性视图的对比结果得到的。
  • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图

读已提交

在可重复读级别下,每一个语句执行前都会重新算出一个新的视图

如何解决幻读

在RR级别下,快照读是通过MVCC(多版本控制)和undo log来实现的,当前读是通过加record lock(记录锁)和gap lock(间隙锁)来实现的。在mysql中通过MVCC快照读next-key当前读两种模式解决幻读问题。

关于MVCC

MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control)

MVCC最大的好处:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,现阶段几乎所有的RDBMS,都支持了MVCC。

LBCC:Lock-Based Concurrency Control,基于锁的并发控制

MVCC:Multi-Version Concurrency Control

基于多版本的并发控制协议。纯粹基于锁的并发机制并发量低,MVCC是在基于锁的并发控制上的改进,主要是在读操作上提高了并发量。

快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写)

当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录

关于间隙锁

当我们用范围条件,而不是使用相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据进行加锁; 对于键值在条件范围内但并不存在的记录,叫做 “间隙(GAP)” , InnoDB也会对这个 “间隙” 加锁,这种锁机制就是所谓的 间隙锁 。

3 MYSQL的两种存储引擎

事务 索引 场景 外键
MyISAM 表级锁 不支持 不支持全~ 大量查询速度快,小型 不支持
InnoDB 行级锁 支持且安全 支持全文索引 支持事务,增删改更好 支持

4 索引

4.1 四大分类

索引的类型分类、区别、优缺点

  1. 单列索引
    1. 普通索引
    2. 唯一索引
    3. 主键索引
  2. 组合索引
  3. 全文索引

4.2 索引的优缺点⭐

  1. 索引最大的好处是提高查询速度
  2. 缺点是更新数据时效率低,因为要同时更新索引

对数据进行频繁查询进建立索引,如果要频繁更改数据不建议使用索引。

4.3 聚集索引和非聚集索引

索引 区别
聚集索引 数据按索引顺序存储,中子结点存储真实的物理数据
非聚集索引 存储指向真正数据行的指针

4.4 底层实现

  1. B+索引(MylSAM和InnoDB均是这种,也有区别)
    数据有序,范围查询
  2. hash索引
    hash索引,等值查询效率高不能排序,不能进行范围查询

4.5 索引的底层实现(B+树,为何不采用红黑树,B树)⭐

区别
红黑树 增加,删除,红黑树会进行频繁的调整,来保证红黑树的性质,浪费时间
B树也就是B-树 B树,查询性能不稳定,查询结果高度不致,每个结点保存指向真实数据的指针,相比B+树每一层每屋存储的元素更多,显得更高一点。
B+树 1.B+树相比较于另外两种树,显得更矮更宽,查询层次更浅 2.非叶子结点不存放数据,只存放索引,结点更小,所以能存放更多的查找关键字 3.数据都在根节点,每条查询的效率一致 4.只需遍历叶子结点就可以遍历整个树
哈希索引 1、哈希索引数据并不是按照索引列的值顺序存储的,故无法用于排序。2、哈希索引只支持等值比较查询,如:=、in()、<=>(安全比较运算符,用来做 NULL 值的关系运算),不支持任何范围查询

索引的原理

4.6 使用索引

alter语句

1. 添加PRIMARY KEY(主键索引)

     alter table `table_name` add primary key(`column`);

2.添加UNIQUE(唯一索引)

     alter table `table_name` add unique(`column`);

3.添加普通索引

     alter table `table_name` add index index_name(`column`);

4.添加全文索引

     alter table `table_name` add fulltext(`column`);

5.添加多列索引

     alter table `table_name` add index index_name(`column1`,`column2`,`column3`);

create语句

创建一个简单的索引,名为 "PersonIndex",在 Person 表的 LastName 列:
      CREATE INDEX PersonIndex ON Person (LastName) 

通过查询索引列来观察

4.7 索引失效的sql语句

1、如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)

   注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
   
2、如果是包含> 或者 < 的 想解决 其他索引不失效 就把其他条件放到前面

3、对于多列索引,不是使用的第一部分,则不会使用索引

4、like查询是以%开头,索引失效;以%结尾,索引有效

5、如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引

6、如果mysql估计使用全表扫描要比使用索引快,则不使用索引

5 分库分表,主写从读,读写分离

6 数据库三范式

级别 概念
1NF 属性不可分
2NF 非主键属性,完全依赖于主键属性
3NF 非主键属性无传递依赖

7 关系型数据库Mysql和非关系型数据库Redis

7.1 关系型

优点

  1. 容易理解:二维表结构是非常贴近逻辑世界一个概念,关系模型相对网状、层次等其他模型来说更容易理解
  2. 使用方便:通用的SQL语言使得操作关系型数据库非常方便
  3. 易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率;
  4. 支持SQL,可用于复杂的查询
  5. 支持事务

缺点

  1. 为了维护一致性所付出的巨大代价就是其读写性能比较
  2. 固定的表结构
  3. 不支持高并发读写需求;
  4. 不支持海量数据的高效率读写

7.2 非关系型

1、使用键值对存储数据;
2、分布式;

优点

  1. 无需经过sql层的解析,读写性能很高
  2. 基于键值对,数据没有耦合性易扩展
  3. 存储数据的格式:nosql的存储格式是key,value形式

缺点

不提供sql支持

8 有哪些锁,select时怎么加排它锁

概念
乐观锁 自己实现,通过版本号
悲观锁 共享锁,多个事务,只能读不能写,加 lock in share mode
排它锁 一个事务,只能写,for update
行锁 作用于数据行
表锁 作于用表

——————————————————————————————————————————————————————
详情
mysql 共享锁 (lock in share mode)

  • 允许其它事务也增加共享锁读取
  • 不允许其它事物增加排他锁 (for update)
  • 当事务同时增加共享锁时候,事务的更新必须等待先执行的事务 commit 后才行,如果同时并发太大可能很容易造成死锁

共享锁,事务都加,都能读。修改是惟一的,必须等待前一个事务 commit,才可

排他锁 (for update)

  • 事务之间不允许其它排他锁或共享锁读取,修改更不可能
  • 一次只能有一个排他锁执行 commit 之后,其它事务才可执行

不允许其它事务增加共享或排他锁读取。修改是惟一的,必须等待前一个事务 commit,才可

9 Mysql语法

详情

9.1 DQL:select、where、order by、连接查询、limit、union

(Data Query Language):数据查询语言

多表查询、连接查询

  • 内连接:( 等值连接、非等值连接、 自连接)
  • 外连接:( 左外连接 、右外连接 、全外连接)
  • 交叉连接
select 查询列表
from 表
join type join 表2
on 连接条件
where 筛选条件
group by 分组字段
having 分组后的筛选
order by 排序的字段】
limit 【offset,】size;
sql99:(sql92使用where仅支持内连接)
分类:
内连接(★):inner
外连接
	左外():left 【outer】
	右外():right 【outer】
	全外:full【outer】
交叉连接:cross 

左右外连接的例子

9.2 DML:insert into…values/set …、update…set、delete…from…、truncate table…

(Data Manipulate Language):数据操作语言

delete pk truncate Pk drop【面试题★】



/*
1.delete 可以加where 条件,truncate不能加
2.truncate删除,效率高一丢丢
3.假如要删除的表中有自增长列,
	如果用delete删除后,再插入数据,自增长列的值从断点开始,
	而truncate删除后,再插入数据,自增长列的值从1开始。
4.truncate删除没有返回值,delete删除有返回值
5.truncate删除不能回滚,delete删除可以回滚.
6. drop删除更彻底,表的内容和结构都删除,delete和truncate都保留表的结构
*/

9.3 DDL : create、drop、alter

(Data Define Languge):数据定义语言

create table 表名(
列名 列的类型【(长度) 约束】,
列名 列的类型【(长度) 约束】,
列名 列的类型【(长度) 约束】,

列名 列的类型【(长度) 约束】

)

alter table 表名 add|drop|modify|change column 列名 【列类型 约束】;

DROP TABLE IF EXISTS book_author;

9.4 TCL:commit、rollback

(Transaction Control Language):事务控制语言

10 六大约束

  • NOT NULL:非空,用于保证该字段的值不能为空 比如姓名、学号等
  • DEFAULT:默认,用于保证该字段有默认值 比如性别
  • PRIMARY KEY:主键,用于保证该字段的值具有唯一性,并且非空比如学号、员工编号等
  • UNIQUE:唯一,用于保证该字段的值具有唯一性,可以为空 比如座位号
  • CHECK:检查约束【mysql中不支持】 比如年龄、性别
  • FOREIGN KEY:外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值在从表添加外键约束,用于引用主表中某列的值比如学生表的专业编号,员工表的部门编号,员工表的工种编号

11 Redis

11.1 持久化

RDB和AOF详解

RDB(Redis Database) 持久化

  1. 三种机制:save、bgsave、自动化
  2. 将某个时间点的所有数据(快照)都存放到硬盘上。
  3. 可以将快照复制到其它服务器从而创建具有相同数据的服务器副本。
  4. 如果系统发生故障,将会丢失最后一次创建快照之后的数据。
  5. 如果数据量很大,保存快照的时间会很长。

AOF(Append Only File) 持久化
将写命令添加到 AOF 文件的末尾。
使用 AOF 持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。有以下同步选项:

选项 同步频率
always 每个写命令都同步
everysec 每秒同步一次
no 让操作系统来决定何时同步
  1. always 选项会严重减低服务器的性能;
  2. everysec 选项比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响;
  3. no 选项并不能给服务器性能带来多大的提升,而且也会增加系统崩溃时数据丢失的数量。
    随着服务器写请求的增多,AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗余写命令。

对比
⏰数据库面试宝典(更新中)_第2张图片

11.2 redis中原生批命令(mset, mget)与Pipeline对比

详情

  1. 原生批命令是原子性,pipeline是非原子性
    (原子性概念:一个事务是一个不可分割的最小工作单位,要么都成功要么都失败。原子操作是指你的一个业务逻辑必须是不可拆分的. 处理一件事情要么都成功,要么都失败,原子不可拆分)

  2. 原生批命令一命令多个key, 但pipeline支持多命令(存在事务),非原子性

  3. 原生批命令是服务端实现,而pipeline需要服务端与客户端共同完成

11.3 Redis中共有下面八种内存淘汰策略:

详情

  • volatile-lru:设置了过期时间的key使用LRU算法淘汰;
  • allkeys-lru:所有key使用LRU算法淘汰;
  • volatile-lfu:设置了过期时间的key使用LFU算法淘汰;
  • allkeys-lfu:所有key使用LFU算法淘汰;
  • volatile-random:设置了过期时间的key使用随机淘汰;
  • allkeys-random:所有key使用随机淘汰;
  • volatile-ttl:设置了过期时间的key根据过期时间淘汰,越早过期越早淘汰;
  • noeviction:默认策略,当内存达到设置的最大值时,所有申请内存的操作都会报错(如set,lpush等),只读操作如get命令可以正常执行;

12 Redis语法

详情语法
知识点

11.1 基础

select db、dbsize、keys *、flushdb、flushall、config get *

11.2 string

set key value (设值)
get key(得值)
append key value(加值)
strlen key(键中值长)
incr key、decr key(加减一)
incrby key offset、decrby key offset(加减量)
getrange key startIndex endIndex(得索引的子字符串)
setrange key offsetIndex value(覆盖值)
setex key seconds value(生存时间)
setnx key value(没有设值)
mset key value [key value…]、mget key [key …](多设、得)
msetnx key value[key value…](没有多设)

list

lpush key value [value…]、rpush key value [value…](左、右设值)
lrange key startIndex endIndex(范围取值)
lpop key、rpop key(左、右弹值)
lindex key index(查询元素)
llen key(获取值的长度,个数)
lrem key count value(删除)
ltrim key startIndex endIndex(截取覆盖)
lset key index value(单设值)
linsert key before/after pivot value(pivot之前/后插入)

set

sadd key member [member…](添加)
smembers key(显示所有)
sismember key member(单值是否存在)
scard key(显示个数)
srem key member [member…](删除元素)
srandmember key[count](随机返回count个元素)
spop key[count](随机删除count个)
smove src dest member(member从scr移到dest)
sdiff key key [key…](作差)
sinter key key [key…](交集)
sunion key key [key…](并集)

hash

hset key field value [field value …](存键值对)
hget key field(拿值)
hmset key field value [field value…](设值覆盖)
hmget key field [field…](获取多值)
hgetall key(获取所有域和值)
hdel key field [field…](删除指定域)
hlen key(域个数)
hexists key field(域是否存在)
hkeys key(所有域列表)
hvals key(所有值列表)
hincrby key field int(域中增int)
hincrbyfloat key field float(域中增float)
hsetnx key field value(没有时初始化)

zset

zrange key startIndex endIndex [WITHSCORES](索引范围查询)
zrangebyscore key min max [WITHSCORES ] [LIMIT offset count](分数范围查询)
zrem key member [member…](删除)
zcard key(个数)
zcount key min max(分数内个数)
zrank key member(单值排名)
zscore key member(单值分数)
zrevrank key member(倒序排名)
zrevrange key startIndex endIndex [WITHSCORES](范围倒叙取值)
zrevrangebyscore key max min [WITHSCORES ] [LIMIT offset count](分数范围倒叙取值)

13 JDBC

什么是jdbc?

  • JDBC的全称是Java DataBase Connection,也就是Java数据库连接,我们可以用它来操作关系型数据库。我们可以用它来连接数据库,创建和执行SQL查询,存储过程,并处理返回的结果。

使用步骤

1.注册驱动
 Class.forName("com.mysql.jdbc.Driver"); 

2.注册url,用户名密码,建立数据库连接
 Connection con = DriverManager.getConnection(url , username , password);
 
3.准备 SQL 语句,获取 SQL 语句发送器(Statement)
 静态sql:Statement stmt = con.createStatement();   
 动态sql:PreparedStatement pstmt = con.prepareStatement(sql);
 
4.发送并执行 SQL 语句, 得到结果集(ResultSet)
  ResultSet rs = stmt.executeQuery("SELECT * FROM ...");

5.处理结果集
  while(rs.next()) {    
         String name = rs.getString("name");    
         String pass = rs.getString(1); // 此方法比较高效    
       }
       
6.关闭资源(ResultSet, Statement, Connection)

注册驱动的三种方式

一、DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());

jdbc是使用桥的模式进行连接的。DriverManager就是管理数据库驱动的一个类,java.sql.Driver就是一个提供注册数据库驱动的接口,而com.microsoft.sqlserver.jdbc.SQLServerDriver()是java.sql.Driver接口的一个具体实现。

二、System.setProperty(“jdbc.drivers”, “com.microsoft.sqlserver.jdbc.SQLServerDriver”);

多个驱动使用冒号分隔开,在连接时JDBC会按顺序搜索,直到找到第一个能成功连接指定URL的驱动程序。

三、Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”);

第一种与第二种注册的方法看起来更加的直接与好理解。第三种方法是通过Class把类先装载到java的虚拟机中,并没有创建Driver类的实例。

Statement 和PreparedStatement的区别?

1.PreparedStatement 继承于 Statement
2.Statement 一般用于执行固定的没有参数的SQL
3.PreparedStatement 一般用于执行有?参数预编译的SQL语句。
4.PreparedStatement支持?操作参数,相对于Statement更加灵活。
5.PreparedStatement可以防止SQL注入,安全性高于Statement

为什么PreparedStatement能防止sql注入呢?

  • 因为sql语句是预编译的,而且语句中使用了占位符,规定了sql语句的结构。用户可以设置"?"的值,但是不能改变sql语句的结构,因此想在sql语句后面加上如“or 1=1”实现sql注入是行不通的。

  • 实际开发中,一般采用PreparedStatement访问数据库,它不仅能防止sql注入,还是预编译的(不用改变一次参数就要重新编译整个sql语句,效率高),此外,它执行查询语句得到的结果集离线的,连接关闭后,仍然可以访问结果集。

  • PreparedStatement的一个缺点是,我们不能直接用它来执行in条件语句;需要执行IN条件语句的话,下面有一些解决方案:

Java中如何进行事务的处理?

事务是作为单个逻辑工作单元执行的一系列操作,四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务。
Connection类中提供了4个事务处理方法:

  • setAutoCommit(Boolean autoCommit):设置是否自动提交事务,默认为自动提交,即为true,通过设置false禁止自动提交事务;
  • commit():提交事务;
  • rollback():回滚事务.
  • savepoint:保存点

注意:savepoint不会结束当前事务,普通提交和回滚都会结束当前事务的

你可能感兴趣的:(数据库,mysql,redis,数据库)