亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

實際面試中遇見的相關問題

標簽:
Java
  • Redis 持久化

    • RDB(Redis DataBase)持久化:
      • 快照方式持久化,将某一个时刻的内存数据,以二进制的方式写入磁盘;
    • AOF(Append Only File)持久化:
      • 文件追加持久化,记录所有非查询操作命令,并以文本的形式追加到文件中;
    • 混合持久化:
      • RDB + AOF 混合方式的持久化,Redis 4.0 之后新增的方式,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能减低数据丢失的风险。
  • 限流方案

    • 单机
      • 用aop做一个计数器,按照接口做技术器就可以。
    • 令牌桶机制
      • count = max_sync,获取到令牌后再处理,处理完不放回去,定时任务每隔1s充令牌,让count = max_sync
    • 集群限流方案
      • 第一种方案商品系统 ----> redis <--------- ,通过decr key>=0,来获取令牌,定时任务1秒运行一次,setex key 补充令牌,缺点很明显,不一定可以完全匹配的上
      • 第二种方案:在应用启动时用hset设置时间和数量,用hincirby扣减,扣减没了之后用redis的乐观锁进行充能。
      • 第三种方案:创建一个分布式限流系统,商品系统从这个分布式系统中获取令牌,一次拿10个在本机的内存中进行扣减,消耗完之后在从分布式限流系统中拿。
      • 第四种方案:可以使用redis的zset,统计在某个时间段内的请求有多少个。
  • 分布式事务方案

    • 四种分布式事务方案:

    • 图片描述

    • 二阶段提交:

      • 要保证每个阶段的事务都执行成功才可以往下执行。
    • tcc协议,try -> confirm - > cancel

      • 基础表 id 状态 item_id
      • 库存表 + 库存流水表(包含状态字段)
      • 优惠卷表 + 优惠卷流水表(包含状态字段)
      • try阶段,扣减库存,扣减优惠卷,confirm阶段,把两个流水表状态改为success
      • 图片描述
    • 最大努力提交型
      图片描述

      • 事务执行者1执行成功,发送mq消息,让事务执行者2执行,这种适合业务解耦,并且事务1只要执行成功了,事务2一定要执行成功场景。
      • 这个里面有个问题,有可能事务1执行成功了,发送mq消息失败了。
    • 事务型消息

      • 图片描述
      • 可以利用rocketmq做事务型消息,事务1先给rocketmq发送perpare消息,发送成功后,事务1继续执行,执行完成后发送commit prepare消息或者rollback消息。
      • 如果prepare消息发送成功了,commit或者rollback发送失败了,rockmq会根据prepare定期反查事务1,然后事务1在决定重发commit还是rollback消息。
  • 缓存雪崩

    • 缓存雪崩是指在缓存中大量的键同时过期或失效,导致请求直接访问数据库或后端服务,给数据库或后端服务造成巨大压力,导致系统性能下降甚至崩溃的现象。
    • 设置随机过期时间:
      • 为缓存键设置随机的过期时间,避免大量键同时过期的情况发生,减少缓存雪崩的概率。
    • 实现缓存预热:
      • 在系统启动或缓存失效前,提前加载热门数据到缓存中,避免在关键时刻大量请求直接访问后端服务。
    • 使用分布式缓存:
      • 将缓存数据分布在多个缓存节点上,通过分散请求负载来减少单个缓存节点的压力,提高系统的可用性和抗压能力。
    • 设置熔断机制:
      • 在缓存失效的情况下,通过设置熔断机制,直接返回默认值或错误信息,避免请求直接访问后端服务,减轻后端服务的压力。
    • 实时监控和报警:
      • 监控缓存系统的状态和性能指标,及时发现异常情况,并通过报警机制通知运维人员进行处理,减少缓存雪崩的影响
  • 缓存穿透

    • 缓存穿透是指在缓存系统中,大量的请求查询不存在于缓存和数据库中的数据,导致这些请求直接访问数据库,占用数据库资源,而缓存无法发挥作用的现象。
    • 布隆过滤器(Bloom Filter):
      • 布隆过滤器是一种高效的数据结构,可以用于快速判断一个元素是否存在于集合中。在缓存层引入布隆过滤器,可以在查询请求到达时,首先通过布隆过滤器判断该请求对应的数据是否存在于缓存或数据库中,从而避免无效的查询操作。
    • 缓存空值处理:
      • 对于查询数据库返回的空结果,也可以将空结果缓存起来,设置一个较短的过期时间,避免频繁查询数据库。这样在下次查询相同的数据时,可以直接从缓存中获取空结果,而不需要再次查询数据库。
    • 异步加载缓存:
      • 当缓存未命中时,可以异步加载数据到缓存中,避免在高并发场景下直接访问数据库。在异步加载过程中,可以通过互斥锁或分布式锁来保证只有一个线程去加载数据,避免重复加载。
    • 设置热点数据永不过期:
      • 对于一些热点数据,可以将其设置为永不过期,或者过期时间较长,以保证这部分数据始终在缓存中可用。
    • 限制恶意请求:
      • 通过访问频率控制、验证码等手段,限制对缓存的恶意请求,防止攻击者通过查询不存在的数据来触发缓存穿透。
  • 缓存击穿

    • 缓存击穿是指在缓存系统中,某个热点数据过期或失效时,同时有大量的请求访问该数据,导致请求直接访问数据库或后端服务,给数据库或后端服务造成巨大压力,导致系统性能下降甚至崩溃的现象。
    • 设置热点数据永不过期或过期时间较长:
      • 对于一些热点数据,可以将其设置为永不过期,或者设置一个较长的过期时间,确保热点数据在缓存中可用,减少因为过期而触发的缓存击穿。
    • 加互斥锁或分布式锁:
      • 在访问热点数据时,可以引入互斥锁或分布式锁,保证只有一个线程去访问后端服务或数据库,其他线程等待结果。当第一个线程获取到数据后,其他线程可以直接从缓存获取,避免多个线程同时访问后端服务,减轻压力。
    • 限制并发访问:
      • 通过限制并发访问热点数据的请求量,可以控制请求的流量,避免过多请求同时访问热点数据。
  • 分库分表

    • 垂直拆分:
      • 把相关性强的,带join可能得放到同一个库中
    • 水平拆分:
      • 按照某一个外键id进行拆分,同一个用户的交易记录放到一个表中
      • 可以用create_time进行拆分,历史数据即使有进行扩容,也不会需求迁移等
  • Java 线程池中 submit() 和 execute()方法有什么区别?

    • 提交方式
      • submit()方法是定义在ExecutorService接口中的,它允许开发人员提交一个Callable或Runnable对象给线程池来执行,返回一个Future对象,可以用于检索结果或取消任务。
      • execute()方法是定义在Executor接口中的,只接收Runnable对象,并且没有返回类型。简单来说,submit()方法更加灵活,可以处理带返回值的任务,而execute()只能处理不带返回值的任务。
    • 异常处理
      • 使用submit()方法时,该异常会被包装在一个ExecutionException中并重新抛出。因此,在使用该方法时,开发人员必须捕获ExecutionException或声明它可能抛出。
      • 使用execute()方法时,异常将不会被重新抛出。这使得异常处理变得更加困难,因为开发人员必须自己处理异常。
    • 队列策略
      • 线程池通常会使用队列来保存已提交但未处理的任务。线程池如何使用这个队列,被称为队列策略。通过submit()方法提交的任务,会被添加到阻塞队列中,并保留之前提交的任务执行顺序。而对于execute()方法提交的任务,将会被添加到队列的尾部。这意味着队列中的第一个任务是最早的任务并且先被执行。
    • 任务的处理过程与方式
      • submit()方法在处理任务时,将任务交由一个线程池中的工作线程去处理,而另一个线程(可能是主线程)可以继续做其他事情。负责处理submit()方法提交的任务的线程,当任务结束后会自动返回给线程池并等待下一个任务,从而避免了重复创建和销毁线程的开销。
      • execute()方法在处理任务时,它的任务直接在调用execute()方法的调用线程(通常是主线程)中运行,如果当前没有可用线程,则会立即创建新的线程来处理该任务,并在完成任务后销毁线程。
    • 消息传递方式
      • submit()方法中提交的任务可以通过Future对象获取执行结果,开发人员可以使用该对象等待线程池中对应的任务完成,并获取其返回值;
      • execute()方法则没有提供返回值或者其他机制来获取任务的执行情况,因此即便一个任务执行失败了,开发人员也无法了解到在哪里以及什么地方出现了问题。
  • MyBatisa 延迟加载

    • 延迟加载也称为 懒加载只、惰性加载,使用延迟加载可以提高呈序的运行效率,针对数据持久层的操作,在某些特定查询的情况下去访问特定的数据库,在其他口情况下可以不访问某些数据表,尽减少 SQL的执行,从而达到提高速度的目的,是对数据库操作的一种优化。
    • 说明:延迟加载只存在于数据表的级联查询中,单表查询没延迟加载的功能。
    • 具体的业务场景:图片描述
  • nacos相关

    • 动态刷新
      • 配置存储与监听: Nacos Server作为配置中心,负责存储所有配置信息。当应用启动并配置了Nacos Config客户端后,客户端会连接到Nacos Server并根据配置的dataId和group订阅相应的配置。

      • @NacosPropertySource与@NacosValue注解: 在Spring Boot应用中,通过@NacosPropertySource注解可以指定要加载的配置源(dataId),同时通过autoRefreshed = true参数开启自动刷新功能。而@NacosValue注解则用于注入配置值到Bean的字段上,并可通过autoRefreshed = true使该值具备动态更新的能力。

      • 长轮询机制: Nacos客户端实现配置实时更新的一个关键技术是长轮询(Long Polling)。客户端定期向Nacos Server发送请求检查配置是否有更新,如果没有更新,服务器会保持连接不响应,直到有新的配置变更或达到超时时间。这种方式能有效减少网络请求次数,提高效率。

      • 配置变更推送: 当配置在Nacos Server端发生变更时,Nacos Server会立即通知所有订阅了该配置的客户端。客户端收到更新通知后,会立刻获取最新的配置并更新到本地环境,进而更新应用中的相关属性值。

      • 动态更新应用状态: 如示例代码所示,一旦配置值如useLocalCache发生变化,通过Nacos Value注入的属性值会自动更新,从而影响到应用的行为,比如从数据库读取数据的策略变化等。

    • 配置优先级
      • 图片描述
  • MySQL三大日志——binlog、redoLog、undoLog详解

    • redoLog
      • redo log是InnoDB存储引擎层的日志,又称重做日志文件,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。一个事务生成的redo日志是按顺序写入磁盘的,是顺序IO,在实例和介质失败(media failure)时,redo log文件就能派上用场,如数据库掉电,InnoDB存储引擎会使用redo log恢复到掉电前的时刻,以此来保证数据的完整性。
      • redo log包括两部分:一个是内存中的日志缓冲(redo log buffer),另一个是磁盘上的日志文件(redo log file)。mysql每执行一条DML语句,先将记录写入redo log buffer,后续某个时间点再一次性将多个操作记录写到redo log file。这种先写日志,再写磁盘的技术就是MySQL里经常说到的WAL(Write-Ahead Logging) 技术。
      • redo log实际上记录数据页的变更,而这种变更记录是没必要全部保存,因此redo log实现上采用了大小固定,循环写入的方式,当写到结尾时,会回到开头循环写日志。
    • binlog
      • binlog是属于MySQL Server层面的,又称为归档日志,属于逻辑日志,是以二进制的形式记录的,用于记录数据库执行的写入性操作(不包括查询)信息,依靠binlog是没有crash-safe能力的
      • binlog是通过追加的方式进行写入的,可以通过max_binlog_size参数设置每个binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
    • redolog和binlog区别
      • redo log是属于innoDB层面,binlog属于MySQL Server层面的,这样在数据库用别的存储引擎时可以达到一致性的要求。
      • redo log是物理日志,记录该数据页更新的内容;binlog是逻辑日志,记录的是这个更新语句的原始逻辑
      • redo log是循环写,日志空间大小固定;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
      • binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。
    • undo log
      • 主要记录了数据的逻辑变化,比如一条INSERT语句,对应一条DELETE的undo log,对于每个UPDATE语句,对应一条相反的UPDATE的undo log,这样在发生错误时,就能回滚到事务之前的数据状态。
      • 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读
  • Spring中Bean的五大作用域

    • Singleton(单例):默认的作用域
      • 在整个应用程序中只创建一个Bean实例。
      • 所有对该Bean的请求都将返回同一个实例。
      • Bean是全局共享的,适用于无状态的Bean或者需要在多个组件之间共享数据的情况。
    • Prototype(原型)
      • 每次对Bean的请求都会创建一个新的实例。
      • 没有共享状态,适用于有状态的Bean或者需要频繁创建新实例的情况。
    • Request(请求)
      • 在每个HTTP请求中创建一个新的Bean实例。
      • 每个请求的Bean实例对于该请求是唯一的。
      • 仅在Web应用程序的上下文中有效,适用于处理HTTP请求的控制器或服务。
    • Session(会话)
      • 在每个用户会话(Session)中创建一个新的Bean实例。
      • 对于同一用户的所有请求,都将使用相同的Bean实例。
      • 仅在Web应用程序的上下文中有效,适用于保存用户特定的数据或状态。
    • Global Session(全局会话)
      • 在整个应用程序的全局会话中创建一个新的Bean实例。
      • 仅在基于Portlet的Web应用程序中有效,通常与Portlet会话一起使用。
  • MyBatis 避免 SQL 注入的方法

    • 使用预编译语句(#{}),#{} 会被 MyBatis 转换为预编译的参数化查询
    • 避免直接使用 $ {},${} 是字符串替换,不会预编译,存在 SQL 注入风险
      • 如果必须使用 ${}(如表名、列名等动态内容),应该:
        • 使用白名单验证
        • 进行严格的输入过滤
        • 避免直接使用用户输入
    • 使用类型处理器(TypeHandler),为特殊数据类型实现 TypeHandler 可以确保数据安全转换
  • RocketMQ 消息的有序性

    • 可以实现严格有序的消息消费,但需要满足以下条件:
      • 单个消息队列(Queue):在同一个 Queue 内保证 FIFO(先进先出)顺序
      • 同一消息组(MessageGroup):对于顺序消息,相同 MessageGroup 的消息会被分配到同一个 Queue
        • Topic 有多个 Queue
        • 相同 MessageGroup/ShardingKey 的消息会进入同一 Queue
        • 不同 MessageGroup 之间无序,同一 Group 内有序
      • 同步发送:生产者使用同步发送模式(sync)
      • 顺序消费模式:消费者注册 MessageListenerOrderly
  • java 内存溢出排查指南

    • 获取内存快照
      • MAT (Memory Analyzer Tool):分析内存泄漏对象
      • VisualVM:实时监控内存使用
      • JProfiler:商业级分析工具
  • Java CPU 使用率过高排查指南

    • 使用 top 命令定位 Java 进程
    • 查看线程级 CPU 使用
    • 将线程 ID 转换为 16 进制
    • 根据线程id去寻找相关线程看具体情况
  • InnoDB 锁表情况详解

    • DDL 操作导致的锁表,表结构,创建索引等
    • 当 UPDATE/DELETE 语句无法使用索引时:
    • 大事务影响
      • 事务涉及表中大量数据(超过阈值)
      • 事务执行时间过长
    • 系统资源紧张
      • 当系统检测到严重资源竞争时可能自动升级锁
  • redis分布式锁怎么续期

    • 手动续期(简单但不可靠)
      • 在业务代码中定期(如每隔 TTL/3 时间)调用 PEXPIRE 命令重置锁的 TTL。
      • 缺点:如果客户端崩溃,续期逻辑停止,锁仍会过期。
    • 异步守护线程(看门狗机制)
      • Redisson 的实现:启动一个后台线程(看门狗,Watchdog),定期检查锁是否仍被持有,如果是则续期。
      • 默认续期间隔 = 锁 TTL 的 1/3(如 TTL=30s,则每 10s 续期一次)。
      • 如果客户端正常释放锁,看门狗线程终止;如果客户端崩溃,锁最终自动过期。
    • 基于 Lua 的原子续期
      • 使用 Lua 脚本保证续期操作的原子性(避免因客户端阻塞导致竞态条件)
  • rockmq消息丢失怎么处理,或者怎么预防消息丢失

    • RocketMQ 提供了相应的机制来确保消息不丢失,核心思想是:同步落盘 + 同步复制 + 确认机制。
      • 生产者端预防措施
        • 使用同步发送并检查结果:这是最基本也是最重要的要求。
        • 合理配置生产者参数。
          • retryTimesWhenSendFailed: 设置合理的同步发送重试次数(默认是 2)。
          • retryAnotherBrokerWhenNotStoreOK: 当发送失败时,是否尝试发送到其他 Broker(默认 false,可根据场景开启)。
      • Broker 端预防措施
        • 刷盘策略:同步刷盘 (flushDiskType = SYNC_FLUSH)
          • 生产者发送的消息,只有在被 Broker 成功刷写到磁盘后,才会向生产者返回成功 ACK。这样即使 Broker 宕机,消息也不会丢失。代价是性能大幅下降。
        • 复制方式:同步双写 (brokerRole = SYNC_MASTER)
          • 生产者发送的消息,只有在被 Broker 主节点成功同步到至少一个从节点后,才会向生产者返回成功 ACK。这样即使主节点磁盘损坏且无法恢复,从节点上也有一模一样的消息副本。代价是性能进一步下降,延迟更高
      • 消费者端预防措施
        • 使用可靠的消费模式:推荐使用 Push 模式,由 RocketMQ 客户端帮你管理偏移量,更简单可靠。
        • 只有在业务处理成功后才返回消费成功。
        • 监控消息堆积:在控制台上密切关注 Topic 的消息堆积量,如果发现堆积持续增长,及时排查消费端问题,防止因消息过期而被删除。
  • Mysql索引底层

    • B树
      • 非终端节点,存储了关键字和孩子节点的子树指针。

    • B+树
      • B+树的非终端阶段,关键字和指针数量一致。

      • B+树非终端节点,不存储数据,只存放索引信息,所以其内部节点相对于B树更小,如果把所有的内容节点,放到统一盘块中,能查找的数据范围更广,减少了io次数

  • Mysql事务隔离级别和每个级别出现的问题

    • 更新丢失:事务1在更新数据,事务2也在更新相同的数据并提交,事务1遇到异常进行回滚导致更丢失。
    • 脏读:READ UNCOMMITED 一个事务读到另一个事务未提交的数据->READ COMMITED 可以避免
    • 不可重复读:事务1修改值,事务2读出数据x,事务1提交,事务2读出数据y,x不等于y。->REPEATABLE READ 可以避免
    • 幻读:事务1执行当前读操作,事务2插入一条数据,事务1再执行一次读操作结果集跟前一次不一样。->SERIALIZABLE 可以避免
  • 线程池是如果运行的,还有拒绝策略

    • 线程池的执行流程是:先判断当前线程数是否大于核心线程数?如果结果为 false,则新建线程并执行任务;如果结果为 true,则判断任务队列是否已满?如果结果为 false,则把任务添加到任务队列中等待线程执行,否则则判断当前线程数量是否超过最大线程数?如果结果为 false,则新建线程执行此任务,否则将执行线程池的拒绝策略
    • 当任务过多且线程池的任务队列已满时,此时就会执行线程池的拒绝策略,线程池的拒绝策略默认有以下 4 种:
      • AbortPolicy:中止策略,线程池会抛出异常并中止执行此任务
      • CallerRunsPolicy:把任务交给添加此任务的(main)线程来执行
      • DiscardPolicy:忽略此任务,忽略最新的一个任务;
      • DiscardOldestPolicy:忽略最早的任务,最先加入队列的任务。
      • 还可以实现通过 new RejectedExecutionHandler,并重写 rejectedExecution 方法来实现自定义拒绝策略
  • ConcurrentHashMap如何实现线程安全

    • 1.7
      • 在 JDK 1.7 中它使用的是数组加链表的形式实现的,而数组又分为:大数组 Segment 和小数组 HashEntry。**大数组 Segment 可以理解为 MySQL 中的数据库,而每个数据库(Segment)中又有很多张表 HashEntry,每个 HashEntry 中又有多条数据,这些数据是用链表连接的。
      • Segment 本身是基于 ReentrantLock 实现的加锁和释放锁的操作,这样就能保证多个线程同时访问 ConcurrentHashMap 时,同一时间只有一个线程能操作相应的节点,这样就保证了 ConcurrentHashMap 的线程安全了。也就是说 ConcurrentHashMap 的线程安全是建立在 Segment 加锁的基础上的,所以我们把它称之为分段锁或片段锁
    • 1.8
      • 1.8 则使用了数组 + 链表/红黑树的方式优化了 ConcurrentHashMap 的实现
      • 在 JDK 1.8 中 ConcurrentHashMap 使用的是 CAS + volatile 或 synchronized 的方式来保证线程安全的
      • 添加元素时首先会判断容器是否为空,如果为空则使用 volatile 加 CAS 来初始化。
      • 如果容器不为空则根据存储的元素计算该位置是否为空,如果为空则利用 CAS 设置该节点;如果不为空则使用 synchronize 加锁,遍历桶中的数据,替换或新增节点到桶中,最后再判断是否需要转为红黑树,这样就能保证并发访问时的线程安全了。
  • volatile底层是如何实现的

    • volatile 关键字在底层的实现主要是通过内存屏障(memory barrier)来实现的。内存屏障是一种 CPU 指令,用于强制执行 CPU 的内部缓存与主内存之间的数据同步。
    • 在 Java 中,当线程读取一个 volatile 变量时,会从主内存中读取变量的最新值,并把它存储到线程的工作内存中。当线程写入一个 volatile 变量时,会把变量的值写入到线程的工作内存中,并强制将这个值刷新到主内存中。这样就保证了 volatile 变量的可见性和有序性。
    • 在有内存屏障的地方,会禁止指令重排序,即屏障下面的代码不能跟屏障上面的代码交换执行顺序。在有内存屏障的地方,线程修改完共享变量以后会马上把该变量从本地内存写回到主内存,并且让其他线程本地内存中该变量副本失效
  • AQS

    • AQS 的核心思想是利用一个双向队列来保存等待锁的线程,同时利用一个 state 变量来表示锁的状态。AQS 的同步器可以分为独占模式和共享模式两种。独占模式是指同一时刻只允许一个线程获取锁,常见的实现类有 ReentrantLock;共享模式是指同一时刻允许多个线程同时获取锁,常见的实现类有 Semaphore、CountDownLatch、CyclicBarrier 等。
    • 独占模式:AQS 维护了一个同步队列,该队列中保存了所有等待获取锁的线程。当一个线程尝试获取锁时,如果锁已经被其他线程持有,则将该线程加入到同步队列的尾部,并挂起线程,等待锁被释放。当锁被释放时,从同步队列中取出一个线程,使其获取锁,同时将它从队列中移除,唤醒该线程继续执行。
      • 独占模式又分为公平锁和非公平锁:
        • 公平锁:按照线程在队列中的排队顺序,先到者先拿到锁;
        • 非公平锁:当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的。
    • 共享模式:AQS 维护了一个等待队列和一个共享计数器。共享计数器表示当前允许获取锁的线程数,当一个线程尝试获取锁时,如果当前允许获取锁的线程数已经达到了最大值,则将该线程加入到等待队列中,并挂起线程,等待其他线程释放锁或者共享计数器增加。当锁被释放时,会从等待队列中取出一个线程,使其获取锁,同时将它从队列中移除,唤醒该线程继续执行。
  • 聚簇索引和非聚簇索引的区别

    • 聚簇索引(Clustered Index)也被称为聚集索引,在 InnoDB 存储引擎中,每个表只能有一个聚集索引,其余的索引都是非聚集索引(也称为二级索引)。
    • 聚集索引
      • 聚集索引是按照数据在磁盘上的物理顺序来组织数据的,其叶子节点保存着完整的数据行信息。InnoDB 中,如果表定义了主键,则主键索引是聚集索引;如果表没有定义主键,则第一个唯一非空索引是聚集索引;如果都没有,则 InnoDB 会隐式创建一个隐藏的聚集索引
    • 非聚簇索引
      • 非聚集索引也叫二级索引,其叶子节点保存着索引字段和指向对应数据行的指针(相当于主键 ID),通过这个指针可以找到对应的数据行。在查询中,如果使用的是非聚集索引,则需要先根据索引查找到对应的行指针,再通过行指针查找数据行,这个过程叫做回表查询,因此他的查询速度相对于聚集索引要慢一些。
    • 聚簇索引和非聚簇索引的区别主要有以下几点:
      • 存储数据不同:聚簇索引将数据行存储在与索引相同的 B+ 树结构中,而非聚簇索引是将索引和主键 ID 存储在 B+ 树结构中;
      • 数量限制不同:一张表只能有一个聚簇索引,但可以有多个非聚簇索引;
      • 索引更新不同:由于聚簇索引中的数据行与索引行是一一对应的,因此对于聚簇索引的任何更新都需要重新排列数据行的物理顺序。这可能会导致性能问题,特别是在高并发环境中,而非聚簇索引的更新不需要重新排列数据行的物理顺序,因为索引和数据行是分开存储的;
      • 索引大小不同:由于聚簇索引中的数据行与索引行是一一对应的,因此聚簇索引的大小通常比非聚簇索引大,而非聚簇索引通常比较小,因为它们只存储索引不存储数据行;
      • 范围查询不同:聚簇索引中的数据行与索引行是一一对应的,因此聚簇索引通常比非聚簇索引更适合范围查询,而非聚簇索引需要进行两次查找:首先查找索引,然后查找数据行,这可能会导致性能问题,特别是在大型表上进行范围查询时。
  • 为什么redis运行比较快

    • 数据存储在内存中:Redis 的数据存储在内存中,而内存的读写速度远远快于硬盘。这使得 Redis 能够实现非常快速的读写操作。
    • 单线程处理请求:Redis 是单线程的,因此可以避免线程切换和锁竞争等问题,提高了 CPU 的利用率和性能。
    • 高效的数据结构:Redis 提供了多种高效的数据结构,如哈希表、有序集合等,这些数据结构能够快速地进行插入、删除、查找和排序等操作。
    • 异步 I/O:Redis 使用异步 I/O 技术,可以在等待客户端输入或输出时继续处理其他请求,从而提高了系统的吞吐量。
    • 高效的持久化机制:Redis 提供了多种持久化机制,如 RDB、AOF 和混合持久化机制,这些机制运行都非常高效,可以在不影响性能的情况下保证数据的安全。
  • spring事务传播机制

    • REQUIRED(默认传播行为):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
    • SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
    • MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
    • REQUIRESNEW:创建一个新的事务,如果当前存在事务,则挂起该事务。
    • NOTSUPPORTED:以非事务方式执行操作,如果当前存在事务,则挂起该事务。
    • NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。
    • NESTED:如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则创建一个新的事务。
  • 雪花算法

    • 符号位:最高位是符号位,始终为 0,1 表示负数,0 表示正数,ID 都是正整数,所以固定为 0。
    • 时间戳部分:由 41 位组成,精确到毫秒级。可以使用该 41 位表示的时间戳来表示的时间可以使用 69 年。
    • 节点 ID 部分:由 10 位组成,用于表示机器节点的唯一标识符。在同一毫秒内,不同的节点生成的 ID 会有所不同。
    • 序列号部分:由 12 位组成,用于标识同一毫秒内生成的不同 ID 序列。在同一毫秒内,可以生成 4096 个不同的 ID。
  • 线程池

    • 核心参数
      • corePoolSize:核心线程数量
      • maximumPoolSize:线程不够用时能够创建的最大线程数
      • workQueue:任务等待队列(当任务提交时,如果线程池中的线程数量如果大于等于corePoolSize,会将该任务封装成一个Worker对象,放入到workQueue中)
      • keepAliveTime:空闲线程存活时间
      • threadFactory:创建新线程
      • handler:创建线程的工厂
    • 线程池的大小如何选定:
      • CPU密集型:线程数 = CPU核数或者核数 + 1
      • IO密集型:线程数 = CPU核数 * (1+平均等待时间/平均工作时间)
  • MongoDB 和 MySQL 对比

    • 选择 MySQL 当:
      • 你的数据是结构化的,且结构相对稳定。
      • 需要复杂的查询、报告和数据分析(SQL非常适合此场景)。
      • 需要多行、跨表的强事务一致性(如银行交易系统、库存管理系统)。
    • 选择 MongoDB 当:
      • 你的数据是非结构化或半结构化的,或者结构经常变化。
      • 你需要快速迭代和开发,不希望被固定的 Schema 束缚。
      • 应用需要高性能和高可扩展性来处理海量数据(如社交平台、物联网应用)。
      • 数据模型是面向对象的,并且嵌套的数据结构可以直接映射到文档模型,从而减少代码的复杂性。
  • CAP 理论

    • 一致性(Consistency):在分布式系统中的多个副本或节点之间,保持数据的一致性。也就是说,如果有多个客户端并发地读取数据,在任何时间点上,它们都应该能够观察到相同的数据。
    • 可用性(Availability):系统在任何时间点都能正常响应用户请求,即系统对外提供服务的能力。如果一个系统不能提供响应或响应时间过长,则认为系统不可用。
    • 分区容忍性(Partition tolerance):指系统在遇到网络分区或节点失效的情况下,仍能够继续工作并保持数据的一致性和可用性。
    • Redis 的设计选择使其在 CAP 理论中主要符合 CP 系统。
      • Redis 在默认的单实例模式或使用哨兵(Sentinel)进行主从故障转移时,其设计优先考虑强一致性。
      • 当发生网络分区时,如果 Redis 集群无法保证数据的一致性(例如,主节点和大多数从节点失去了联系),它会选择牺牲可用性(A):
點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
JAVA開發工程師
手記
粉絲
2
獲贊與收藏
0

關注作者,訂閱最新文章

閱讀免費教程

  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消