常见问题练习

20210718&25练习

编辑时间:2021/07/28

读完本节:大概花费60分钟,共5182词

文章目录

2021718
1.比较Innodb和Myisam引擎的区别
  1. InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
  2. MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用
  3. InnoDB支持外键,MyISAM不支持
  4. MyISAM是默认引擎,InnoDB需要指定
  5. InnoDB不支持FULLTEXT类型的索引
  6. InnoDB中不保存表的行数,如select count( ) from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count( )语句包含where条件时MyISAM也需要扫描整个表
  7. 对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引
  8. 清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表
  9. InnoDB支持行锁(某些情况下还是锁整表)
  10. 存储限制两者都存在存储限制,Innodb的上限是64TB
  11. 对外键的支持情况:Innodb支持外键,MyISAM不支持外键
2.描述MVCC
  1. MVCC(Multiversion Concurrency Control) :多版本并发控制
    原理:

    ​ 通过数据行的多个版本管理来实现数据库的并发控制,简单来说就是保存数据的历史版本。可以通过比较版本号决定数据是否显示出来。读取数据的时候不需要加锁可以保证事务的隔离效果。

    流程:

    1. 获取事务自己的版本号-事务ID
    2. 获取Read View
    3. 查询的得到数据,然后Read View中的事务版本号进行比较。
    4. 如果不符合ReadView规则,就需要UndoLog中的历史快照。
    5. 返回符合规则的数据

    MVCC 可以解决的问题:

    1. 通过 MVCC 可以让读写互相不阻塞,读不阻塞写,写不阻塞读,这样可以提升数据并发处理能力。
    2. 降低了死锁的概率,这个是因为 MVCC 采用了乐观锁的方式,读取数据时,不需要加锁,写操作,只需要锁定必要的行。
    3. 解决了一致性读的问题,当我们朝向某个数据库在时间点的快照是,只能看到这个时间点之前事务提交更新的结果,不能看到时间点之后事务提交的更新结果。
3.事务的四大特性是什么?请分别描述
  1. 原子性Atomicity:事务中包含的所有操作要么都做,要么都不做,保证数据库是一致的。
  2. 一致性Consistency:数据库中的数据在事务操作前和事务处理后都必须满足业务规则约束。事务必须使数据库从一个一致性状态变换到另外一个一致性状态
  3. 隔离性Isolation:事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
  4. 持久性Durability:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
4.mysql的索引的底层树结构,为什么使用此种结构?
  1. 二叉查找树(BST):不平衡。解决了排序的基本问题,但是由于无法保证平衡,可能退化为链表;
  2. 平衡二叉树(AVL):旋转耗时。通过旋转解决了平衡的问题,但是旋转操作效率太低;
  3. 红黑树:树太高。通过舍弃严格的平衡和引入红黑节点,解决了AVL旋转效率过低的问题,但是在磁盘等场景下,树仍然太高,IO次数太多;
  4. B树:通过将二叉树改为多路平衡查找树,解决了树过高的问题;
  5. B+树:在B树的基础上,将非叶节点改造为不存储数据的纯索引节点,进一步降低了树的高度;此外将叶节点使用指针连接成链表,范围查询更加高效。
  6. B+树比起B树:
    1. 更少的IO次数:B+树的非叶节点只包含键,而不包含真实数据,因此每个节点存储的记录个数比B数多很多(即阶m更大),因此B+树的高度更低,访问时所需要的IO次数更少。此外,由于每个节点存储的记录数更多,所以对访问局部性原理的利用更好,缓存命中率更高
    2. 更适于范围查询:在B树中进行范围查询时,首先找到要查找的下限,然后对B树进行中序遍历,直到找到查找的上限;而B+树的范围查询,只需要对链表进行遍历即可。
    3. 更稳定的查询效率:B树的查询时间复杂度在1到树高之间(分别对应记录在根节点和叶节点),而B+树的查询复杂度则稳定为树高,因为所有数据都在叶节点。
5.Innodb和MyIsam的B+树实现有什么不同?
  1. InnoDB中主键索引的叶子节点的数据区域存储的是数据记录,辅助索引存储的是主键值
  2. MYISAM中叶子节点的数据区域存储的是数据记录的地址
6.简述聚簇索引和非聚簇索引的区别,Innodb使用哪种索引?
  1. 聚簇索引:树的叶节点data域保存了完整的数据记录
  2. 非聚簇索引:将数据与索引分开存储,索引结构的叶子节点data指向了数据对应的位置,然后以data域的值为地址,读取相应数据记录。
  3. Innodb使用聚簇索引
7.描述更新一行数据的过程

一行数据的隐藏列如下图:

截屏2021-07-28 上午3.47.12

ROW_ID: 隐藏的行ID,用来生成默认的聚簇索引。
DB_TRX_ID: 操作这个事务的ID,也就是最后一个对数据插入或者更新的事务id。
DB_ROOL_PTR: 回滚指针,指向这个记录的Undo Log信息

更新一行数据:

  1. 用排他锁锁定该行

  2. 记录redo

    redo log就是保存执行的SQL语句到一个指定的Log文件,当Mysql执行recovery时重新执行redo log记录的SQL操作即可。当客户端执行每条SQL(更新语句)时,redo log会被首先写入log buffer;当客户端执行COMMIT命令时,log buffer中的内容会被视情况刷新到磁盘。redo log在磁盘上作为一个独立的文件存在,即Innodb的log文件。

  3. 把该行修改前的值复制到undo.log

    undo log是为回滚而用,具体内容就是copy事务前的数据库内容(行)到undo buffer,在适合的时间把undo buffer中的内容刷新到磁盘。undo buffer与redo buffer一样,也是环形缓冲,但当缓冲满的时候,undo buffer中的内容会也会被刷新到磁盘;

  4. 修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行

8.描述jdbc开发的基本流程。
  1. 加载驱动: Class.forname(“类全名”)

  2. 创建连接
    Connection con = DriverManager.getConnection(URL,USERNAME,PASSWORD);
    三个参数为:
    URL:jdbc:mysql://localhost:3306/数据库名称?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username:数据库用户
    password:数据库用户名

  3. Statment执行对象
    Statment对象会造成“SQL注入漏洞“问题
    我们可以使用PreparedStatement代替Statment,PreparedStatement是java.sql包下面的一个接口 。
    PreparedStatement可以重复使用,减少和SQL引擎交互的次数。提高了安全性(阻止了SQL注入)

      String sql ="SELECT * FROM book_tab WHERE book_id=?"//?:预先占位
      PreparedStatement pst= conn. preparedStatement(sql);
      pst.setString(1,"abc OR 1=1");// 1表示第几个问号
    
  4. 执行操作
    增删改:pst.executeUpdate()
    查询:pst.executeQuery() 返回ResultSet对象

  5. 关闭连接
    判断ResultSet对象是否为空:if(rs!=null) rs.close();
    判断PreparedStatment对象是否为空 :if(pst!=null) st.close();
    判断Connection对象是否为空:if(conn!=null) conn.close();

9.简述数据表设计的三大范式
  1. 第一大范式:所有的域都应该是原子性的,即数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项。实体中的某个属性有多个值时,必须拆分为不同的属性。
  2. 第二大范式:主键策略。即数据库表中的每个实例或记录必须可以被唯一地区分。选取一个能区分每个实体的属性或属性组,作为实体的唯一标识。(例如身份证就是人的主键,一个身份证对应一个人)
  3. 第三大范式:非主依赖。在第二大范式基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
10.将两个有序链表合并为一个有序链表
//合并链表
public ListNode mergeListNode(ListNode l1,ListNode l2){
		ListNode temp1;
		ListNode temp2;
		while(l1!=null && l2!=null){
      	temp1 = l1.next;
				temp2 = l2.next;
      	//我愿称之为蛇形合并
      	l1.next = l2;
      	l1 = temp1;
      	l2.next = l1;
      	l2 = temp2;
		}
		return l1;
}
20210725
1.Statement和PreparedStatement有什么区别?哪个性能更好?
  1. Statment对象会造成“SQL注入漏洞“问题
    可以使用PreparedStatement代替Statment,PreparedStatement是java.sql包下面的一个接口 。
    PreparedStatement可以重复使用,减少和SQL引擎交互的次数。提高了安全性(阻止了SQL注入)
2.transient关键字的作用
  1. Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。

    为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。

    当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

    简而言之,被transient修饰的变量不参与序列化和反序列化。

  2. 例外

    java中有两种序列化的方式。

    1. 实现Serializable接口。

    2. 实现Externalizable接口。

    Externalizable接口是Serializable接口的子类

    源码如下

    public interface Externalizable extends java.io.Serializable {
        void writeExternal(ObjectOutput out) throws IOException;
        void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
    }
    

    这个接口的两个方法可以指定对类中的哪些属性进行序列化。使用这个接口时,无论属性有没有被transient修饰,默认不对任何属性进行序列化。所以实现了Externalizable接口的类一般不再使用transient修饰属性。

3.mysql中使用delete、trucate、drop删除表中数据的区别
  1. 使用

    delete

    1. 删除整张表的数据:delete from table_name;
    2. 删除部分数据,添加where子句:delete from table_name where...;
    3. 说明
      1. 属于DML语言,每次删除一行,都在事务日志中为所删除的每行记录一项。产生rollback,事务提交之后才生效;如果有相应的 trigger,执行的时候将被触发,如果删除大数据量的表速度会很慢。
      2. 删除表中数据而不删除表的结构(定义),同时也不释放空间。

    truncate

    1. 只能操作表,将表中数据全部删除,在功能上和不带where子句的delete语句相同:truncate table table_name;
    2. 说明
      1. 默认情况下,truncate通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。所以使用的系统和事务日志资源少,可以使用reuse storage; truncate会将高水线复位(回到最开始).
      2. truncate是DDL语言, 操作立即生效,自动提交,原数据不放到rollback segment中,不能回滚. 操作不触发trigger.
      3. 删除内容、释放空间但不删除表的结构(定义)。

    drop

    1. drop语句将删除表的结构,以及被依赖的约束(constrain),触发器(trigger),索引(index);drop table table_name;
    2. 说明
      1. 删除之后,依赖于该表的存储过程/函数将保留,但是变为invalid状态.
      2. drop也属于DDL语言,立即执行,执行速度最快
      3. 删除内容和定义,释放空间。
  2. 区别

    1. 表和索引所占空间:
        当表被TRUNCATE 后,这个表和索引所占用的空间会恢复到初始大小;
        DELETE操作不会减少表或索引所占用的空间;
        DROP语句将表所占用的空间全释放掉。

    2. 应用范围:
        TRUNCATE 只能对table;
        DELETE可以是table和view。

    3. 执行速度:
        drop > truncate > delete

    4. delete from删空表后,会保留一个空的页,truncate在表中不会留有任何页。

    5. DELETE语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。
      TRUNCATE TABLE 则一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的。并且在删除的过程中不会激活与表有关的删除触发器。执行速度快。

    6. 当使用行锁执行 DELETE 语句时,将锁定表中各行以便删除。truncate始终锁定表和页,而不是锁定各行。

    7. 如果有identity产生的自增id列,delete from后仍然从上次的数开始增加,即种子不变;
      使用truncate删除之后,种子会恢复到初始值。

  3. 总结

    1. delete 语句可以使用where子句实现部分删除,而truncate不可以,会将表中的整个数据全部删除,使用时,可以按需求选择;
    2. 如果想从表中删除所有的数据,不要使用delete,可以使用truncate语句,因为这样执行速度更快。truncate语句实际是删除原来的表然后重新建立一个新表;
    3. 在没有备份情况下,谨慎使用 drop 与 truncate。要删除表结构使用drop;
    4. 对于由 FOREIGN KEY 约束引用的表,不能使用 TRUNCATE TABLE,而应使用不带 WHERE 子句的 DELETE 语句。由于 TRUNCATE TABLE 不记录在日志中,所以它不能激活触发器。
4.死锁的四个必要条件
  1. 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。

  2. 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

  3. 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。

  4. 循环等待条件:若干进程间形成首尾相接循环等待资源的关系

    截屏2021-07-28 上午4.17.18
5.解释脏读,不可重复读,幻读,mysql默认使用的隔离策略是什么?
  1. 数据库的隔离级别:

    1. Read Uncommitted 读未提交

      在其中一个事务中,可以读取到其他事务未提交的数据变化。这种读取其它会话还没有提交的事务,会产生脏读问题。

    2. Read Committed 读已提交

      在其中一个事务中,可以读取到其它事务已经提交的数据变化。这种读取可能产生不可重复读问题 。

    3. Repetable Read 可重复读

      在其中一个事务中,直到事务结束前,都可以反复读取到事务刚开始时看到的数据,并一直不会发生变化,避免了脏读、不可重复读。

    4. Serializable 可序列化

      在每个读的数据行上都需要加上表级共享锁,在每次写数据时都要加上表级排他锁。

  2. 脏读

    截屏2021-07-28 上午4.33.59

  3. 不可重复读

    截屏2021-07-28 上午4.34.24

  4. 幻读

    截屏2021-07-28 上午4.34.37

6.ConcurrentHashMap是如何实现线程安全的?
  • 整体结构与HashMap别无二致,都是使用哈希表+红黑树结构

  • 线程安全:使用内建锁Sychronized+CAS锁每个桶的头结点,使得锁进一步细粒度化

  • ConcurrentHashMap不允许键值对为空

    DK7与JDK8 ConcurrentHashMap的变化

    1. 结构上的变化:

      取消原先的Segment设计,取而代之的是使用与HashMap同样的数据结构,但其内部仍然有 Segment 定义,但仅仅是为了保证序列化时的兼容性而已,不再有任何结构上的用处
      即哈希表+红黑树,并且引入了懒加载机制。(JDK1.7一上来就初始化,JDK1.8 在第一次put时才初始化)

    2. 线程安全:

      • 锁粒度更细:由原来的锁Segment一片区域到锁桶的头结点

      • 由原先的ReentrantLock替换为Sychronized+CAS

      现版本的sychronized已经经过不断优化,性能上与ReentrantLock基本没有差异,

      并且相对于ReentrantLock,使用Sychronized可以节省大量内存空间(原来ReentrantLock下的segment都得加入同步队列,都得继承AQS下的Node,而synchronized只是锁住头结点,头结点下边的节点都不会加入同步队列里,所以 节省了空间),这是非常大的优势所在。

7.简述ThreadLocal的工作原理及流程?
  1. ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立地改变自己的副本,而不影响其它线程所对应的副本。

  2. void set(T value);设置当前线程的线程局部变量的值。

    T get( );返回当前线程所对应的线程局部变量。

    void remove( );当前线程局部变量的值删除,目的是为了减少内存的占用,当线程结束后,对应线程的局部变量将自动被垃圾回收。

    T initialValue( );返回该线程局部变量的初始值。

8.举例说明内部类,静态内部类,匿名内部类?
  1. 内部类:HashMap中的Values、KeySet、EntrySet以及TreeMap中的EntrySet、Value

  2. 静态内部类:LinkedList中的Node节点就是静态内部类

  3. 匿名内部类:Comparator中的Compare方法在创建的时候,可以使用匿名内部类的方式创建

9.给你一个字符串 s,由若干单词组成,单词之间用单个或多个连续的空格字符隔开。返回字符串中最后一个单词的长度。如果不存在最后一个单词,请返回 0 。单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。(LeetCode58-easy)
class Solution {
    public int lengthOfLastWord(String s) {
        s = s.trim();
        if(s.length() == 0) return 0;
        int index = 0;
        int n = s.length();
        for(int i = n - 1; i > 0;i--){
            if(s.charAt(i) == ' '){
                index = i + 1;
                break;
            }
        }
        return n - index;
    }
}
10.给你一个有序数组 nums ,请你原地删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。(LeetCode26-easy)
class Solution {
    public int removeDuplicates(int[] nums) {
        int n = nums.length;
        if (n == 0) {
            return 0;
        }
        int fast = 1, slow = 1;
        while (fast < n) {
            if (nums[fast] != nums[fast - 1]) {
                nums[slow] = nums[fast];
                ++slow;
            }
            ++fast;
        }
        return slow;
    }
}
无限进步
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值