事务是什么?
作为单个逻辑工作单元执行的一系列操作,这一系列操作要么全部执行成功,要么全部执行失败。
事务的四大特性(ACID)?
原子性(Atomicity):事务是一个不可分割的逻辑工作单元,事务中的一系列操作要么全部成功,要么全部失败。
一致性(Consistency):事务必须使数据库从一个一致性状态变换到另一个一致性状态。我们假设用户A和用户B两个人的账户加起来有5000块钱,那么不管A和B之间如何转账,事务结束后两个人的账户加起来还得是5000块钱,这就是一致性状态。
隔离性(Isolation):多个用户并发访问数据库时,数据库为每一个用户开启一个事务,多个并发事务之间相互隔离,不会相互干扰。
持久性(Durability):一个事务一旦被提交了,那么对数据库中的数据的改变是永久性的,即使数据库系统出现故障也不会丢失提交事务的操作。
事务没有隔离会出现哪些问题?
脏读:事务A读取到事务B未提交的数据
不可重复读:事务A读取同一个数据两次,这两次中间事务B修改了这个数据并提交,导致事务A读取的数据不一致
幻读(虚读):事务A批量更新一批数据中的某一字段期间,事务B在这批数据中插入或者删除一条数据,事务A提交的时候,发现了一条自己未修改的数据
更新丢失:两个事务同时更新一个数据,势必导致一个更新会丢失
事务的隔离级别?
读未提交(read-uncommitted):能读到其它事务未提交的数据,不能防止脏读、不可重复读、幻读问题
读已提交(read-committed):能读到其它事务已提交的数据,能防止脏读,不能防止不可重复读、幻读。(Oracle默认的隔离级别)
可重复读(repeatable-read):能重复读取同一个数据,读的时候加一把锁,防止其它事务对这一数据进行更新操作,能防止脏读、不可重复读,不能防止幻读。(MySQL默认的隔离级别)
串行化(serializable):最高的隔离级别,并发事务串行化执行,不会相互干扰,能防止脏读、不可重复读、幻读问题。
Spring 事务的传播机制?
propagation_required(spring 默认):支持当前事务,如果当前没有事务,则新建一个事务。比如:方法A内部调用方法B,如果A开启了事务,则B会运行在A的事务内,如果A没开启事务,则B会为自己分配一个事务。
propagation_requires_new:新建事务,如果外层存在事务,则将外层事务挂起,等当前事务执行完毕再执行外层事务。外层事务回滚不影响当前事务,当前事务回滚,如果外层捕获了异常就不影响外层事务回滚,如果没有捕获异常会进行回滚。注意事项:如果在同一个类中,方法A开启了默认事务,方法B新建了事务,由于动态代理的原因,在invoke方法中无法在此代理方法B,所以直接当作普通方法调用,导致事务失效。
propagation_supports:支持当前事务,如果当前没事务,则以非事务的方式运行。比如方法A内部调用方法B,如果A开启了事务,则B加入到此事务中,如果A没事务,B也不开启事务
propagation_mandatory:支持当前事务,如果当前没事务,则抛出异常。
propagation_not_supported:如果当前存在事务,则将事务挂起,自己以非事务的方式运行。
propagation_never:非事务方式运行,如果当前存在事务,则抛出异常。
propagation_nested:如果当前没事务,则进行与propagation_required类似的操作,如果当前存在事务,则嵌套事务内执行,成为外部事务的一个子事务,子事务回滚会回滚到一个保存点,外部事务如果回滚,子事务也会回滚,外部事务提交,子事务一起提交,子事务异常回滚,外部事务正常可以提交。仅仅支持DataSourceTransactionManager作为事务管理器。
什么是死锁?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,无法继续执行。
死锁产生的四个必要条件?
互斥条件:进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。
请求与保持条件:指进程已经保持至少一个资源,但又请求新的资源,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
循环等待条件:指在发生死锁时,必然存在一个进程—资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
解决死锁的方法?
1、所有的锁都按照特定的顺序获取
2、线程获取锁超时后,主动释放之前获取的所有锁
3、一次性锁住所有资源
Cookie 和 Session 的区别?
cookie 数据保存在客户端,session 数据保存在服务端
session 比 cookie 更具有安全性,可以将重要信息放在session中,无关紧要的信息放在cookie中
单个 cookie 大小不能超过4k,session 没限制,内存大小跟服务器大小有关,session 过多会影响服务器性能
session 能存储任意的 java 对象,cookie 只能存储 String 类型的对象
jre 与 jdk 的区别?
jre 包含了jvm和基础类库等,支撑Java程序的运行;jdk 包含了jre,还包含了编译器javac,开发工具和更多的类库等,支撑Java程序员开发Java程序
Java 中有哪些数据类型?
基本数据类型:byte、short、int、long、float、double、char、boolean
引用数据类型:类、接口、数组
== 和 equals 有什么区别?
==:对于基本数据类型,比较的是值,对于引用数据类型,比较的是引用地址
equals:String 类中重写了Object类的equals方法,先比较引用地址,如果一样,直接返回true;如果不一样,再比较值是否相同
String、StringBuffer、StringBuilder 有什么区别?
String:字符串常量,每次改变内容都会产生新的对象,只适合少量字符串操作的情况
StringBuffer:字符串变量,线程安全,性能低,适合多线程下使用
StringBuilder :字符串变量,线程不安全,性能高,适合单线程下使用
HashMap 和 HashTable 有什么区别?
1、HashMap 继承自AbstractMap类;HashTable 继承自Dictionary类
2、HashMap 线程不安全;HashTable 线程安全
3、HashMap 无contains方法;HashTable 有contains方法
4、HashMap 允许key和value为null值;HashTable 不允许key和value为null值
5、HashMap 通过hashCode值的高16位亦或低16位,得到新hash值;HashTable 直接用的hashCode值作为hash值
6、HashMap 计算索引位用的是数组长度减一按位与hash值;HashTable 计算索引位直接是hash值对数组长度取模运算
7、HashMap 扩容2倍;HashTable 扩容2倍加1
8、HashMap 底层结构是数组+链表+红黑树;HashTable 底层结构是数组+链表
Spring 是什么?
Spring 是一个轻量级的IoC和AOP的容器框架,是为Java应用程序提供基础性服务的一套框架,目的是简化企业应用程序的开发。
说一说对Spring中Ioc的理解?
Ioc就是控制反转,指的是将创建对象的控制权交给Spring框架,由Spring框架根据配置文件去创建实例和管理各个实例之间的依赖关系。
数据库锁分类
按锁粒度分类
行锁:锁一行的数据
- 特点:粒度小,锁冲突概率低,并发度高;锁开销大,加锁慢,容易出现死锁
页锁:锁住一页的数据
- 特点:粒度介于行锁和表锁之间,会出现死锁,并发度一般
表锁:锁住整张表的数据
- 特点:粒度大,锁冲突概率高,并发度低;锁开销小,加锁快,不会出现死锁
从程序员角度划分
乐观锁:每次去拿数据的时候都认为别人不会修改,不会上锁,更新的时候再去判断数据有没有被修改
悲观锁:每次去拿数据的时候都认为别人会修改,会上锁,其它事务拿这个数据时会被阻塞,直到锁被释放
从数据库角度划分
共享锁(S):锁定的数据可以被其它事务读,但是不能被修改
排它锁(X):锁定的数据不允许其它事务读和写
意向锁:告知其它事务,表中是否有数据行被锁定。(当要获取表的排它锁的时候,需要先判断表中是否有数据上了行锁)
间隙锁(Next-Key):保证某个间隙内的数据在锁定情况下不会发生任何变化。用范围条件检索数据的时候,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁。
Redis 内存淘汰机制有哪些
redis在内存空间不足的时候,为了保证命中率,就会选择一定的数据淘汰策略;我们可以在 redis.config 中设置最大的内存参数,默认是关闭的。redis5.0为我们提供了八个不同的内存置换策略,以前是6种。
- volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
- volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
- volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰
- allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
- allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰
- allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
- no-enviction(驱逐):禁止驱逐数据,这也是默认策略。意思是当内存不足以容纳新入数据时,新写入操作就会报错,请求可以继续进行,线上任务也不能持续进行,采用no-enviction策略可以保证数据不被丢失
这八种大体上可以分为4中,lru、lfu、random、ttl。
Redis 过期策略有哪些
- 惰性删除:查询某个 key 的时候,redis 会先检查一下,查看这个key是否设置了过期时间,如果设置了过期时间,那判断是否过期,过期了就删除
- 定期删除:redis 默认是每隔 100 ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期了就删除
- 主动删除:如果定期删除漏了很多过期的key,也没有频繁的查询key,过期的key堆积多了导致内存不够,这时候会走内存淘汰机制
手写一下LRU代码实现
public class LRUCache<Object> {
/**
* 默认缓存大小
*/
private int CAPACITY = 0;
private LinkedList<Object> list;
public LRUCache(int capacity){
this.CAPACITY = capacity;
list = new LinkedList<Object>();
}
public synchronized void put(Object object){
if (list != null && list.contains(object)){
list.remove(object);
}
removeLeastVisitElement();
list.addFirst(object);
}
/**
* 移除最近访问次数最少的元素
*/
private synchronized void removeLeastVisitElement() {
int size = size();
//注意,这儿必须得是CAPACITY - 1否则所获的size比原来大1
if(size > (CAPACITY - 1) ) {
Object object = list.removeLast();
System.out.println("本次被踢掉的元素是:" + object.toString());
}
}
public int size() {
if(list == null) {
return 0;
}
return list.size();
}
public synchronized Object get(int index) {
return list.get(index);
}
public synchronized void clear() {
list.clear();
}
@Override
public String toString() {
return list.toString();
}
}
// 测试
LRUCache<String> lruCache = new LRUCache<>(3);
lruCache.put("a");
System.out.println(lruCache.toString());
lruCache.put("b");
System.out.println(lruCache.toString());
lruCache.put("c");
System.out.println(lruCache.toString());
lruCache.put("d");
System.out.println(lruCache.toString());
lruCache.put("e");
System.out.println(lruCache.toString());
测试结果:
[a]
[b, a]
[c, b, a]
本次被踢掉的元素是:a
[d, c, b]
本次被踢掉的元素是:b
[e, d, c]