某大厂后端java实习一面

本人是努力的26届在校努力学习的程序员,努力学习开发,每天按照自己的学习和答案,总结全网最新的面经,大家可以关注一下,一起努力,打破信息差,找到满意工作

目录

1.聊一下关于mp的使用

2.锁的区间划分

3锁的粒度划分

4.锁级别划分

5加锁方式划分

6.锁的使用方式划分

7.用过linux吗?Linux的常用命令有哪些


1.聊一下关于mp的使用

MyBatis-Plus是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。如果添加了MybatisPlus的依赖 但是不想使用MybatisPlus的类和方法 这时候仍然可以按照之前使用Mybatis的步骤做开发 几乎和之前没有任何的改变

它的使用方法

① 导入依赖,如果有注释掉之前mybatis的依赖

②如果MyBatis Plus有自定义mapper文件,地址配置由mybatis-mapper-locations改为mybatis-plus.mapper-locations

③ 给实体类加注解

@TableName(“user”) 加载类上 将该类和数据库中对应的表建立联系 注解值为表名

@TableId(value = “对应表列名”,type = IdType.AUTO) 建立主键属性和主键字段之间的联系。 value 字段名, type 定义主键自增类型 IdType.AUTO MySQL自动递增

常规属性@TableField(“name”) 将常规属性和常规字段名建立联系

连表查询 封装数据的属性 没有对应的字段 需要定义忽略

@TableField(exist = false) exist = false代表当前属性在表中没有字段名

  1. 基于Redis实现了短信验证码的登录并独立解决了登陆状态刷新的问题。

一.设计key的结构

所以我们可以使用String结构,就是一个简单的key,value键值对的方式,但是关于key的处理,session他是每个用户都有自己的session,但是redis的key是共享的,咱们就不能使用code了

在设计这个key的时候,我们之前讲过需要满足两点

1、key要具有唯一性

2、key要方便携带

如果我们采用phone:手机号这个的数据来存储当然是可以的,但是如果把这样的敏感数据存储到redis中并且从页面中带过来毕竟不太合适,所以我们在后台生成一个随机串token,然后让前端带来这个token就能完成我们的整体逻辑了

  • 设计整体访问流程

1.发送短信验证码:将手机号作为key,生成的验证码作为value存到redis中,等登录的时候,在去校验验证码是否一致。

2.验证码登录、注册:将用户发过来的手机号和验证码进行校验,查询redis对应的验证码,检验是否和发送过来的验证码是否一致,如果一致查询是否存在用户信息,如果不存在则去创建用户信息,最后将该用户信息存入redis中,以token作为key,用户信息作为value。为了后续的校验登录状态。

3.校验登录状态:根据请求携带的token去redis查询对应的用户信息,如果没有则拦截,如果有则保存到Threadlocal中,并且放行。

三,解决状态登录刷新问题

初始方案思路总结:

在这个方案中,他确实可以使用对应路径的拦截,同时刷新登录token令牌的存活时间,但是现在这个拦截器他只是拦截需要被拦截的路径,假设当前用户访问了一些不需要拦截的路径,那么这个拦截器就不会生效,所以此时令牌刷新的动作实际上就不会执行,所以这个方案他是存在问题的

优化方案

既然之前的拦截器无法对不需要拦截的路径生效,那么我们可以添加一个拦截器,在第一个拦截器中拦截所有的路径,把第二个拦截器做的事情放入到第一个拦截器中,同时刷新令牌,因为第一个拦截器有了threadLocal的数据,所以此时第二个拦截器只需要判断拦截器中的user对象是否存在即可,完成整体刷新功能。

  1. HashMap的底层讲一下

我从三个方面讲一下它

1.HashMap 中的关键属性---看-HashMap 的源码片段,可以知道它的几个属性

第一个属性 loadFactor,它是负载因子,默认值是 0.75,表示扩容前。

第二个属性 threshold 它是记录 HashMap 所能容纳的键值对的临界值,它的计算规 则是负载因子乘以数组长度。

第三个属性 size,它用来记录 HashMap 实际存在的键值对的数量。

第四个属性 modCount,它用来记录 HashMap 内部结构发生变化的次数。

第五个是常量属性 DEFAULT_INITIAL_CAPACITY ,它规定 的默认容量是 16。

2、HashMap 的存储结构

HashMap 采用的是 的存储结构。HashMap 的数组部分称为 Hash 桶,数组元素保存 在一个叫做 table 的属性中。jdk1.8以后当链表长度大于等于 8 时,链表数据将会以红黑树的形式进行存储,当长度降到 6 时,又会转成链表形式存储。

每个 Node 节点,保存了用来定位数组索引位置的 hash 值、Key、Value 和链表指向 的下一个 Node 节点。而 Node 类是 HashMap 的内部类,它实现了 Map.Entry 接口, 它的本质其实可以简单的理解成就是一个键值对。

  1. HashMap 的工作原理

首先,通过hash算法计算出key的hashcode值,然后根据数组长度取模,得到在数组中的位置。

如果该位置上没有元素,则直接将key-value存储在该位置上。

如果该位置上已经存在元素,则需要进行链表或红黑树的操作。

如果链表长度小于8,则采用链表存储,将新元素插入到链表尾部。

如果链表长度大于等于8,则将链表转化为红黑树进行存储。

当数组长度达到阈值时(默认为0.75),需要进行扩容操作,将数组长度扩大为原来的两倍,并将原有元素重新分布到新数组中。

当数组中的元素数量小于阈值的0.25时,会进行缩容操作,将数组长度缩小为原来的一半。

  1. mysql的锁了解吗

我通常会把Mysql中锁搞成六种分类,共14种锁

  1. 死锁

死锁,简单来说就是两个或者两个以上的线程在执行的过程中,争夺同一个共

享资源造成的相互等待的现象

互斥条件,共享资源 X 和 Y 只能被一个线程占用;

请求和保持条件,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不

释放共享资源 X;

不可抢占条件,其他线程不能强行抢占线程 T1 占有的资源;

循环等待条件,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有

的资源,就是循环等待

2.锁的区间划分

1、间隙锁

间隙锁是开区间的,是一个在索引记录之间的间隙上的锁。

作用:保证某个间隙内的数据在锁定情况下不会发生任何变化。比如我mysql默认隔离级别下的可重复读(RR)。
当使用唯一索引来搜索唯一行的语句时,不需要间隙锁定。如下面语句的id列有唯一索引,此时只会对id值为10的行使用记录锁。

2、临键锁(Next-key Locks)

临键锁是行锁+间隙锁,即临键锁是是一个左开右闭的区间,比如(- ∞, 1 ] |(1, 3 ] |(3, 4 ] | (4, + ∞)。

InnoDB的默认事务隔离级别是RR,在这种级别下,如果使用select … in share mode或者select … for update语句,那么InnoDB会使用临键锁,因而可以防止幻读;但即使你的隔离级别是RR,如果你这是使用普通的select语句,那么InnoDB将是快照读,不会使用任何锁,因而还是无法防止幻读。

3锁的粒度划分

  1. 表级锁(Table-level lock)

InnoDB在使用过程中只要不通过索引检索数据时,全部是表锁。
开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低InnoDB在使用过程中只要不通过索引检索数据时,全部是表锁。
开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低

  1. 行级锁(Record Locks)

InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点,MySQL于Oracle不同,后者是通过在数据块中对相应的数据行加锁来实现的,InnoDB只有通过索引条件检索数据,InnoDB才使用行级锁

行锁的劣势:开销大;加锁慢;会出现死锁

行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强

3、页级锁

页级锁是 MySQL 中比较独特的一种锁定级别,在其他数据库管理软件中并不常见。
页级锁的颗粒度介于行级锁与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力同样也是介于上面二者之间。另外,页级锁和行级锁一样,会发生死锁。
页级锁主要应用于 BDB 存储引擎。

4.锁级别划分

1、共享锁(share lock,即S锁)

共享锁(S):又称读锁,允许一个事务去读取一行,阻止其他事务获得相同数据集的排它锁,若事务T对数据对象A加上S锁,则事务T可以读A,但不能修改A,其他事务只能对再对A加S锁,而不能加X锁,直到T释放A上的锁,这保证了其他事务可以读A,但在释放A上的S锁之前不能对A做任何修改。

2、排它锁 / 独占锁(exclusive lock,即X锁)

排它锁(X):又称写锁,允许获取排它锁的事物更新数据,阻止其他事务取得相同的数据集共享读锁和排它写锁,若事务T对数据对象A加上X锁,事物T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T 释放A上的锁

3、意向锁

事物B对一行数据使用行锁,当有另一个事物A对这个表使用了表锁,那么这个行锁就会升级为表锁,事务A在申请行锁(写锁)之前,数据库会自动先给事务A申请表的意向排他锁。当事务B去申请表的写锁时就会失败,因为表上有意向排他锁之后事务B申请表的写锁时会被阻塞。

当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他锁。

5加锁方式划分

1、自动锁( Automatic Locks)

当进行一项数据库操作时,缺省情况下,系统自动为此数据库操作获得所有有必要的锁。

自动锁分为三种:

DML 锁:

锁用于控制并发事务中的数据操纵,保证数据的一致性和完整性。

保护并发情况下的数据完整性。

语句能够自动地获得所需的表级锁(TM)与行级(事务)锁(TX)。

DDL 锁

锁用于保护数据库对象的结构,如表、索引等的结构定义。

排它 DDL 锁

创建、修改、删除一个数据库对象的 DDL 语句获得操作对象的 排它锁。

共享 DDL 锁

需在数据库对象之间建立相互依赖关系的 DDL 语句通常需共享获得 DDL锁。

如创建一个包,该包中的过程与函数引用了不同的数据库表,当编译此包时该事务就获得了引用表的共享 DDL 锁。如使用 alter table 语句时,为了维护数据的完成性、一致性、合法性,该事务获得一排它 DDL 锁

systemlocks。

2.显示锁(LOCK TABLES )

某些情况下,需要用户显示的锁定数据库操作要用到的数据,才能使数据库操作执行得更好,显示锁是用户为数据库对象设定的。

6.锁的使用方式划分

1、乐观锁(Optimistic Lock)

乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。

2、悲观锁(Pessimistic Lock)

悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。

  1. 索引为什么用B+树,有什么特性

首先,常规的数据库存储引擎,一般都是采用 B 树或者 B+树来实现索引的存储。

(如图)因为 B 树是一种多路平衡树,用这种存储结构来存储大量数据,它的整个高度 会相比二叉树来说,会矮很多。 而对于数据库来说,所有的数据必然都是存储在磁盘上的,而磁盘 IO 的效率实际上是 很低的,特别是在随机磁盘 IO 的情况下效率更低。 所以树的高度能够决定磁盘 IO 的次数,磁盘 IO 次数越少,对于性能的提升就越大,这 也是为什么采用 B 树作为索引存储结构的原因。

但是在 Mysql 的 InnoDB 存储引擎里面,它用了一种增强的 B 树结构,也就

是 B+树来作为索引和数据的存储结构。

相比较于 B 树结构,B+树做了几个方面的优化。

1. B+树的所有数据都存储在叶子节点,非叶子节点只存储索引。

2. 叶子节点中的数据使用双向链表的方式进行关联

使用 B+树来实现索引的原因,我认为有几个方面。

3. B+树非叶子节点不存储数据,所以每一层能够存储的索引数量会增加,意味着 B+

树在层高相同的情况下存储的数据量要比 B 树要多,使得磁盘 IO 次数更少。

4. 在 Mysql 里面,范围查询是一个比较常用的操作,而 B+树的所有存储在叶子节点

的数据使用了双向链表来关联,所以在查询的时候只需查两个节点进行遍历就行,

而 B 树需要获取所有节点,所以 B+树在范围查询上效率更高。

5. 在数据检索方面,由于所有的数据都存储在叶子节点,所以 B+树的 IO 次数会更加 稳定一些。

6. 因为叶子节点存储所有数据,所以 B+树的全局扫描能力更强一些,因为它只需要

扫描叶子节点。但是 B 树需要遍历整个树。

另外,基于 B+树这样一种结构,如果采用自增的整型数据作为主键,还能更好的避免

增加数据的时候,带来叶子节点分裂导致的大量运算的问题。

总的来说,我认为技术方案的选型,更多的是去解决当前场景下的特定问题,并不一定

是说 B+树就是最好的选择,就像 MongoDB 里面采用 B 树结构,本质上来说,其实是 关系型数据库和非关系型数据库的差异

  1. 创建索引需要考虑什么,索引优化有没有相关经验

(1)MySQL 表主键设计

自增:  顺序存储,索引维护成本低,索引效率高;

UUID:非顺序增长,随机IO严重。

(2)索引并不是越多越好,要根据查询,有针对性的创建

(3)应尽量避免在WHERE子句中对字段进行NULL值判断,否则将导致引擎放弃使用索引而进行全表扫描;

(4)值分布很稀少的字段不适合建索引,例如“性别”这种只有两三个值的字段;

(5)不用外键,由程序保证约束;

(6)尽量不用UNIQUE,由程序保证约束;

(7)使用多列索引时主意顺序和查询条件保持一致,同时删除不必要的单列索引。

(8)排序时,排序字段需要注意index, 尤其是关联查询排序时,尽可能使用小表的字段进行排序

SQL 优化 原则

(1)避免属性隐试转换 , 如定义Moblie varchar  where Moblie =198989888会导致全表扫描;

(2)Where子句中条件字段本身避免使用函数;

(3)使用获取的必要字段代替SELECT *;

(4)批量插入,使用INSERT INTO table (col1,col2,...) VALUES (value1, value2,...),(value1, value2,...); 插入多条数据只有一次提交;

(5)避免使用长事务;

(6)禁止负向查询: NOT、!=、<>、!<、!>、NOT IN、NOT LIKE,会导致全表扫描;

(7)大表之间的join,尽量缩小结果集之后再join,否则会消耗较多的内存和CPU;

(8)搜索严禁左模糊或者全模糊(like %XX, 或like %XX%),会导致全表扫描。

7.用过linux吗?Linux的常用命令有哪些

切换用户(su)

切换目录(cd)

查看目录(ls)

创建目录(mkdir)

删除目录与文件(rm)

修改目录(mv)

拷贝目录(cp)

搜索目录(find)

 查看当前目录(pwd)

新增文件(touch)

删除文件(rm)

编辑文件(vi、vim)

过滤文件(grep)

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值