1.异种多数据源时你们怎么解决的?如何切换不同数据源
引入了com.baomidou--->'dynamic-datasource-spring-boot-starter'驱动
在yml文件中进行了不同种数据源的配置
指定前驱数据源datasource.dynamic.primary:XXX
在需要切换的类或方法上指定@DB("XXX")
2.Mybatis拦截器有了解过么?展开讲讲
例如:自定义的分页插件PageHelper中就有用到拦截器,在mybatis中提供了Interceptor接口,自己实现拦截器只需要实现Interceptor接口
Mybatis中拦截器的设计非常巧妙,将jdk动态代理用到了极致,使用代理代理类的方法构建拦截器链
援引连接[这里讲的蛮好的非常好值得一看](https://www.cnblogs.com/ethan-wu/p/11897026.html)
3.你们项目中redis怎么部署的?(想问redis部署方案架构诸如)
我们项目中采用的是读写分离,主从同步的方式部署,有主备灾多台构建,我了解到Redis的的部署方式有单机版、主从同步、Sentinel哨兵、Cluster集群部署四种方式...
援引连接[这里讲的蛮好的值得一看](https://blog.csdn.net/liangsena/article/details/128049854)
4.redis中有用到多租户么?
多租户技术(Multi-TenancyTechnology)又称多重租赁技术,用于实现如何在多用户的环境下共用相同的系统或程序组件,并且仍可确保各用户间数据的隔离性。
自定义开发集成RedisTemplate的getKeySerializer 方法,来根据当前租户切换keySerializer ,来达到修改前缀的目的,重写方法方法定制化
https://my.oschina.net/u/3706162/blog/1649227
5.redis常见哪些数据类型?它是单线程还是多线程?
五种常见数据类型:String、List、Set、ZSet、Hash
三类特殊数据类型:geospatial(地理位置)、hyperloglog基数:一个集合中不重复的元素个 页面UV、bitmaps位图
Redis6.0版本之前的单线程是指网络I/O和键值对读写是由一个线程完成的。Redis6.0之后引入的多线程指的是网络请求过程采用了多线程,但是键值对的读写命令仍然是单线程处理,所以Redis是并发安全的。
也就是6.0前只有网络请求模块和数据操作模块是单线程的,而其他的持久化、集群数据同步等,是由额外的线程执行的。
可以说Redis涉及到数据读写时是单线程的,但是其他的持久化、集群数据同步等都是多线程完成的。
原文链接:https://blog.csdn.net/weixin_45248492/article/details/126953467
6.了解数据库中的锁么?
数据库里有的锁有很多种,为了方面理解,所以我根据其相关性"人为"的对锁进行了一个分类,分别如下
基于锁的属性分类:共享锁、排他锁。
基于锁的粒度分类:表锁、行锁、记录锁、间隙锁、临键锁。
基于锁的状态分类:意向共享锁、意向排它锁。
https://blog.csdn.net/itworld123/article/details/113852680
7.数据库隔离级别有哪些?它们分别解决了什么问题?
Read UnCommitted(读未提交): 读到其他事务未提交的数据,会出现脏读、不可重复读、幻读。
Read Committed(读已提交): 读到其他事务已提交的数据,解决了脏读,会出现不可重复读、幻读。
Repeatable Read(可重复读): 相同的条件,多次读取到的结果一致。解决了脏读、不可重复读,会出现幻读。
Serializable(串行化): 所有事务串行执行,解决了脏读、不可重复读、幻读。
链接:https://juejin.cn/post/7185433021292986426
8.MVCC原理有了解过没?
MVCC,全称 Multi-Version Concurrency Control ,MVCC是多版本并发控制的全称,是指多版本的并发控制。MVCC是一种并发控制方法。通常,在数据库管理系统中,它用编程语言实现对数据库和事务存储器的并发访问。
MVCC最大的好处,【读不加锁,读写不冲突】。在读多写少的OLTP()应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能
MVCC的实现方式有多种,典型的有乐观(optimistic)并发控制 和 悲观(pessimistic)并发控制。
MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作。
其他两个隔离级别和MVCC不兼容,因为 READ UNCOMMITTED 总是读取最新的数据行,而不是符合当前事务版本的数据行。而 SERIALIZABLE 则会对所有读取的行都加锁。
原文链接:https://blog.csdn.net/huaishu/article/details/89924250
它的实现原理主要是依赖记录中的 3个隐式字段(DB_ROW_ID、DB_TRX_ID、DB_ROLL_PT),undo日志 , Read View 来实现的。
默认情况下,DB_ROW_ID 是数据库为这行记录生成的唯一隐式主键。DB_TRX_ID 是当前操作记录的事务ID,而 DB_ROLL_PTR 是一个回滚指针,与撤消日志一起使用以指向以前的旧版本。
有两种 undo 日志:insert undo log、update undo log,帮助MVCC的撤销的本质是update undo log 。事实上,撤消日志是指代回滚段中的旧记录链。
援引链接:https://www.cnblogs.com/yidengjiagou/p/16663224.html
9.什么情况下会发生行锁转表锁?
没有索引或者索引失效时,InnoDB 的行锁变表锁
原因:Mysql 的行锁是通过索引实现的
10.Java中的锁了解么?有什么区别?展开讲讲,顺便说下锁升级原理
Lock接口
ReetrantLock类 , 使用 CAS + AQS实现, 它可以是公平锁, 也可以是非公平锁, 它用于显示的加锁和释放锁
synchronized 关键字
java提供的一种原子性内置锁(关键字), 每个对象都可以使用它当作同步监视器, 当线程进入使用Synchronized修饰的代码块中会自动获取内部锁 , 此时其他线程想要访问此同步代码时只能被阻塞, 等待锁的释放(前一个线程执行完, 或者出现异常,调用了wait()方法等), 在进入 synchronized 会从 主内存把变量读取到自己工作内存,在退出的时候会把工作内存的值写入到主内存,保证了原子性。
原文链接:https://blog.csdn.net/xx12321q/article/details/124925441
区别:
1.synchronized是关键字,Lock是接口;
2.synchronized是隐式的加锁,lock是显式的加锁;
3.synchronized可以作用于方法上,lock只能作用于方法块;
4.synchronized底层采用的是objectMonitor,lock采用的AQS;
5.synchronized是阻塞式加锁,lock是非阻塞式加锁支持可中断式加锁,支持超时时间的加锁;
6.synchronized在进行加锁解锁时,只有一个同步队列和一个等待队列, lock有一个同步队列,可以有多个等待队列;
7.synchronized只支持非公平锁,lock支持非公平锁和公平锁;
8.synchronized使用了object类的wait和notify进行等待和唤醒, lock使用了condition接口进行等待和唤醒(await和signal);
9.lock支持个性化定制, 使用了模板方法模式,可以自行实现lock方法;
JDK 1.6 为了减少获得锁和释放锁所带来的性能消耗,在JDK 1.6里引入了4种锁的状态:无锁、偏向锁、轻量级锁和重量级锁,它会随着多线程的竞争情况逐渐升级,但不能降级。
研究发现大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了不让这个线程每次获得锁都需要CAS操作的性能消耗,就引入了偏向锁。当一个线程访问对象并获取锁时,会在对象头里存储锁偏向的这个线程的ID,以后该线程再访问该对象时只需判断对象头的Mark Word里是否有这个线程的ID,如果有就不需要进行CAS操作,这就是偏向锁。当线程竞争更激烈时,偏向锁就会升级为轻量级锁,轻量级锁认为虽然竞争是存在的,但是理想情况下竞争的程度很低,通过自旋方式等待一会儿上一个线程就会释放锁,但是当自旋超过了一定次数,或者一个线程持有锁,一个线程在自旋,又来了第三个线程访问时(反正就是竞争继续加大了),轻量级锁就会膨胀为重量级锁,重量级锁就是Synchronized,重量级锁会使除了此时拥有锁的线程以外的线程都阻塞。
援引链接:https://www.cnblogs.com/aikutao/p/15895770.html
专门针对于synchronized而言 偏向锁, 轻量级锁与重量级锁
1、当没有被当做锁的时候,这就是个普通对象,锁标志位为01,是否偏向锁为0
2、当对象被当做同步锁时,一个线程A抢到锁时,锁标志位依然是01,是否偏向锁为1,前23位记录A线程的线程ID,此时锁升级为偏向锁
3、当线程A再次试图来获得锁时,JVM发现同步锁对象的标志位是01,是否偏向锁是1,也就是偏向状态,Mark Word中记录的线程id就是线程A自己的id,表示线程A已经获得了这个偏向锁,可以执行同步锁的代码,这也是偏向锁的意义
4、当一个线程B尝试获取锁,JVM发现当前的锁处于偏向状态,并且现场ID不是B线程的ID,那么线程B会先用CAS将线程id改为自己的,这里是有可能成功的,因为A线程一般不会释放偏向锁。如果失败,则执行5
5、偏向锁抢锁失败,则说明当前锁存在一定的竞争,偏向锁就升级为轻量级锁。JVM会在当前线程的现场栈中开辟一块单独的空间,里面保存指向对象锁Mark Word的指针,同时在对象锁MarkWord中保存指向这片空间的指针。上面的保存都是CAS操作,如果竞争成功,代表线程B抢到了锁,可以执行同步代码。如果抢锁失败,则继续执行6
6、轻量级锁抢锁失败,则JVM会使用自旋锁,自旋锁并非是一个锁,则是一个循环操作,不断的尝试获取锁。从JDK1.7开始,自旋锁默认开启,自旋次数由JVM决定。如果抢锁成功,则执行同步代码;如果抢锁失败,则执行7
7、自旋锁重试之后仍然未抢到锁,同步锁会升级至重量级锁,锁标志位改为10,在这个状态下,未抢到锁的线程都会被阻塞,由Monitor来管理,并会有线程的park与unpark,因为这个存在用户态和内核态的转换,比较消耗资源,故名重量级锁
原文链接:https://blog.csdn.net/weixin_52593321/article/details/119918202
11.索引数据结构了解么?用B+树有哪些优势?
12.AQS了解吗?JUC并发包下用过哪些
AQS 全名 AbstractQueuedSynchronizer,意为抽象队列同步器,JUC(java.util.concurrent 包)下面的 Lock 和其他一些并发工具类都是基于它来实现的。AQS 维护了一个 volatile 的 state 和一个 CLH(FIFO)双向队列
AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。
atomic包:
基本类型:AtomicInteger、AtomicLong、AtomicBoolean
数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
引用类型:AtomicReference、AtomicMarkableReference、AtomicStampedReference
对象的属性修改类型:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
locks包:ReentrantLock、ReentrantReadWriteLock
同步工具类:CountDownLatch、Semaphore、Cyclicbarrier、FutureTask
并发容器类:ConcurrentHashMap、CopyOnWriteArrayList、ConcurrentLinkedQueue、BlockingQueue、ConcurrentSkipListMap
原文链接:https://blog.csdn.net/Kiwi_fruit/article/details/125946539
13.聊一聊你们项目分布式锁,分布式事务怎么做的?
分布式锁方案:
基于数据库悲观锁、乐观锁、
redis setnx+expire、
Redisson就是使用watch dog解决了锁过期释放,业务没执行完问题、
RedLock(红锁)Redis Distributed Lock,可用实现多节点redis的分布式锁【Redisson完成了对Redlock算法封装】
zk临时顺序节点:有顺序的临时节点(用于实现分布式锁) 引入客户端CuratorFramework
https://blog.csdn.net/sumengnan/article/details/125034081
分布式事务:
常见分布式事务解决方案
1.seata 阿里分布式事务框架 2、消息队列 3、saga 4、XA
https://www.jianshu.com/p/654debe463c7
https://blog.csdn.net/I_am_fine_/article/details/124622313
https://blog.csdn.net/weixin_43332735/article/details/129214008?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2~default~YuanLiJiHua~Position-2-129214008-blog-124622313.235^v31^pc_relevant_default_base3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~YuanLiJiHua~Position-2-129214008-blog-124622313.235^v31^pc_relevant_default_base3&utm_relevant_index=5
14.了解哪些索引优化策略?
15.设计模式用的多么?聊一聊
16.什么是回表、索引覆盖
回表查询,先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。追加建立联合索引,使走覆盖索引。
17.ThreadLocal、inheritableThreadLocals、TransmittableThreadLocal
ThreadLocal
inheritableThreadLocals :
缺陷:使用线程池的情况下,因为线程池是复用线程,不会重复创建,而上述的inheritableThreadLocals是在创建子线程时才会将父线程的值复制到子线程,但是在线程池中不会重复创建,所以多次使用后,仍然记录的是第一次提交任务时的外部线程的值,造成了数据的错误
阿里类包:TransmittableThreadLocal
18.redis 缓存穿透,击穿,雪崩
① 缓存穿透:大量请求根本不存在的key ->透
② 缓存雪崩:redis中大量key集体过期 ->崩
③ 缓存击穿:redis中一个热点key过期(大量用户访问该热点key,但是热点key过期)
缓存穿透:客户端访问不存在的数据,使得请求直达存储层,导致负载过大,直至宕机。原因可能是业务层误删了缓存和库中的数据,或是有人恶意访问不存在的数据。解决方式:1.存储层未命中后,返回空值存入缓存层,客户端再次访问时,缓存层直接返回空值。2.将数据存入布隆过滤器,访问缓存之前经过滤器拦截,若请求的数据不存在则直接返回空值。 缓存击穿:一份热点数据,它的访问量非常大,在它缓存失效的瞬间,大量请求直达存储层,导致服务崩溃。解决方案:1.永不过期:对热点数据不设置过期时间。2.加互斥锁,当一个线程访问该数据时,另一个线程只能等待,这个线程访问之后,缓存中的数据将被重建,届时其他线程就可以从缓存中取值。 缓存雪崩:大量数据同时过期、或是redis节点故障导致服务不可用,缓存层无法提供服务,所有的请求直达存储层,造成数据库宕机。解决方案:1.避免数据同时过期,设置随机过期时间。2.启用降级和熔断措施。3.设置热点数据永不过期。4.采用redis集群,一个宕机,另外的还能用
穿透解决方案:
对空值进行缓存
设置白名单
使用布隆过滤器
网警
雪崩解决方案:
进行预先的热门词汇的设置,进行key时长的调整
实时调整,监控哪些数据是热门数据,实时的调整key的过期时长
使用锁机制
击穿解决方案:
进行预先的热门词汇的设置,进行key时长的调整
实时调整,监控哪些数据是热门数据,实时的调整key的过期时长
使用锁机制
原文链接:https://blog.csdn.net/starboyxyh/article/details/127131427
19.缓存一致性方案:
Cache Aside Pattern 首选先写入数据库后删除缓存的策略,再增加缓存时间兜底。对于一致性要求更高的场景,考虑用订阅MySQL binlog+MQ的方式做延迟双删。
Read/Write through Pattern 增加一个Cache Provider 对外提供读写操作,解耦且避免缓存服务挂掉给应用系统带来的影响。
Write Behind Pattern 应用只写缓存,再由Cache Provider定时入库,数据一致性差。
Write Around 由读请求写缓存并设置一个过期时间,写请求只负责写库
https://www.jianshu.com/p/1a14fcc22204
https://blog.csdn.net/hkl_Forever/article/details/127798965
问题复盘:
20.负责的项目,核心模块功能应用背景和技术实现细节上详细展开说说;
略
21.HashMap底层源码put、get、resize流程详细展开讲讲;
HashMap底层主要使用数组+链表(或红黑树)来实现。下面分别介绍HashMap的put、get、resize流程。
1. put方法:
put方法用于往HashMap中添加键值对,其大致流程如下[[1](https://www.cnblogs.com/chengxiao/p/6059914.html)]:
- 首先根据Key的hashCode值计算出存储在数组中的位置(hash % 数组长度),如果该位置上的链表为空,则直接将键值对存储到该位置;
- 如果该位置上已经存储了键值对,则遍历该位置上的链表,判断Key是否已经存在,如果已经存在则更新其Value值,否则将新的键值对添加到链表末尾;
- 如果链表长度达到一定的阈值(默认为8),且数组长度已经达到扩容的阈值(默认为0.75),则触发扩容操作。
2. get方法:
get方法用于根据Key获取对应的Value,其大致流程如下[[1](https://www.cnblogs.com/chengxiao/p/6059914.html)]:
- 根据Key的hashCode值计算出在数组中的位置,如果该位置上的链表为空,则返回null;
- 如果该位置上不为空,则遍历链表,查找Key所对应的节点,如果找到则返回其Value值,否则返回null。
3. resize方法:
resize方法用于对HashMap进行扩容,其大致流程如下[[1](https://www.cnblogs.com/chengxiao/p/6059914.html)]:
- 计算新的数组长度(原长度的两倍),然后创建一个新的数组;
- 遍历旧数组中的每个位置,以该位置为起点遍历链表,并将链表上的所有节点重新计算在新数组上的位置,添加到新数组中的相应位置;
- 由于新数组长度为原长度的两倍,因此节点在新数组中的位置可能与原来不同,如果多个节点在新数组中的位置相同,则使用链表或红黑树进行连接。
综上所述,HashMap底层源码实现了put、get和resize操作,通过数组+链表来实现高效的键值对存储和检索,并在适当的时候触发数组扩容以提高性能。
22.索引优化策略,联合索引(a,b,c)失效情况分析;
当联合索引(a,b,c)失效时,通常是由于以下原因导致的:
索引列没有按照最左前缀顺序出现,例如在查询条件中只使用了(b,c)两个列,而没有使用到a列。这时虽然联合索引包含了b和c两列,但是a列并没有使用索引,因此该索引失效。
查询条件中使用了索引列的范围查询或者不匹配查询,例如使用了大于、小于、不等于、like等操作符,而不是精确查找。这时候B+树索引无法被有效利用,因为B+树是按照值的大小进行排序的,因此范围查询和不匹配查询可能会导致一部分索引数据无法被过滤掉,从而导致MySQL放弃使用该索引。
索引列上存在隐式或显式的数据类型转换,例如列a为字符串类型,查询条件中使用了数字或日期类型的值。这时候MySQL需要先将查询条件中的类型转换为索引列上的类型,然后才能进行比较,这可能导致索引失效。
索引列存在NULL值,当查询条件中使用了IS NULL或IS NOT NULL操作符时,MySQL不能使用索引来优化查询,因为索引中不存在NULL值。
为避免联合索引失效,可以在设计索引时遵循以下原则:
将经常用于过滤、排序和分组的列作为索引的前缀。
避免使用范围查询和不匹配查询,如有必须使用则尽量减少对结果集的影响。
尽量避免数据类型转换,确保索引列和查询条件列的数据类型一致。
如果有NULL值,可以将NULL值放在索引列的最后,以防止其影响索引效率。
小表驱动大表:
1、首先优化原则,小表驱动大表,即小的数据集驱动大的数据集。
2、select * from A where id in(select id from b),当B表的数据集必须小于A表的数据集时,用in优于exists。
3、select *from A where exists (select 1 from B where b.id=a.id)。当A表的数据集小于B表的数据集时,用exists优于in。
原文链接:https://blog.csdn.net/weixin_47104688/article/details/120238004
https://blog.csdn.net/qq_38011415/article/details/103304189
23.b+树和b树的比较;
Mysql索引使用B+树而不是B树是因为B+树相比于B树有以下几个优点:
B+树的内部节点只保存键值,而不保存数据,所有数据都保存在叶子节点上。这样可以使得每个节点能够存储更多的键值,从而减少了树的高度,提高了查询效率。
在B+树中,所有叶子节点形成一个有序链表,便于范围查询和遍历整个表,同时也方便通过叶子节点扫描整个表,因此B+树具有更好的顺序访问性能。
由于B+树的内部节点不保存数据,因此在插入或删除时,只需要对叶子节点进行操作,不需要对内部节点进行修改,这样可以大大减少树的更新代价,降低维护索引的成本。
B+树相对于B树更适用于磁盘存储,因为B+树的内部节点和叶子节点都可以利用磁盘块进行连续读取,而B树的节点则会分散在不同的块中,难以进行有效的IO操作,因此B+树在外存储存储数据时,能够更好地利用磁盘读写性能。
综上所述,由于B+树具有更优秀的查询效率、顺序访问性能和更新代价以及更适用于磁盘存储等优点,Mysql索引通常使用B+树而不是B树
24.介绍下你了解的数据结构有哪些;
25.设计模式有用过么,展开说说你知道的设计模式,介绍下如何设计一个工厂模式coding编码细节;
26.springboot自动装配流程和实现细节;
Spring Boot 是一个基于 Spring 框架的快速开发脚手架,可以通过自动装配帮助开发者快速集成各种组件。Spring Boot 的自动装配流程如下:
1. 加载启动类:在运行时,Spring Boot 会加载启动类,并将其作为 Spring 应用上下文的主配置类。
2. 扫描组件:Spring Boot 会扫描启动类所在包及其子包下所有的组件,并实例化这些组件,并加入 Spring 容器中。
3. 加载配置:Spring Boot 会加载 application.yml 或 application.properties 文件中的配置信息,并将其加入 Spring 环境中。
4. 自动装配:Spring Boot 的核心就是通过自动装配来进行各种组件的集成,例如数据库连接池、Web 容器等。Spring Boot 会自动识别项目中使用的组件,并进行自动装配。
那么,Spring Boot 是如何实现自动装配的呢?其实,Spring Boot 主要是通过以下两个机制来实现自动装配:
1. @EnableAutoConfiguration:该注解会自动加载 META-INF/spring.factories 文件中的所有自动装配类,并将它们加入容器中。在 Spring Boot 的 jar 包中,通常会包含多个 spring.factories 文件,在构建应用时 Spring Boot 可以识别并加载它们。
2. @Conditional:该注解可以让 Spring 在满足特定条件的情况下才进行自动装配。常见的条件包括:类路径中是否存在某个特定的类、是否定义了某个特定的 Bean 等。
最后,Spring Boot 还实现了按需加载的功能,可以让项目在不需要某些组件时不进行自动装配。此外,开发者也可以自定义 Starter,将多个组件打包成一个 Starter,使得使用者可以更容易地引用到这些组件。[[1]([https://zhuanlan.zhihu.com/p/384540393])][[2]([https://zhuanlan.zhihu.com/p/123343325])]
27.MVCC实现原理;
MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数据库事务的并发控制技术,主要用于解决并发访问数据库时的读写冲突问题。MVCC主要有两种实现方式:基于时间戳和基于版本链。
基于时间戳的MVCC实现原理:在数据库中,每个事务在执行期间都会被分配一个唯一的时间戳,用以标识该事务。当一个事务需要读取数据库中的某些数据时,它只能看到已经提交的所有事务的快照,也就是时间戳早于该事务的所有快照。如果该数据所属的事务还没有提交,则该事务无法看到该数据。这种方式可以避免读写冲突问题,并且能够提高读取性能,但是会增加存储空间的开销。
基于版本链的MVCC实现原理:在数据库中,每次对数据的修改都会生成一个新的版本,这些版本按时间顺序形成了一个版本链。每个事务在读取数据时,会根据自己的启动时间和每个版本的时间戳来获取正确的快照。当查询完成后,该事务就能够看到该版本被该事务之前提交的所有事务的数据修改。这种方式可以减少额外的存储空间的开销,并且能够更方便地管理事务的版本,但是在高并发的情况下,版本链会越来越长,导致查询缓慢。
需要注意的是,MVCC虽然可以有效地减少读写冲突,但也会增加存储和CPU的开销,并且不适用于所有场景。在实际应用中,需要根据具体的业务需求和场景选择合适的并发控制技术。
28.Lock与Synchronized区别及实现原理;
29.事务的隔离级别及其分别解决了什么问题;
事务隔离级别是指在多个事务同时访问数据库时,数据库是如何进行隔离的。常见的有四种隔离级别:
1. 读未提交(Read Uncommitted)
最低的事务隔离级别,一个事务可以读取另一个事务尚未提交的数据。容易出现脏读、不可重复读和幻读等问题。
2. 读已提交(Read Committed)
一个事务只能读取另一个事务已经提交的数据。解决了脏读问题,但仍然可能出现不可重复读和幻读的问题。
3. 可重复读(Repeatable Read)
一个事务开始后,它看到的所有数据都是该事务所见过的数据。在这个事务内部,多次读取同一数据会返回同样的结果。解决了脏读和不可重复读问题,但仍然可能出现幻读问题。
4. 序列化(Serializable)
最高的事务隔离级别,在不考虑并发性能的前提下,通过强制事务串行执行,从而避免了脏读、不可重复读和幻读等问题。
需要注意的是,隔离级别越高,对系统性能的影响也会越大,因此需要根据实际需求和系统负载来确定合适的隔离级别。常见的应用场景是选择可重复读或读已提交隔离级别,仅在必要的情况下选择序列化隔离级别。
30.Redis常用的数据结构,以及你们的主要应用场景;
Redis常用的数据结构包括:
1. String:最基本的数据结构,可以存储字符串、整数和浮点数。
2. Hash:键值对集合,适合存储对象或者结构化数据。
3. List:链表,可以从头或尾部添加或删除元素,适合做队列或栈。
4. Set:无序集合,可以进行交集、并集、差集等操作,适合存储不重复的数据。
5. Sorted Set:有序集合,每个元素有一个权重,可以根据权重排序,适合存储排行榜等数据。
Redis的主要应用场景包括:
1. 缓存:Redis实现内存缓存,可以减少数据库压力,提高访问速度。
2. 消息队列:Redis的List可以实现简单的消息队列,适合异步处理任务。
3. 计数器:Redis可以快速地实现计数器功能,并支持自增、自减操作。
4. 分布式锁:Redis通过SETNX命令可以实现分布式锁,避免多个客户端同时操作同一个资源。
5. 排行榜:Redis的Sorted Set可以很方便地实现排行榜功能,可以根据权重进行排序。
以上都是Redis的常见应用场景,当然还有很多其他的使用方式。资料来源:[[1](https://zhuanlan.zhihu.com/p/491342749)][[2](http://news.hexun.com/2023-04-23/208374325.html)][[3](https://redis.io/topics/data-types)]
31.Redis部署架构;
Redis是一种常见的内存缓存数据库,可以通过不同的部署架构实现高可用、高性能和数据持久化等需求。常见的部署架构包括以下几种:
1. 单机架构(Standalone)
最简单的部署方式,将Redis实例直接运行在一台计算机上。该方式适合于开发环境和小规模生产环境。
2. 主从复制架构(Master-Slave Replication)
在主从复制中,有一个Redis实例作为主节点,负责所有写操作。其他多个Redis实例作为从节点,只负责复制主节点的数据。该方式可以提高数据读取性能,并且支持自动故障转移。
3. Sentinel架构
Sentinel是Redis官方提供的高可用解决方案,通过引入多个Sentinel节点来实现监控Redis实例的状态,并在主节点出现故障时自动进行故障转移。该方式可以提供高可用性,并支持数据持久化。
4. Cluster架构
Cluster是Redis官方提供的分布式解决方案,通过将数据分片到多台计算机节点上来实现数据存储和并行处理。每个节点都可以接收读写请求,并将数据传输到正确的节点上。该方式适用于大规模应用场景,并且支持自动故障转移和数据持久化。
需要根据实际需求和场景来选择合适的部署架构,以提供最佳性能和高可用性。[[1](https://redis.io/topics/cluster-tutorial)][[2](https://redis.io/topics/sentinel)][[3](https://redis.io/topics/replication)]
32.SpringCloud组件你了解过哪些?他们分别是用作什么的,讲下你了解的技术栈;
33.介绍下并发安全问题;
并发安全问题是多线程程序中需要解决的一个重要问题。在互联网企业,特别注意并发编程问题。当多个线程同时访问共享资源时,可能会出现并发安全问题,例如数据竞争、死锁等。
数据竞争是指多个线程同时尝试读写同一数据结构,可能会导致数据不一致或程序崩溃。死锁是指多个线程同时占用某些资源,导致互相等待对方所占用的资源而无法继续执行。
在多线程编程中,应该尽可能使用线程安全的方式访问共享资源,例如使用锁机制、同步机制和CAS等技术来保证数据的原子性和一致性。此外,可以使用线程池来管理并发请求,以达到合理利用资源和避免线程创建销毁的开销。
总之,并发安全问题是多线程编程中需要注意的一个重要问题。需要在设计程序时特别关注多线程的交互,选择适当的线程同步方式保证程序的正确性和可靠性。[[1](https://blog.csdn.net/weixin_47723535/article/details/109366323)][[2](https://blog.csdn.net/lwpoor123/article/details/130218061)]
正在为您搜索:并发三大特性
并发三大特性是指:原子性、可见性、有序性。[2]
- 原子性:一个操作是不可中断的整体,要么全部执行成功,要么全部不执行。在Java中,对于基本数据类型的读取和赋值操作是原子性操作。
- 可见性:多个线程之间共享变量时,对于一个线程对变量值的修改,该变量的新值能够即时地被其他线程看到,这就是可见性。
- 有序性:程序执行的过程中,可能出现编译器或处理器的指令重排,这会导致程序的执行顺序与代码编写的顺序不一致。在Java中,可以使用synchronized或volatile等关键字来保证代码的有序性。