如何利用Redis实现一个分布式锁
加锁setnx(set if not exist)
,解锁del(key)
,存在问题用户忘记解锁,会出现死锁
加锁setnx(key,value)
,expire(key,30)
,解锁del(key)
,存在问题:
setnx
和expire
两者不是原子性,解决方法使用lua
脚本执行- 锁到期后线程还在执行,当线程执行结束时去释放锁会把别的线程锁释放,解决方法加锁时生成一个随机唯一的标识符,解锁时判断标识符是否匹配
请说说你对反射的理解
反射表示可以在程序运行期间动态获取对象的所有属性和方法
获取class
对象四种方式:
getClass()
.class
Class.forName()
- 包装类
.TYPE
,例Integer.TYPE
优点:运行期间动态获取类,提高代码的灵活性
缺点:破坏类的封装性,没有遵循面向对象原则
请你说说聚簇索引和非聚簇索引
它们两个最大的区别是索引和数据是否分离
聚簇索引:索引和数据不分离,叶子结点保留数据行
非聚簇索引:索引和数据分离,叶子结点存放指向数据行的地址
数据库为什么不用红黑树而用B+树
索引的数据结构会存在磁盘当中,每次查询需要到磁盘中访问,需要使用磁盘IO
,红黑树高度非常高,进行很多次磁盘IO
,而B+
树的高度一般2-4
,磁盘IO
次数小于红黑树的,性能高
红黑树磁盘IO
需要遍历整个树,而B+
树磁盘IO
可以一次读取一页的数据,从而减少磁盘IO
次数
红黑树每个节点需要保存数据,而B+
树只需要保存键值信息,根据数据行地址找到数据
请你说说ConcurrentHashMap
支持高并发读和写操作,JDK1.7
之前底层数据结构,大数组(segment
)+小数组(HashEntry
)+链表,使用锁住segment
;1.8之后数组+链表/红黑树,使用CAS
保证线程安全
Redis如何与数据库保持双写一致性
有四种同步策略:
- 先更新数据库再更新缓存:多线程存在缓存和数据库数据不一致
- 先更新缓存再更新数据库:每次数据更新就更新缓存,对性能影响很大
- 先删除缓存再更新数据库:多线程存在缓存和数据库数据不一致
- 先更新数据库再删除缓存(较优):也会存在数据不一致,可以使用重试机制,它和第三个比较优点在于都是读取旧数据,那就先不删除缓存,第三个删除缓存,读取旧数据还得重新删除缓存
请你说说InnoDB和MyISAM的区别
InnoDB | MyISAM | |
---|---|---|
数据锁 | 行级锁 | 表级锁 |
事务 | 支持 | 不支持 |
外键 | 支持 | 不支持 |
性能 | 增删改 | 查询 |