1,773 Matching Annotations
  1. Aug 2022
    1. HashSet 基于 HashMap,数据结构是哈希表。所以,HashSet 的 contains 方法,其实就是根据 hashcode 和 equals 去判断相等的

      现在也有红黑树

    1. HttpServletRequestWrapper
    2. 异常操作是一个非常耗费性能的操作
    3. 使用 addSuppressed 方法把 finally 中的异常附加到主异常上
    4. 把原始异常作为转换后新异常的 cause,原始异常信息同样不会丢
    5. 我不建议在框架层面进行异常的自动、统一处理,尤其不要随意捕获异常。但,框架可以做兜底工作
    6. 可能需要在异常后转入分支业务流程
    7. 不在业务代码层面考虑异常处理,仅在框架层面粗犷捕获和处理异常
    8. Controller 层往往会给予用户友好提示,或是根据每一个 API 的异常表返回指定的异常类型,同样无法对所有异常一视同仁
    9. MyBatis @Column注解的updateIfNull属性,可以控制,当对应的列value为null时,updateIfNull的true和false可以控制

      mybatis-plus有fieldStrategy

    10. 使用 =NULL 并没有查询到 id=1 的记录,查询条件失效
    11. ConcurrentModificationException
    12. List.subList 返回的子 List 不是一个普通的 ArrayList。这个子 List 可以认为是原始 List 的视图,会和原始 List 相互影响
    13. 如果使用 Java8 以上版本可以使用 Arrays.stream 方法来转换,否则可以把 int 数组声明为包装类型 Integer 数组:
    1. 比较更新要使用的实体类中的字段值与从数据库中查询出来的字段值,判断其是否有修改
    2. 使用@DynamicUpdate性能会好一些。因为不使用@DynamicUpdate时,即使没有改变的字段也会被更新
    1. 如果我们希望只比较 BigDecimal 的 value,可以使用 compareTo 方法
    2. BigDecimal 有 scale 和 precision 的概念,scale 表示小数点右边的位数,而 precision 表示精度,也就是有效数字的长度
    3. 使用 BigDecimal 表示和计算浮点数,且务必使用字符串的构造方法来初始化 BigDecimal

      或者用valueOf

    1. 对于自定义的类型,如果要实现 Comparable,请记得 equals、hashCode、compareTo 三者逻辑一致。
    2. XX:AutoBoxCacheMax=1000
    3. 进行判等,需要使用 equals 进行内容判等。因为引用类型的直接值是指针,使用 == 的话,比较的是指针,也就是两个对象在内存中的地址,即比较它们是不是同一个对象,而不是比较对象的内容。

      默认情况

    4. getClass获得类型信息采用==来进行检查是否相等的操作是严格的判断。不会存在继承方面的考虑
    5. 那么查询索引本身已经“覆盖”了需要的数据,不再需要回表查询。因此,这种情况也叫作索引覆盖

      extra中显示:use index,不是user index condition,也不是null

    6. Controller 里出现了一个 UnexpectedRollbackException,异常描述提示最终这个事务回滚了,而且是静默回滚的异常描述提示最终这个事务回滚了,而且是静默回滚的
    7. Transactional

      是spring的tranactional,而不是javax的

    8. 也是坑点二,如果要配置 Feign 的读取超时,就必须同时配置连接超时,才能生效

      有可能已经修复

    9. 否则由定时任务调用外部查询接口查询交易结果,然后根据查到的结果补偿本地状态

      外部接口一般可以回调

    10. 发送数据到服务端,因此写入操作可以任务是自己本地的操作,本地操作是不需要什么超时时间的,如果真的有什么异常,那也是连接(TCP)不上,或者超时的问题,连接超时和读取超时就能覆盖这种场景
    11. 等到count个任务全部执行完毕
    12. 也就是同一个主机 / 域名的最大并发请求数为 2。我们的爬虫需要 10 个并发,显然是默认值太小限制了爬虫的效率
    13. 是服务端处理业务逻辑的时间
    14. 只要服务端收到了请求,网络层面的超时和断开便不会影响服务端的执行
    1. 沈寅就把街道取名为“易赖街”,即容易耍赖皮
    1. 校验又是如何触发的

      通过拦截器触发,使用max和min校验器

    2. Body 对象已经是一个解析过的对象,而不再是一个流了
    1. equest.getParameterValues(name)",返回的是一个 String 数组,最终给上层调用者返回的是单个 String(如果只有一个元素时)或者 String 数组
    1. 不会还是没解决我们说的一致性问题。如果在3、4之间插入了 Session B的逻辑呢
    2. C会同时查询表t的总行数

      C没有事务

    3. 可见的行才能够用于计算“基于这个查询”的表的总行数。
    1. 这就最大程度地减少了事务之间的锁等待,提升了并发度
    2. 在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议

      select ... for update是在读的时候加悲观锁

    3. 最可能造成锁冲突、最可能影响并发度的锁的申请时机尽量往后放
    1. 知道幻读都是发生在insert之后的, 我们回到假设1当中, 可以看到事务3插入了一条新的数据
    1. LSN

      Log sequence number

    2. 这时候系统会停止所有更新操作,把checkpoint往前推进
    3. 把innodb_flush_neighbors的值设置成0。因为这时候IOPS往往不是瓶颈,而“只刷自己”,就能更快地执行完必要的刷脏页操作,减少SQL语句响应时间
    1. 普通索引和change buffer的配合使用,对于数据量大的表的更新优化还是很明显的
    2. 对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时change buffer的使用效果最好。这种业务模型常见的就是账单类、日志类的系统
    1. select还是旧值
    2. 如果A、B同时喜欢对方,会出现不会成为好友的问题。因为上面第1步,双方都没喜欢对方。第1步即使使用了排他锁也不行,因为记录不存在,行锁无法生效。请问这种情况,在mysql锁层面有没有办法处理

      解决办法

      分两步走: 1. 如果是A喜欢B,应该是先执行插入,然后提交, 1. 然后再去查询B是否喜欢A,如果喜欢,则往friend表里插一条数据。

    3. version被其他事务抢先更新

      version拿到最新的当前值

    4. 事务B是当前读,必须要读最新版本,而且必须加锁,因此就被锁住了,必须等到事务C’释放这个锁,才能继续它的当前读。
    5. 版本已提交,而且是在视图创建前提交的
    1. 为了防止子线程伪唤醒(spurious wakeup),只要子线程没有TERMINATED的,父线程就需要继续等下去

      当前线程对象死亡时,其相关的锁也会被唤醒

    1. 事务自动开启、提交或回滚,比如insert、update、delete语句,事务的开启、提交或回滚由mysql内部自动控制的
    1. 事务传播行为是指声明式事务中,在一个事务方法中调用另一个事务方法,另一个事务方法的事务行为,加入现有事务、使用新的事务还是其他的行为

      事务传播行为

    1. connection-timeout

      获取连接超时

    2. 虽然使用 newFixedThreadPool 可以把工作线程控制在固定的数量上,但任务队列是无界的。如果任务较多并且执行较慢的话,队列可能会快速积压,撑爆内存导致 OOM

      默认策略是先塞满队列

    3. 由于线程池在工作队列满了无法入队的情况下会扩容线程池,那么我们是否可以重写队列的 offer 方法,造成这个队列已满的假象呢?

      默认情况下,先塞满队列,再扩容线程池。

      线程池不满时,queue直接拒绝,这样就可以让线程池扩容

      https://github.com/apache/tomcat/blob/a801409b37294c3f3dd5590453fb9580d7e33af2/java/org/apache/tomcat/util/threads/TaskQueue.java

    4. 对于执行比较慢、数量不大的 IO 任务,或许要考虑更多的线程数,而不需要太大的队列。
    5. 换句话说线程在跑

      线程是gc root,然后线程又是引用了外部的线程池,只要线程不被回收(核心线程在allowCoreThreadTimeOut为false的情况下不会被回收),那么线程池也不会被回收。

    6. 可以想想tomcat为什么觉得这样激进的线程更适合
    7. 扩容线程池

      当队列满的时候才会去扩容线程池

    8. 由于线程池在工作队列满了无法入队的情况下会扩容线程池,那么我们是否可以重写队列的 offer 方法,造成这个队列已满的假象呢?
      1. 默认情况下,先塞满队列,再扩容线程池。
      2. 线程池不满时,queue直接拒绝,这样就可以让线程池扩容

      https://github.com/apache/tomcat/blob/a801409b37294c3f3dd5590453fb9580d7e33af2/java/org/apache/tomcat/util/threads/TaskQueue.java

    9. firstTask

      firstTask默认不入队列

    10. 由于我们 Hack 了队列,在达到了最大线程后势必会触发拒绝策略,那么能否实现一个自定义的拒绝策略处理程序,这个时候再把任务真正插入队列呢
    11. 线程在跑

      线程是gc root,然后线程又是引用了外部的线程池,只要线程不被回收(核心线程在allowCoreThreadTimeOut为false的情况下不会被回收),那么线程池也不会被回收。

    12. 队列来做缓冲。

      类似消息队列

    13. 对于执行比较慢、数量不大的 IO 任务,或许要考虑更多的线程数,而不需要太大的队列。
    14. 每秒输出一次线程池的基本内部信息

      可以用在caffeine的缓存监控中

    15. 任何时候,都应该为自定义线程池指定有意义的名称,以方便排查问题
    16. 禁止使用这些方法来创建线程池,而应该手动 new ThreadPoolExecutor 来创建线程池
    17. 然后遍历购物车中的商品依次尝试获得商品的锁,最长等待 10 秒

      本地测试最小可以到毫秒

    18. Comparator.comparing(Item::getName)

      .reversed()

    19. 如果这个变量不是 volatile 修饰的,子线程可以退出吗?你能否解释其中的原因呢?

      不会,可能无限循环下去,因为编译器可能会优化这个循环

    20. tem.lock.tryLock(10, TimeUnit.SECONDS)

      这里避免了长时间死锁

    21. 查看抓取出的线程栈,在页面中部可以看到如下日志:

    22. Object 类型的静态字段,在操作 counter 之前对这个字段加锁

      锁必然是唯一的

    23. 只能确保多个线程无法执行同一个实例的 wrong 方法,却不能保证不会执行不同实例的 wrong 方法
    1. 我们的监听器监听的体系是另外一套

      这个事件监听器的初始化早于一般的bean

    2. ,修正起来也就简单了。假设不允许我们去拆分类,我们可以按照下面的思路来修改:

      还可以使用order机制

    3. 它的核心就是通过一个 ThreadLocal 来将 Proxy 和线程绑定起来,这样就可以随时拿出当前线程绑定的 Proxy

      当前proxy必然是所调用方法所对应的对象实例(代理)

    4. @Autowired

      需要lazy注解

    5. Disposable 方法的注册

      用于缓存spring的解构者

    6. doCreateBean 管理了 Bean 的整个生命周期中几乎所有的关键节点
    7. @Component(Service 也是一种 Component)将当前类自动注入到 Spring 容器时,shutdown 方法则不会被自动执行
    8. 当使用收集装配方式来装配时,能找到任何一个对应的 Bean,则返回,如果一个都没有找到,才会采用直接装配的方式
    9. @Value 没有注入预期的值
    10. 寻找不到对应的 Bean,一定会如案例 2 那样直接报错

      集合、数组不会

    11. CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor
    12. 根据参数来寻找对应的 Bean

      寻找的优化: 1. 事先扫描构建bean的索引(并不实际构建bean) 1. 当需要找个bean的时候,再去构建bean

    1. a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

      -1,前者小于后者 0,等于 1,前者大于后者

    1. 因为无需默认构造函数就可以反射生成对象,这个属性在很多的序列框架可以使用,比如 xml 转换成 bean
    1. I came across the same error when trying to deploy a Spring Boot 2 application to Wildfly 13. This is the only Stack Overflow question that came up when I was searching for answers, so I thought I'd leave my findings here in case anyone else has the same issue, because my solution was very different from the only other answer here right now.
    1. 事务中的MDL锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。

      mdl只有在事务之后才会释放

    2. 比较理想的机制是,在alter table语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到MDL写锁最好,拿不到也不要阻塞后面的业务语句,先放弃

      等待

    3. 使用参数–single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于MVCC的支持,这个过程中数据是可以正常更新的。
    1. 线程池中线程的回收依赖JVM自动的回收,线程池做的工作是根据当前线程池的状态维护一定数量的线程引用,防止这部分线程被JVM回收,当线程池决定哪些线程需要回收时,只需要将其引用消除即可
    1. API网关、防火墙、路由器等流量入口的服务器,要对流量做密集计算、校验、转发,CPU不强那肯定是不行的
    2. 绝大部分场景,内存才是限制系统性能的主要因素,而cpu一般都是性能过剩
    1. 没有写入时,多个线程允许同时读(提高性能)

      写入时,还是不允许读的

    1. 实例设置到静态变量中,在多线程情况下重用呢?

      不能,这样除了主线程,其他线程的seed都是同一个值

    2. 会根据用每个线程的 thread 的一个实例字段 threadLocalRandomProbe 是否为 0 来判断是否当前线程实例是否为第一次调用随机数生成方法,从而决定是否要给当前线程初始化一个随机的 threadLocalRandomSeed 种子值

      current()会初始化一个随机的种子,而跳过了,就只能用一个固定的值

    3. 而 PIA 是插入 KV 对后,返回 null 值

    4. 都会用 Arrays.copyOf 创建一个新数组,频繁 add 时内存的申请释放消耗会很大
    5. max-threads=1

      现在是: server: tomcat: threads: max: 1

    1. alter table T engine=InnoDB
    2. 第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的
    1. 乐观锁为理论基础的MVCC(多版本并发控制)

      错误,乐观锁是写写控制,MVCC是写读控制

    2. 使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据

      亦可使用乐观锁

    3. 幻读是读取了其他事务新增的数据,针对insert和delete操作

      可重复读

    1. 恢复目标时间
    2. select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
    3. 就是当系统里没有比这个回滚日志更早的read-view的时候

      疑惑点

    4. MySQL的隔离级别设置为“读提交

      mysql默认是可重复读

    5. 创建一个视图
    6. 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的

      非所有数据,而是所读取行

    7. 幻读(phantom read)

      又是可重复读

    1. 感觉oracle的DG就诞生了,物理的速度也将远超逻辑的,毕竟只记录了改动向量
    2. redo log和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致

      如果中间出现事故,mysql会做相应处理两阶段提交

    1. 会去比较redolog中的内容和binlog中的内容。如果发现像上面这种情况,也会认为是成功的,因为binlog已经记录,只是差redolog中的一个commit状态没有修改成功
    1. RabbitMQ版可用于单体应用被拆解为微服务后不同微服务间的通信
      1. 接受券核销、购买信息(异步解耦、削峰填谷)
      2. 用户注册信息(异步解耦)
      3. 推送数据给ES(缓存同步)
      4. 分销活动,用户购买订单号+券id的最终一致性
      5. 延时队列,异步(取消订单)
    2. BasicRecover

      重放unack的消息

    3. 消息重试

      服务器端重试机制

    1. 无平台维护消息发送方、消费方的关联信息,多个版本迭代后无法确定对接方;

      APM

    2. 镜像队列的方式保证消息在集群的可靠

      集群

    1. 在表和字段上强制执行的数据检验规则,为了防止不规范的数据进入数据库

      有可能有重复数据进入

    1. Interface ApplicationContextAware 和 InitializingBean来获取我们在Configuration class中声明的exchange, queue, binding beans并调用channel的相应方法来声明

      源码分析

    1. 表示当前Exchange是RabbitMQ内部使用,用户所创建的Queue不会消费该类型交换机下的消息,既然是为了RabbitMQ系统所用,作为用户,我们就没有必要创建该类型的Exchange,当然默认也是选择No

      系统使用

    1. retry只能在自动ack模式下使用。如果一定要在手动ack模式下使用retry功能,需保证消息能在有限次重试过程中可以重试成功,否则超过重试次数,又没办法执行ack或者nack,消息就会一直处于unack,并不会转发到死信队列

      manul模式下重试可能还有bug:

      recover与manual模式也有关系(是否是bug、按理manul不能被自动ack/reject

      重试机制下: 1. 默认情况,manual模式的消息会最终处于unack状态; 1. ImmediateRequeueMessageRecoverer,manual消息会被重新requeue; 1. RejectAndDontRequeueRecoverer,manual模式的消息会最终处于unack状态;

    1. Wait Time设为大于0的值,即Long Polling

      长轮询

    2. Queue中的一条Message被Receiver接收后,将在一段时间内变为不可见

      rabbitmq的unack状态 即不被其他消费者看见的时间段

    1. 跟rabbitmq比的优势:

      1. 消息回溯
      2. 有push/pull模型
      3. 简化了direct、topic模式(可以只有topic,没有queue)
      4. raft优化,可用性提高
      5. 性能优化
      6. 有可见性概念、简化了消费者确认模型
      7. 可以批量处理
    2. 可从队列删除 Message A,以避免一旦取出消息隐藏时长过期后该消息被再次接受并处理

      需要主动删除消息

    3. 建议消费者在 visibilityTimeout 时间内消费成功后需要调用(batch)DeleteMessage 接口删除该消息,否则该消息将会重新变成为 active 状态,此消息又可被消费者重新消费,保证消息至少消费一次,但是不能保证幂等性, 业务侧需要有去重逻辑。

      消费者需要delete,不然可能会出现重新消费

    4. 当其被取走后在 VisibilityTimeout 的时间内状态为 Inactive,若超过 VisibilityTimeout 时间后消息还未被删除,消息会重新变成 Active 状态

      相当于可以从unack自动变成ready状态

    5. 避免失败回滚和频繁轮询数据库等传统方式的弊端。

      最终一致性

    1. 跟rabbitmq比的优势:

      1. 消息回溯
      2. 有push/pull模型
      3. 简化了direct、topic模式(可以只有topic,没有queue)
      4. raft优化,可用性提高
      5. 性能优化
      6. 有可见性概念
    2. 您可以将消费过的去重 key 缓存(如 KV 等),然后每次消费时检查去重 key 是否已消费过。去重 key 缓存可以根据消息最大有效时间来淘汰。CMQ 提供了队列当前最小未消费消息的时间(min_msg_time),您可以使用该时间和业务生产消息最大重试时间来确定缓存淘汰时间。存在多个消费者时,去重 key 缓存就需要是分布式的

      分布式缓存的最佳实践