技术知识随记

静态内部类有什么用?

静态内部类可以封装一些只在方法内部使用的逻辑,提高代码的封装性和安全性。
静态内部类的对象不依赖于外部类的对象。

什么是抽象工厂模式?

工厂模式将对象的创建和使用分开。
抽象工厂模式体现为定义一个抽象工厂类,多个不同的具体工厂继承这个抽象工厂类。
对于不同产品系列有比较多共性特征时,可以使用抽象工厂模式,有助于提升组件的复用性。

Spring AOP与拦截器的区别

1、作用层面
拦截器只对action负责,作用层面一般位于Controller层。
Spring AOP主要是拦截对Spring管理的Bean的访问,一般作用与Service层。
2、联系与区别
联系:
Spring AOP和拦截器一样,都是AOP实现方式的一种,均使用代理模式实现。
区别:
1、拦截器和过滤器有点相似,是链式的处理模式,这样有一个缺点就是,每次请求,都会访问action的上下文,不够灵活。
2、Spring AOP的注解有@Before、@After、@AfterReturning、@AfterThrowing、@Around,可以更灵活的配置要监听处理的Bean。

数据库事务有哪些?

原子性,一致性,隔离性,持久性。

事务的隔离性级别

串行化,可重复读,读已提交,未提交读

sync和lock的区别

  1. sync是一个关键字,lock是一个接口。
  2. sync可以锁代码块,也可以锁方法,而lock只能锁代码块。
  3. lock提供的有trylock方法,通过trylock可以中断锁。
  4. lock提供有读写锁,读读不互斥,从而提高了读的效率,读写,写写互斥。
  5. sync是非公平锁,而lock支持公平锁和非公平锁。
  6. sync不需要手动释放锁,而lock需要手工释放锁。

spring的作用域

1、singleton作用域
2、prototype作用域
3、request作用域
4、session作用域
5、globalSession作用域

IOC(控制反转)与依赖注入的原理

  • (1)基本原理其实就是通过反射解析类及其类的各种信息,包括构造器、方法及其参数,属性。然后将其封装成bean定义信息类、constructor信息类、method信息类、property信息类,最终放在一个map里,也就是所谓的container,池等等,其实就是个map。

  • (2)当你写好配置文件,启动项目后,框架会先按照你的配置文件找到那个要scan的包,然后解析包里面的所有类,找到所有含有@bean,@service等注解的类,利用反射解析它们,包括解析构造器,方法,属性等等,然后封装成各种信息类放到一个map里。每当你需要一个bean的时候,框架就会从container找是不是有这个类的定义?如果找到则通过构造器new出来(这就是控制反转,不用你new,框架帮你new),再在这个类找是不是有要注入的属性或者方法,比如标有@autowired的属性,如果有则还是到container找对应的解析类,new出对象,并通过之前解析出来的信息类找到setter方法,然后用该方法注入对象(这就是依赖注入)。

  • (3)如果其中有一个类container里没找到,则抛出异常,比如常见的spring无法找到该类定义,无法wire的异常。还有就是嵌套bean则用了一下递归,container会放到servletcontext里面,每次reQuest从servletcontext找这个container即可,不用多次解析类定义。如果bean的scope是singleton,则会重用这个bean不再重新创建,将这个bean放到一个map里,每次用都先从这个map里面找。如果scope是session,则该bean会放到session里面。

Spring 中的bean是否线程安全

Spring容器中的bean是否线程安全,容器本身并没有提供bean的线程安全策略,因此可以说spring容器中的bean本身不具备线程安全的特性,但是具体还是要结合具体scope的bean去研究。

对于原型bean,每次创建一个新对象,也就是线程之间并不存在bean共享,自然是不会有线程安全的问题。

对于单例bean,所有线程都共享一个单例实例bean,因此是存在资源的竞争。

如果单例bean是一个无状态bean,也就是线程中的操作不会对bean的成员执行查询以外的操作,那么这个单例bean是线程安全的。比如spring mvc的controller service dao等,这些bean大多是无状态的,只关注于方法本身。

  • 有状态就是有数据存储功能
  • 无状态就是不会保存数据

Springboot自动配置原理

@EnableAutoConfiguration 是 Spring Boot 最核心的注解,它能根据类路径下的 jar 包和配置动态加载配置和注入bean。
举个例子,比如我在 lib 下放一个 druid 连接池的 jar 包,然后在 application.yml 文件配置 druid 相关的参数,Spring Boot 就能够自动配置所有我们需要的东西,如果我把 jar 包拿掉或者把参数去掉,那 Spring Boot 就不会自动配置。这样我们就能把许多功能做成公共的自动配置的启动器(starters)。

简单的说 springboot 的自动装载机制就是通过配置@EnableAutoConfiguration 将配置为@Configuration下的@Bean方法加载到spring容器中,这个过程就是spring自动装载机制。

springboot自动配置功能是为了满足什么?
是为了满足其他的插件进行扩展,因为有很多外部的bean我们没法管理,也不知道具体包的路径,这个时候springboot提供了自动装配功能,让我们外部的类能够注入到spring项目中。

如果说这个是springboot的自动装配功能不如说是spring的自动装配功能。因为springboot使用了 spring3.1出来的importSelector 动态bean装载实现的自动装载机制,同时使用了 META-INF/spring.factories中的SPI机制实现了spring自动扫描到自动装载的bean机制。

Springboot 自动配置流程

  1. Spring Boot 在启动时除了扫描与启动类同一包下的组件之外,还会检查各个 jar 包中是否存在 META-INF/spring.factories 文件,为自动装配做准备。
  2. 第三方的 spring-boot-starter 会通过将自己的自动装配类写到 META-INF/spring.factories 中让 Spring Boot 加载到容器中,使自动装配类能够生效。
  3. 第三方的自动装配类会通过利用 @Conditional 系列注释保证自己能在各种环境中成功自动装配。

什么是 SPI机制

SPI的全名为Service Provider Interface。

简单的总结下java SPI机制的思想。我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。

java SPI就是提供这样的一个机制: 为某个接口寻找服务实现的机制。

Spring Boot中的SPI机制

在Spring中也有一种类似与Java SPI的加载机制。它在 META-INF/spring.factories 文件中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。

这种自定义的SPI机制是Spring Boot Starter实现的基础。

为什么不建议开发中使用UUID作为MySQL的主键?

uuid主键的插入
在这里插入图片描述
由于新行的主键不一定比前一个大,因此InnoDB不能总是把新行插入到索引的最后。它不得不为新行寻找合适的位置:通常在已有数据的中段,并且为它分配空间。这会导致大量的额外工作并且导致不优化的数据布局。主要缺点如下:

  • 目标页面也许会被刷写到磁盘上并且从缓存中移走,无论哪种情况,InnoDB都不得不在插入新行之前从磁盘上找到并读取它,这导致了大量的随机I/O。
  • InnoDB有时不得不进行分页,为新行开辟空间。这会导致移动大量数据。
  • 页面会因为分页而变得稀疏和不规则地被填充,因此最终的数据会有碎片。

spring事务机制

  • (一)什么是事务的传播?
    简单的理解就是多个事务方法相互调用时,事务如何在这些方法间传播。
    举个例子,方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。

  • (二)Spring中事务的默认实现使用的是AOP,也就是代理的方式,如果大家在使用代码测试时,同一个Service类中的方法相互调用需要使用注入的对象来调用,不要直接使用this.方法名来调用,this.方法名调用是对象内部方法调用,不会通过Spring代理,也就是事务不会起作用。

索引下推的好处

索引下推是MySQL 5.6引入的索引优化。

官方文档中给的例子和解释如下: people表中(zipcode,lastname,firstname)构成一个索引
SELECT * FROM people WHERE zipcode=‘95054’ AND lastname LIKE ‘%etrunia%’ AND address LIKE ‘%Main Street%’;如果没有使用索引下推技术,则MySQL会通过zipcode='95054’从存储引擎中查询对应的数据,返回到MySQL服务端,然后MySQL服务端基于lastname LIKE '%etrunia%'和address LIKE '%Main Street%'来判断数据是否符合条件。 如果使用了索引下推技术,则MYSQL首先会返回符合zipcode='95054’的索引,然后根据lastname LIKE '%etrunia%'和address LIKE '%Main Street%'来判断索引是否符合条件。如果符合条件,则根据该索引来定位对应的数据,如果不符合,则直接reject掉。

索引下推在非主键索引上的优化,可以有效减少回表的次数,大大提升了查询的效率。

join语句的优化原则

  1. 用小结果集驱动大结果集,将筛选结果小的表首先连接,再去连接结果集比较大的表,尽量减少join语句中的Nested Loop的循环总次数;
  2. 优先优化Nested Loop的内层循环(也就是最外层的Join连接),因为内层循环是循环中执行次数最多的,每次循环提升很小的性能都能在整个循环中提升很大的性能;
  3. 对被驱动表的join字段上建立索引。

索引失效的情况

  1. 查询条件中有or
  2. like查询是以’%'开头
  3. 对查询的列上有运算或者函数的
  4. 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
  5. 如果查询中没有用到联合索引的第一个字段,则不会走索引
  6. 条件中使用了null
  7. 使用count(*)时

ArrayList的默认大小和扩容策略

ArrayList的容量就是默认大小也就是10;ArrayList每次扩容都为原先容量1.5倍。

hashmap的默认大小和扩容策略

  • capacity 即容量,默认16。
  • loadFactor 加载因子,默认是0.75
  • threshold 阈值。阈值=容量*加载因子。默认12。当元素数量超过阈值时便会触发扩容。

当元素数量超过阈值时便会触发扩容。每次扩容的容量都是之前容量的2倍。

什么是动态代理?

动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。

(一)JDK动态代理机制

JAVA的动态代理的关键就在Proxy.newProxyInstance(…)方法执行时生成了$Proxy0的内存字节码以及JDK的反射机制。

(二)CGLib底层原理

1、通过查看 Enhancer 类源码,最终也是生成动态代理类的字节码,动态代理类继承要被代理的类,然后实现其方法。

2、和 JDK Proxy 的实现代码比较类似,都是通过实现代理器的接口,再调用某一个方法完成动态代理的,唯一不同的是,CGLib 在初始化被代理类时,是通过 Enhancer 对象把代理对象设置为被代理类的子类来实现动态代理的。

什么是CAS?

CAS 即比较并交换。是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS 操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值(V)与预期原值(A)相匹配,那么处理器会自动将该位置值更新为新值(B)。否则,处理器不做任何操作。

什么是悲观锁?

当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式被称之为悲观并发控制。

什么是乐观锁?

乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。

乐观锁的实现

1、CAS 实现:Java 中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种 CAS 实现方式。

2、版本号控制:一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会 +1。当线程 A 要更新数据时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。

3、使用条件限制实现乐观锁

mysql> select * from t_goods;  
+----+--------+------+---------+  
| id | status | name | quantity|  
+----+--------+------+---------+  
|  1 |      1 | 道具 |      10 |  
|  2 |      2 | 装备 |      10 |  
+----+--------+------+---------+  
rows in set  

mysql>

status 表示产品状态:1-在售;2-暂停出售。quantity 表示产品库存。更新库存操作如下:

update goods
set quantity = quantity- #{buyQuantity} 
where id = #{id} 
AND quantity - #{buyQuantity} >= 0 
AND status = 1

说明:quantity -#{buyQuantity}>=0此种做数据安全校验,适合库存模型,扣份额和回滚份额,性能更高。

高并发下原子性修改库存操作的SQL语句

update item set quantity=quantity-1 where id=1 and quantity-1>0

为什么MySQL的索引要使用B+树而不是其它树形结构?比如B树?

简单来说,其中有一个原因就是B+树的高度比较稳定,因为它的非叶子节点不会保存数据,在只保存键值和指针的情况下,一个页能承载大量的数据。B树的非叶子节点会保存数据,同样的一行数据大小是1kb,那么它一页最多也只能保存16个指针,在大量数据的情况下,树高就会速度膨胀,导致IO次数就会很多,查询就会变得很慢。

SQL语句执行顺序

from -> on -> join -> where -> group by -> sum、count、max、avg -> having -> select -> distinct -> order by -> limit

mysql锁 innodb下的记录锁,间隙锁,next-key锁

(一)间隙锁

间隙锁采用在指定记录的前面和后面以及中间的间隙上加间隙锁的方式避免数据被插入;

(二)next-key锁
  • next-key锁其实包含了记录锁(行锁)和间隙锁,即锁定一个范围,并且锁定记录本身,InnoDB默认加锁方式是next-key 锁;
  • 上面的案例一session 1中的sql是:select * from news where number=4 for update ;next-key锁锁定的范围为间隙锁+记录锁,即区间(2,4),(4,5)加间隙锁,同时number=4的记录加记录锁。

innodb自动使用间隙锁的条件:

  • (1)必须在RR级别下;
  • (2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)。

mysql mvcc(多版本并发控制)

快照读是通过mvcc控制的,可能出现幻读;
当前读是通过行锁和间隙锁控制的,此时加了排他锁。

mysql binlog日志

Binlog日志的两个最重要的使用场景:

  • (1)MySQL主从复制:MySQL Replication在Master端开启binlog,Master把它的二进制日志传递给slaves来达到master-slave数据一致的目的;
  • (2)数据恢复:通过使用 mysqlbinlog工具来使恢复数据。

zookeeper的节点类型

  • PERSISTENT 持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只要不手动删除该节点,他将永远存在;
  • PERSISTENT_SEQUENTIAL 持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号;
  • EPHEMERAL 临时目录节点:客户端与zookeeper断开连接后,该节点被删除;
  • EPHEMERAL_SEQUENTIAL 临时顺序编号目录节点:客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号;
  • Container 节点:3.5.3 版本新增,如果Container节点下面没有子节点,则Container节点 在未来会被Zookeeper自动清除,定时任务默认60s 检查一次;
  • TTL 节点:默认禁用,只能通过系统配置 zookeeper.extendedTypesEnabled=true 开启,不稳定。

Zookeeper事件类型

  • None: 连接建立事件
  • NodeCreated: 节点创建
  • NodeDeleted: 节点删除
  • NodeDataChanged:节点数据变化
  • NodeChildrenChanged:子节点列表变化
  • DataWatchRemoved:节点监听被移除
  • ChildWatchRemoved:子节点监听被移除

什么是优雅关闭

  • 在程序被kill时将内存中的一些临时数据和状态处理掉,这里称之为优雅关闭。
  • 当服务提供方正在关闭,可以直接返回一个特定的异常给调用方。然后调用方把这个节点从健康列表挪出,并把其他请求自动重试到其他节点。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值