面试说好的问基础,我怎么感觉一点也不基础呢

2023-05-31 0 1,022

中田在mysql方面因为答题不如健全,被辩手Axat了几番。经过三天的人格备考之后,捷伊半程复试又开始了。

辩手:晚安,请单纯如是说下自己吧。

中田:晚安,我是xxxxxx,以后在广州的xxx公司负责管理了xxx控制系统的研制结构设计。

辩手:嗯嗯,那我嘿嘿问你许多此基础问题吧。

中田:嗯嗯,好的。

辩手:你了解arraylist吧,请说下外部的许多优点。

中田这时心里立马乐开怀,那个单纯啊。

中田:arraylist的下层主要是由字符串组成,它和一般字符串不太一样,arraylist具有手动提速的机能。每天当我们add两个原素到堆栈里头的这时候,单厢有一步棋证实耗电量的监督机制推论(相关联源标识符里头的ensureCapacityInternal表达式)假如当字符串外部的原素达到了字符串共振频率的这时候,就会以1.5倍的表面积去做提速,下层是初始化了才做控制系统外部的两个System.arraycopy方法。

又由于arraylist是选用字符串储存的,在抹除的这时候可以借助于字符串位的负号去加速机能定位,写数据的这时候须要牵涉到停住字符串,所以读的操控性平均值要比写的操控性更高许多。

辩手:嗯嗯,提问地挺全面性的。那你觉得在采用arraylist的这时候通常会特别注意些什么吗?

中田:嗯嗯,有的是。通常就要根据标识符的语句给arraylist附两个常量来机能定位那个字符串的大小不一,避免其做过多无谓的提速操作方式。另外在循环式中展开删掉操作方式的这时候须要特别注意会有坑,通常提议选用插值器的商业模式来处置。

ps:

假如采用下列这种方式展开原素的去除可能会导致出现删掉原素不完备的情况:

public static void main(String[] args) { ArrayListApplication arrayListApplication = new ArrayListApplication(); List<String> list = new ArrayList(3); list.add(“a”); list.add(“c”); list.add(“c”); list.add(“d”); list.add(“e”); System.out.println(list); System.out.println(“==========”); removeV1(list, “c”); System.out.println(list); } public static void removeV1(List<String> list, String deleteItem) { for (int i = 0; i < list.size(); i++) { String item = list.get(i); if (item.equals(deleteItem)) { list.remove(item); } } }

打印结果:

[a, c, c, d, e] ========== [a, c, d, e]

这时由于删掉掉list里头原素之后,list的size值也减少了,随之导致了字符串原素的前移,因此会出现被删掉原素的后一位直接绕开了if推论,没有被“命中”。假如选用foreach的方式删掉,则会抛出一段异常信息,声明删掉失败:

Exception in thread “main” java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) at java.util.ArrayList$Itr.next(ArrayList.java:859)

辩手:嗯嗯,你刚刚有说到插值器删掉,那么你有了解过插值器商业模式吗?

中田:额,插值器商业模式,让我思考一下…. 背了知识点,但是不记得了….

面试说好的问基础,我怎么感觉一点也不基础呢

辩手:好吧…

ps:其实插值器商业模式的好处在于,直接帮我们屏蔽了具体的实现细节,通过选用插值器的方式来帮助我们编写许多可以复用的类。例如说arraylist,其实外部也有自己插值器的具体实现,vector也有自己插值器商业模式的具体实现。非常的方便,并且有助于减少标识符里头的对于具体实现的强依赖性。

辩手:那我们切入下两个话题吧,能说下自己对于幻读的理解吗?

中田:嗯嗯,可以的。我在上家公司工作的这时候,公司外部的事务隔离级别设置为了可重复读级别,这样能够保证当前事务读取的数据不会受到其他事务提交的影响,但是这种隔离级别会在事务提交完毕之后查询数据的这时候出现幻读的场景,假如须要解决幻读的情况须要将事务的隔离级别提升为串行化等级。

辩手:哦,那你在工作中有试过提升为串行化吗?

中田:没有,因为串行化是强行在mysql层加锁,使得事务得排队执行,容易产生堵塞的情况,操控性不佳。

辩手:那你是怎么解决幻读的情况呢?

中田:嗯….别的同事帮我解决的…..

这时,辩手脸上渐渐露出了诡异的笑容。

面试说好的问基础,我怎么感觉一点也不基础呢

ps:其实幻读这种情况在工作中偶尔还是会遇到的,举个具体场景:

假设某一时刻,同时有两个事务访问了数据库,须要先从库里头查询订单是否存在,然后再插入捷伊订单记录。

a连接

mysql> select @@global.tx_isolation,@@tx_isolation; +———————–+—————–+ | @@global.tx_isolation | @@tx_isolation | +———————–+—————–+ | REPEATABLE-READ | REPEATABLE-READ | +———————–+—————–+ 1 row in set, 2 warnings (0.00 sec) mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from t_order_1 where id =100; Empty set (0.00 sec)

b连接

mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from t_order_01 where id =100; ERROR 1146 (42S02): Table test-db01.t_order_01 doesnt exist mysql> select * from t_order_1 where id =100; Empty set (0.00 sec)

假设在两边事务都开启的一刻,a连接中的事务往数据库插入了一条id为100的数据,然后commit。a连接

mysql> INSERT INTO `test-db01`.`t_order_1` ( `id`, `order_no`, `product_id`, `user_id`, `create_time`, `update_time` ) -> VALUES -> ( 100, 2, 2, 2, now(), now()); Query OK, 1 row affected (0.00 sec) mysql> select * from t_order_1 where id=100; +—–+———-+————+———+———————+———————+ | id | order_no | product_id | user_id | create_time | update_time | +—–+———-+————+———+———————+———————+ | 100 | 2 | 2 | 2 | 2020-07-14 22:57:37 | 2020-07-14 22:57:37 | +—–+———-+————+———+———————+———————+ 1 row in set (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec)

当a事务提交结束了,这时b事务开始执行select 查询校验的操作方式,推论不存在id为100的数据,这时打算执行插入数据的操作方式:

mysql> select * from t_order_1 where id=100; Empty set (0.00 sec) mysql> INSERT INTO `test-db01`.`t_order_1` ( `id`, `order_no`, `product_id`, `user_id`, `create_time`, `update_time` ) -> VALUES -> ( 100, 2, 2, 2, now(), now()); ERROR 1062 (23000): Duplicate entry 100 for key PRIMARY

结果出现了异常,这种情况我们通常称之为幻读。那么该如何解决这种场景的问题呢?其实mysql外部提供了一种叫做next-key-lock的加锁监督机制,可以供我们处置这类特殊情况:

mysql> select * from t_order_1 where id=100 for update; +—–+———-+————+———+———————+———————+ | id | order_no | product_id | user_id | create_time | update_time | +—–+———-+————+———+———————+———————+ | 100 | 2 | 2 | 2 | 2020-07-14 23:06:03 | 2020-07-14 23:06:03 | +—–+———-+————+———+———————+———————+ 1 row in set (0.00 sec) 借助于 **for update **语句,我们可以在应用程序的层面手工实现数据加锁保护操作方式。就是那些须要业务层面数据独占时,可以考虑采用** for update**。

就会加入一把锁,其他试图改写数据的请求将会处于堵塞情况。(读数据的请求不会堵塞)

辩手:那你知道mysql里头的mvcc监督机制吗?

中田:mvcc是啥?mvc我倒知道,以后工作中有采用过springmvc框架 blabla(希望把辩手绕开引到自己熟系的话题方向)

辩手满脸微笑地看着中田,似乎想缓解下尴尬的气氛。

辩手:好吧,你以后有对缓存了解过吗?

中田:嗯嗯,我在工作中通常喜欢采用redis作为缓存。当查询数据的这时候先去redis中查询,假如redis没有再去mysql中抹除。

辩手:嗯嗯,那你有了解过redis里头的哪些数据结构吗?

中田:嗯嗯,我在工作中有采用过string,list,hash,zset,set这几类数据结构,它们各自都有自己的特点,在采用的这时候须要结合实际的业务场景来采用。

String类型可以用于储存许多单纯的键值对数据,例如数字,字符串之类的。

List结构通常是选用了双端堆栈的结构,这类结构通常采用的命令有lpush,lpop,rpop等,假如想去除某个节点的前置和后置节点就比较单纯(复杂度就是O(1)),但是搜索比较复杂。适合用于储存许多列表类型的数据信息,例如说用户的留言和评论信息。

Set 是两个无顺序的集合,比较常见的例如说交集查询,用于搜索两个好友之间共同阅读过的图书。或者两个人之间的共同好友等。采用命令sinter key [key…] 即可实现。

面试说好的问基础,我怎么感觉一点也不基础呢

Hash是包含键值对的无序散列表,常用命令有:hget,hgetall等。

辩手:嗯嗯,你讲的这些东西都只是停留在了表层,关于其外部的构造有去做过许多深入的了解吗?

中田:额,没有….

这时中田又一次被辩手打击了自信心

辩手:好吧,今天的一面主要只是问问此基础,那么就先这样吧,我去找下我老大询问下。

中田:嗯嗯,好的。(似乎觉得还有戏)

中田两个人在前台坐着等待着下一场复试的到来,不仅内心感叹道,自己过去的工作中过多地安逸于写crud,很多java的此基础问题也都记得不太清楚了,每天下班之后也没怎么学习,虽然一面只是问了些此基础问题,结果却暴露了自己这么多的知识盲区。

过了不久两个陌生的男人慢慢走了过来,天啊,这家伙真的是聪明“绝顶” 了。中田立马慌了,脑袋一片空白,二面似乎来了一位资深的大佬…..

二面复试官:晚安,我是你的二面辩手,下边我可能会针对你的项目做许多询问。

链接或者直接私信“架构”领取:

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务