数据结构
1、HashMap的底层是用什么实现的
数组+链表
2、在1.8之后有什么区别
数组+链表+红黑树
3、1.8后用的是头插法还是尾插法,为什么
尾插法 因为遍历计算长度后面要用,还有多线程相对安装
4、什么时候会触发扩容机制
元素个数大一数组长度*0.75 就自动扩容 copyOf 到 创建好的长度为2的新数组
5 hashtable是线程安全的,ConcurrentHashMap也是线程安全的,那么为什么不用hashtable?
hashtable是对整个数组结构加锁,ConcurrentHashMap对node节点加锁 所以ConcurrentHashMap相对效率更高
6 hashMap和hashSet的区别
HashSet底层也是hashMap
7 JAVA list、set、map等集合类线程不安全的问题及解决方法?
-
使用
Vector
(ArrayList
所有方法加synchronized
,太重)。 -
使用
Collections.synchronizedList()
转换成线程安全类。 -
使用
java.concurrent.CopyOnWriteArrayList
(推荐), 在增删改的时候加锁,get方法读取的没加锁,还有 每次拿到迭代器的时候复制数据的引用, 优点:读多写少性能优秀,线程安全,保证迭代器的独立性和隔离性(读写分离),缺点:内存占用大,容易引发GC,还有数据一致性问题
迭代器的fail-fast机制, 修改数据就报错
mysql
mysql为什么没有用b树
二叉树->平衡二叉树->红黑树->b树->b+树 这个过程来分别分析一下这些数据结构的优缺点,应为哪些缺点导致不用这个数据结构,io效率高的原因就是 2层的b+树存储的数据量非常大 层数越低io的次数越低
-
b树节点排序,节点可以有多个节点,节点也是排序的
-
b+树有b树的特点,叶子节点之前有指针,叶子节点存储所有元素,也是排序的
-
同层数下的b树存的数据就比b+树少很多,b树就会很高,io次数加大 效率更慢
Mysql锁有哪些,如何理解 按照锁的细粒度划分
-
1.行锁:某行数拐,锁度最小,并发序高
-
2.表锁:锁整张表,锁粒度最大,并发度低
-
3.间隙锁: 锁的是一个区间,不包括本身
-
4.Next-Key Lock 行锁+间隙锁 解决幻读
ACID是靠什么保证的?
-
原子性:由undolog日志来保证,它记录了需要回滚的日志信息,
-
一致性:是由其他三大特性保证,程序代码要保证业务上的一致性
-
隔离性:是由MVCC来保证
-
持久性:由redolog来保证,mysal修改数据的时候会在redolog中记录一份日志数据,就算数据没有保存成功,只要日志保存成功了,数据仍然不会丢失
事务并发问题
脏读:读到别的事务还没提交的数据, 不可重复读:两次读取的数据不是一样的, 幻读:读取的时候数据发生修改,第二次读取数据到插入的新数据
-
读未提交:允许事务读取未被其他事务提交的更改,所以脏读、不可重复读、幻读都会出现
-
读已提交:只能读取到别人提交的完的数据,有不可重复读,和幻读的问题
-
可重复读:不允许修改读到的数据,但是可以插入,有幻读
-
串行化:不可以修改表,基本等于锁表,性能低
InnoDB是聚簇索引,辅助索引是非聚簇索引 读取的话innoDB的效率可能比myisum 效率高, 修改反之
索引下推就是本来要在serve层做过滤处理的放到存储引擎层, 可以动开启或关闭,
索引匹配遵循最左匹配原则
怎么保证数据库和redis的一致性?
可以先修改数据库再删除缓存
MVCC实现原理是什么?
依赖于记录中的三个隐藏字段,最近被修改记录的事务id,undolog回滚指针,可能有隐藏主键 , Read View 解决事务里数据是否可见的问题
当前读和快照读:
对于当前事务开启后提交的数据,当前事务需要通过隐藏的 DB_ROLL_PTR 字段找到 undo log,然后进行逻辑上的回溯才能拿到事务开启时的原数据。 这个通过 undo log + 数据行获取到事务开启时的原始数据的过程就是“快照读”
很多时候,我们在读取数据库时,需要读取的是行的当前数据,而不需要通过 undo log 回溯到事务开启前的数据状态,主要包含以下操作:insert updata,select ...for update
索引失效情况
-
没有按照最左匹配原则进行匹配
-
索引字段使用 or 时,会导致索引失效而转向全表扫描,或者使用order
-
like查询是以%开头
-
如果列类型是字符串,那一定要在条件中将数据使用引号引用起来
慢sql优化
添加索引 ,查看是否走了索引,检查字段有没有多余的,数据是否过多,要不要进行分库分表
mysql的读写错底层原理:数据库读写锁的底层原理是基于多线程同步和互斥机制的实现。读写锁允许多个线程同时读取共享数据,但只允许一个线程进行写操作。在读取时,如果没有写锁,则多个线程可以共享读锁,而在写操作时,必须获取独占的写锁,并阻塞其他线程的读写操作,直到该线程完成写操作并释放写锁。读写锁通过共享锁和排他锁来实现这一机制,通过信号量等机制对锁进行管理,从而保证数据的一致性和完整性。