反射
反射是一种能力
反射是一种在程序运行时能够动态获取当前类对象的所有属性和方法的能力,可以动态执行方法,给属性赋值等操作的能力.
反射主要是让我们的java程序具有动态性. 这种能力带来很多好处,在许多框架的背后实现上都使用了反射这种机制来实现动态效果.
框架更多的是提供一种编程的约定
谈谈你对Spring的认识
解耦
核心的IOC容器技术(控制反转)
IOC 帮助我们自动管理依赖的对象,不需要我们自己创建和管理依赖对象,从而实现了层与层之间的解耦. 重点是 解耦
核心的AOP技术 (面向切面编程)
AOP 方便我们将一些非核心的业务逻辑抽离,从而实现核心业务与非核心业务的解耦. 比如事务的管理,日志,性能建测,读写分离的实现等等…
Spring Dao , Spring web 模块更边防继承各大主流框架,比如ORM框架, hibernate,mybatis. 比如MVC框架,SpringMVC
Spring的bean作用域?
1.默认是singleton, 即单例模式
2.prototype , 每次从容器调用bean时都会创建一个新的对象,比如整合Struts2框架的时候,spring管理action对象则需要这么设置.
3.request,每次http请求都会创建一个对象
4.session,同一个session共享一个对象
5.global-session
Spring的bean是线程安全的吗?
回忆一下线程不安全的3要素: 1.多线程环境 2.访问同一个资源 3.资源具有状态性
bean基本上是无状态的,所以从这个点来说是属于线程安全的.
所谓无状态就是没有存储数据,即没有通过数据状态来判断下一步操作的判断依据.
什么是事务的传播特性?Spring支持的特性有哪些?
1.什么是事务传播的特性?
我们一般都是将事务的边界设置在service层. 那么当我们调用Service层的一个方法时,它能保证我们的方法中执行的所有对数据库的更新及操作保持在一个事务中.保证了原子性.但是如果在一个service中调用了另一个service呢?
2.spring支持的事务传播特性
在Spring中针对传播特性的多种配置. 大多数情况下只使用一种: PROPGATION_REQUIRED;
意思是当我调用service层的方法时,开启一个事务.那么在调用这个service层里面的其他方法的时候,如果当前方法产生了事务就用当前方法产生的事务,否则就创建一个新的事务.
3.Spring支持的事务传播特性
PROPGATION_SUPPORTS: 支持当前事务,如果当前没有事务就以非事务方式执行.
PROPGATION_MANDATORY: 支持当前事务,如果当前没有事务就抛出异常.
PROPGATION_REQUIRES_NEW: 新建事务,如果当前存在事务就把事务挂起.
PROPGATION_NOT_SUPPORTED: 以非事务的方法执行操作,如果当前存在事务就把事务挂起
PROPGATION_NEVER: 以非事务的方式执行,如果当前存在事务则抛出异常.
悲观锁和乐观锁
1.悲观锁是利用数据库本身的锁机制来实现,会锁记录.
实现的方式: select * from t_table where id = 1 for update
2.乐观锁是一种不锁记录的实现方式,采用CAS(compare and set/swap)模式,采用version字段来作为判断依据.
每次对数据的更新操作都会使得version+1, 这样提交更新操作时,如果version的值已被更改则更新失败.
update t_table set store=store+1,version=version+1 where id = 1 and version=old_version
3.乐观锁的实现为什么要选择version字段? 如果选择其他字段,比如业务字段store, 可能会出现所谓的ABA问题.(中间的过程中可能发生了变动,就会出现问题. 初始值是A, 中间改为B, 后又改为了A,实际值发生变化)
Mybatis的缓存机制
缓存主要的作用是为了提高查询性能,减少了跟数据库的交互次数,从而也减轻了数据库承受的压力.
适用于读多写少的场景.
一级缓存是默认开启的
一级缓存作用域在于SqlSession
任何一次更新操作都会清空一级缓存 update
二级缓存
要使用二级缓存需要经历两个步骤:
1.开启二级缓存
2.在Mapper.xml中配置二级缓存 (也支持在接口配置)
在标签下添加标签即可.
默认的二级缓存配置有以下的特点:
1.所有的select语句将会被缓存
2.所有的更新语句(insert update delete)都会刷新缓存
3.缓存将采用LRU (Least Recently Used 最近最少使用)算法来回收
4.缓存会存储1024个对象的引用.
回收算法建议采用LRU , 此外还提供了FIFO(先进先出) , SOFT(软引用), WEAK(弱引用)等其他算法
PS:关闭了SqlSession之后才会将查询数据保存到二级缓存中(SessionFactory)
.
Mybatis的二级缓存默认采用的是Map的实现.
在开发中经常可以集成第三方的缓存来保存Mybatis的二级缓存.EhCache和redis
Mybatis有哪些分页方式?
一般分为逻辑分页和物理分页
逻辑分裂: 指的是使用Mybatis子代的RowBounds进行分页,它会一次性查出多条数据,然后再检索分页中的数据,具体一次性查询多少条数据都受到jdbc配置的fetch-size决定
物理分页: 指从数据库中查询指定条数的数据,而分页插件PageHelper实现的就是物理分页
从发出请求到响应都发生了什么?
1.检查输入的URL格式是否正确
2.解析域名,端口,路径
3.当前有没有缓存 ? 直接使用缓存 : 正式发起请求
网络分层 TCP/IP协议: 应用层(http),传输层(TCP 三次握手 四次挥手),网络层(ip,mac),数据链路层(mac)
synchronized的底层原理
synchronized是由一对monitorenter(自动上锁)和monitorexit(自动解锁)指令来实现同步,在JDK6之前,monitor的实现是依靠操作系统内部的互斥锁来实现的,所以需要进行用户态和内核态的切换,所以此时的同步操作是一个重量级的操作,性能很低.
锁升级
JDK6之后提供了三种monitor的实现方式,分别是 偏向锁,轻量级锁,重量级锁,即锁是会从偏向锁再根据实际情况逐步升级到轻量级锁和重量级锁.
在锁对象的对象头里面有一个 threadId字段,默认为空,当第一次有线程访问的时候,则将threadid设置为当前线程id,我们称为让其获取偏向锁. 当线程执行结束之后threadid重新设置为null
之后,如果线程再次进入,会先判断threadid与该线程id是否一致, 如果一直则获取该对象. 如果不一致则会发生锁升级, 即从偏向锁升级为轻量级锁 (自旋).
轻量锁的工作模式是通过自旋循环的方式来获取锁,看对方线程是否已经释放了锁,如果执行一定次数之后,还是没有获取到锁.则发生锁升级,从轻量级锁升级为重量级锁.
锁升级的目的是为了减少锁带来的性能消耗.
synchronized是如何保证可见性的?
两个线程如何保证变量信息的共享可见性?
线程A -> 本地内存A(共享变量副本) -> 主内存(共享变量)
如果有变更,需要将本地内存的变量写到主内存,对方才可以获取到更新.
当获取到锁之后,每次读取都是从主内存读取,当释放锁的时候,都会将本地内存的信息写到主内存,从而实现可见性.
synchronized 和 volatile 的区别
1.作用的位置不同
synchronized是修饰方法,代码块
volatile是修饰变量
2.作用不同
synchronized 可以保证变量修改的可见性以及原子性.可能会造成线程阻塞
volatile 仅能实现变量修改的可见性,但无法保证原子性.不会造成线程阻塞
volatile 是一个轻量级的线程同步机制. 保证了变量在线程之间的可见性.