一、Java基础篇
-
接口和抽象类的区别
(1)抽象类可以有构造方法
,而接口没有
(2)抽象类可以有抽象方法
和普通方法
,接口只能有抽象方法
(3)抽象类的成员4种权限修饰符都可以修饰,接口只能用private -
java权限修饰符有哪些
- public(公有的)
- protected(受保护的)
- default(缺省的)
- private(私有的)
-
接口重载和重写的区别
- 重载发生在同一个类里面,方法名相同, 参数列表、返回类型、权限修饰符可以不同
- 重写发生在子类中、方法名相同、参数列表相同、返回类型相同,权限修饰符要大于父类方法,声明异常范围要小于父类方法,但是
final
和private
修饰的方法不可重写
-
== 和 equals的区别
- == 对于
基本类型
来说是值比较,对于引用类型
来说是比较的是内存地址; - 而 equals
默认
情况下是引用比较,只是很多类重写
了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
- == 对于
-
异常处理机制
(1)使用try、catch、finaly捕获异常,finaly中的代码一定会执行,捕获一场后程序会继续
执行
(2)使用throws声明该方法可能会抛出
的异常类型,出现异常后,程序终止
-
HashMap的原理
- HashMap的数据结构
- 在JDK1.7中底层数据结构是基于数组+链表,在1.8之后是数组+链表+红黑树来实现的,特点就是
key不能重复
,可以为null
,线程不安全
- 在JDK1.7中底层数据结构是基于数组+链表,在1.8之后是数组+链表+红黑树来实现的,特点就是
- HashMap的扩容机制:
- HashMap的默认容量为
16
,默认的负载因子为0.75
,当HashMap中的元素个数超过临界值时,就会创建一个大小为前一次2倍
的新数组,再将原来数组中的数据复制
到新数组中。当数组长度大于64
且链表长度大于8
时,链表转为红黑树
- HashMap的默认容量为
- HashMap的存取原理
- 计算key的hash值,然后进行二次
hash
,根据二次hash
结果找到对应的索引位置 - 如果这个位置上有值,先进性
equals
比较,若结果为true说明key相同则取代该元素,若结果为false,就使用高低位平移
将节点插入链表(JDK8
以前使用的是头插法
,但是头插法在并发扩容时可能会造成环形链表
或数据丢失
; 而高低位平移发会发生数据覆盖
的情况)
- 计算key的hash值,然后进行二次
- HashMap的数据结构
-
想要线程安全的HashMap怎么办
(1)使用ConcurrentHashMap
(2)使用HashTable
(3)Collections.synchronizedHashMap()方法 -
ConcurrentHashMap原如何保证的线程安全
- JDK1.7:使用
分段锁
,将一个Map分为了16个段,每个段都是一个小的hashmap,每次操作只对其中一个段加锁 - JDK1.8:采用
CAS+Synchronized
保证线程安全,每次插入数据时判断在当前数组下标是否是第一次插入,是就通过CAS方式插入,然后判断f.hash是否=-1,是的话就说明其他线程正在进行扩容,当前线程也会参与扩容;删除方法用了synchronized修饰,保证并发下移除元素安全
- JDK1.7:使用
-
HashTable与HashMap的区别
(1)HashTable的每个方法都用synchronized修饰,因此是线程安全的,但同时读写效率很低
(2)HashTable的Key不允许为null
(3)HashTable只对key进行一次hash,HashMap进行了两次Hash
(4)HashTable底层使用的数组加链表 -
ArrayList和LinkedList的区别
-
ArratList
- ArratList的底层使用动态数组,默认容量为
10
,当元素数量到达容量时,生成一个新的数组,大小为前一次的1.5
倍,然后将原来的数组copy过来 - 因为数组有索引,所以ArrayList查找数据更快,但是添加数据效率更低
- ArratList的底层使用动态数组,默认容量为
-
LinkedList
- LinkedList的底层使用链表,在内存中是分散的,没有扩容机制
- LinkedList在查找数据时需要从头遍历,所以查找慢,但是添加数据效率更高
-
-
如何保证ArrayList的线程安全
(1)使用collentions.synchronizedList()方法为
ArrayList
加锁
(2)使用Vector,Vector底层与Arraylist相同,但是每个方法都由synchronized
修饰,速度很慢
(3)使用juc下的CopyOnWriterArrayList,该类实现了读操作不加锁
,写操作时为list
创建一个副本,期间其它线程读取的都是原本list
,写操作都在副本中进行,写入完成后,再将指针指向副本。 -
String、StringBuffer、StringBuilder的区别
String
和StringBuffer
、StringBuilder
的区别在于String
声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而StringBuffer、StringBuilder
可以在原有对象的基础上进行操作,所以在经常改变
字符串内容的情况下最好不要使用 String。- StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 是StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
二、Java多线程篇
-
进程和线程的区别
进程:系统运行的基本单位,包含多个线程
线程:独立运行的最小单位,是进程的实体,多个线程共享同一进程内的系统资源 -
什么是线程上下文切换
当一个线程被剥夺cpu使用权时,切换到另外一个线程执行 -
什么是死锁
死锁指多个线程在执行过程中,因争夺资源造成的一种相互等待的僵局 -
死锁的必要条件
- 互斥条件:同一资源同时
只能
由一个线程读取 - 不可抢占条件:
不能
强行剥夺线程占有的资源 - 请求和保持条件:请求其他资源的
同时
对自己手中的资源保持
不放 - 循环等待条件:在
相互
等待资源的过程中,形成一个闭环
想要预防死锁,只需要破坏其中一个条件即可,银行家算法可以预防死锁
- 互斥条件:同一资源同时
-
Synchrpnized和lock的区别
(1)synchronized是关键字,lock是一个类
(2) synchronized在发生异常时会自动释放锁,lock需要手动释放锁
(3)synchronized是可重入锁、非公平锁、不可中断锁,lock是可重入锁,可中断锁,可以是公平锁 -
sleep()和wait()的区别
- 所在类不同
- sleep()是Thread类的静态方法。
wait()是Object类的方法。
- sleep()是Thread类的静态方法。
- 锁释放不同
- sleep()是不释放锁的。
wait()是释放锁的。
- sleep()是不释放锁的。
- 用途不同
- sleep()常用于一定时间内暂停线程执行。
wait()常用于线程间交互和通信。
- sleep()常用于一定时间内暂停线程执行。
- 用法不同
- sleep()方法睡眠指定时间之后,线程会自动苏醒。
wait()方法被调用后,可以通过notify()或notifyAll()来唤醒wait的线程。
- sleep()方法睡眠指定时间之后,线程会自动苏醒。
- 所在类不同
-
yield() 和 join()区别
- yield()调用后线程进入就绪状态
- A线程中调用B线程的join() ,则B执行完前A进入阻塞状态
-
线程池七大参数
- 核心线程数:线程池中的基本线程数量
- 最大线程数:当阻塞队列满了之后,逐一启动
- 最大线程的存活时间:当阻塞队列的任务执行完后,最大线长的回收时间
- 最大线程的存活时间单位
- 阻塞队列:当核心线程满后,后面来的任务都进入阻塞队列
- 线程工厂:用于生产线程
- 拒绝策略:阻塞队列满后,拒绝任务, 有四种策略
(1)抛异常
(2)丢弃任务不抛异常
(3)打回任务
(4)尝试与最老的线程竞争
-
Java内存模型
- JMM(Java内存模型 )屏蔽了各种硬件和操作系统的内存访问差异,实现让Java程序在各平台下都能达到
一致
的内存访问效果,它定义了JVM如何将程序中的变量在主存中读取 - 具体定义为:所有变量都存在主存中,主存是线程共享区域;每个线程都有自己
独有
的工作内存,线程想要操作变量必须从主
从中copy变量到自己的工作区,每个线程的工作内存是相互隔离
的 - 由于主存与工作内存之间有读写延迟,且读写
不是
原子性操作,所以会有线程安全问题
- JMM(Java内存模型 )屏蔽了各种硬件和操作系统的内存访问差异,实现让Java程序在各平台下都能达到
-
保证并发安全的三大特性?
- 原子性:一次或多次操作在执行期间
不被
其他线程影响 - 可见性:当一个线程在工作内存修改了变量,其他线程能
立刻
知道 - 有序性:JVM对指令的优化会让指令执行
顺序
改变,有序性是禁止
指令重排
- 原子性:一次或多次操作在执行期间
-
volatile
保证
变量的可见性和有序性,不保证
原子性。使用了 volatile 修饰变量后,在变量修改后会立即同步
到主存中,每次用这个变量前会从主存刷新。- 单例模式双重校验锁变量为什么使用 volatile 修饰? 禁止 JVM 指令重排序,new Object()分为三个步骤:申请内存空间,将内存空间引用赋值给变量,变量初始化。如果不禁止重排序,有可能得到一个未经初始化的变量。
-
线程使用方式
- 继承 Tread 类
- 实现 Runnable 接口
- 实现 Callable 接口:带有返回值
-
ThreadLocal原理
- 原理是为每个线程创建变量副本,不同线程之间不可见,保证线程安全。每个线程内部都维护了一个Map,key为
threadLocal
实例,value为要保存的副本。 - 但是使用ThreadLocal会存在
内存泄露
问题,因为key为弱
引用,而value为强
引用,每次gc时key都会回收
,而value不会被回收
。所以为了解决内存泄漏问题,可以在每次使用完后删除value或者使用static
修饰ThreadLocal,可以随时获取value
ThreadLocal 的经典使用场景是数据库连接和 session 管理等。
- 原理是为每个线程创建变量副本,不同线程之间不可见,保证线程安全。每个线程内部都维护了一个Map,key为
-
什么是CAS锁
- CAS锁可以保证原子性,思想是更新内存时会判断内存值是否被别人修改过,如果没有就直接更新。如果被修改,就重新获取值,直到更新完成为止。这样的缺点是
只能
支持一个变量的原子操作,不能
保证整个代码块的原子操作- CAS频繁失败导致CPU开销大
- ABS问题:线程1和线程2同时去修改一个变量,将值从A改为B,但线程1突然阻塞,此时线程2将A改为B,然后线程3又将B改成A,此时线程1将A又改为B,这个过程线程2是不知道的,这就是ABS问题,可以通过版本号或时间戳解决
- CAS锁可以保证原子性,思想是更新内存时会判断内存值是否被别人修改过,如果没有就直接更新。如果被修改,就重新获取值,直到更新完成为止。这样的缺点是
-
JUC常用辅助类
- CountDownLatch:设定一个数,当调用
CountDown()
时数量减一,当调用await()
时判断计数器是否为0,不为0就阻塞,直到计数器为0 - CyclicBarrier:设定一个数,当调用
await()
时判断计数器是否达到目标值,未达到就阻塞,直到计数器达到目标值 - Semaphore:设定一个信号量,当调用
acquire()
时判断是否还有信号,有就信号量减一线程继续执行,没有就阻塞等待其他线程释放信号量,当调用release()
时释放信号量,唤醒阻塞线程
- CountDownLatch:设定一个数,当调用
-
如何根据 CPU 核心数设计线程池线程数量
- IO 密集型:核心数*2
- 计算密集型: 核心数+1
为什么加 1?即使当计算密集型的线程偶尔由于缺失故障或者其他原因而暂停时,这个额外的线程也能确保 CPU 的时钟周期不会被浪费。
三、JVM
-
JVM运行时数据区
- 线程私有区:
- 虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧
- 本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一
- 程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
- 线程共享区
- 堆内存:Jvm进行垃圾回收的主要区域,存放对象信息,分为
新生代
和老年代
- 方法区:
存放类信息、静态变量、常量、运行时常量池
等信息。JDK1.8之前用持久代
实现,JDK1.8后用元空间
实现,元空间使用的是本地内存,而非在JVM内存结构中
- 堆内存:Jvm进行垃圾回收的主要区域,存放对象信息,分为
- 线程私有区:
-
什么情况下会内存溢出
- 堆内存溢出:
- 当对象一直
不停的创建
而不被回收时 - 加载的类越来越多时
- 虚拟机栈的线程越来越越多时
- 当对象一直
- 栈溢出: 方法调用次数过多,一般递归不当造成
- 堆内存溢出:
-
JVM有哪些垃圾回收算法
- 标记清除算法: 标记不需要回收的对象,然后清除没有标记的对象,会造成许多内存碎片。
- 复制算法: 将内存分为两块,只使用一块,进行垃圾回收时,先将存活的对象
复制
到另一块区域,然后清空之前的区域。用在新生代
- 标记整理算法: 与标记清除算法类似,但是在标记之后,将存活对象
向一端移动
,然后清除边界外的垃圾对象。用在老年代
-
GC如何判断对象可以被回收
- 引用计数法:已淘汰,为每个对象添加
引用计数器
,引用为0
时判定可以回收;这个可能会出现两个对象相互引用无法回收的问题 - 可达性分析法:从
GCRoot
开始往下搜索,搜索过的路径称为引用链
,若一个对象GCRoot没有任何的引用链,则判定可以回收
- GCRoot有:虚拟机栈中引用的对象,方法区中静态变量引用的对象,本地方法栈中引用的对象
- 引用计数法:已淘汰,为每个对象添加
-
典型垃圾回收器
G1 :JDK1.9以后的默认垃圾回收器,支持并发,采用标记整理+复制算法,注重响应速度 -
类加载器和双亲委派机制
从父类加载器到子类加载器分别为:
- BootStrapClassLoader 加载路径为:JAVA_HOME/jre/lib
- ExtensionClassLoader 加载路径为:JAVA_HOME/jre/lib/ext
- ApplicationClassLoader 加载路径为:classpath
还有一个自定义类加载器
当一个类加载器收到类加载请求时,会先把这个请求交给父类加载器处理,若父类加载器找不到该类,再由自己去寻找。该机制可以避免类被重复加载,还可以避免系统级别的类被篡改
-
类加载过程
- 加载:加载字节码文件,将字节码中的
静态变量
和常量
转换到方法区
,在堆中生成class
对象作为方法区入口 - 连接:
- 验证:验证字节码文件的
正确性
- 准备:正式为类变量在方法区中分配内存,并
设置
初始值 - 解析:将
符号引用
解析为直接
的一个引用(类在实际内存中的地址)
- 验证:验证字节码文件的
- 初始化:执行类构造器(这里不是常规的构造方法),为静态变量
赋值
并初始化
静态代码块
- 加载:加载字节码文件,将字节码中的
-
JVM中有哪些引用
强引用:new的对象。哪怕内存溢出也不会回收
软引用:只有内存不足时才会回收
弱引用:每次垃圾回收都会回收(例如:ThreadLocal中的key)
虚引用:必须配合引用队列使用,一般用于追踪垃圾回收动作 -
对象头中有哪些信息
对象头中有两部分,一部分是MarkWork,存储对象运行时的数据,如GC
分代年龄、GC
标记、锁的状态、线程ID等;另外一部分是指向对象类型的指针,如果是数组,还有一个部分存放数组长度 -
JVM内存参数
-Xmx[]: 堆空间最大内存
-Xms[]: 堆空间最小内存,一般设置成跟堆空间最大内存一样的
-Xmn[]: 新生代的最大内存
-xx[use 垃圾回收器名称]:指定垃圾回收器
-xss: 设置单个线程栈大小
一般设堆空间为最大可用物理地址的百分之80 -
JVM类初始化顺序
父类
静态代码块和静态成员变量->子类
静态代码块和静态成员变量->父类
代码块和普通成员变量->父类
构造方法->子类
代码块和普成员变量->子类
构造方法
四、Mysql
-
MyIAm和InnoDB的区别
InnoDB支持事务,MyIAm不支持
InnoDB支持外键,MyIAm不支持
InnoDB是聚簇索引,MyIAm是非聚簇索引
InnoDB支持行锁和表锁,MyIAm只支持表锁
InnoDB不支持全文索引,MyIAm支持
InnoDB支持自增和MVCC模式的读写,MyIAm不支持 -
Mysql事务特性
原子性:一个事务内的操作要么
成功
要么失败会滚
,不存在中间状态
一致性:事务前后的数据总量不变,也就是说一个事务执行之前和执行之后都必须处于一致性
状态
隔离性:是指多个事务并发执行的时候,事务与事务之间相互不影响
持久性:事务一旦提交发生的改变不可逆
的,即便是在数据库系统遇到故障的情况下也不会丢失
提交事务的操作 -
事务靠什么保证
- 原子性:由
undolog
日志保证,他记录了需要回滚的日志信息,回滚时撤销已执行的sql - 一致性:由其他三大特性共同保证,是事务的目的
- 隔离性:由
MVCC
保证 - 持久性:由
redolog
日志和内存
保证,mysql修改数据时内存和redolog
会记录操作,宕机时可恢复
- 原子性:由
-
事务的隔离级别
在高并发情况下,并发事务会产生脏读
、不可重复读
、幻读
问题,这时需要用隔离级别来控制
1、脏读
出现原因:一个事务读取到了缓存中另一个事务未提交的脏数据。
(说明:当事务B对data进行了修改但是未提交事务,此时事务A对data进行读取,并使用事务B修改的数据做业务处理。)
2、幻读
出现原因:一个事务在读取数据时,另一个事务插入了数据,导致上个事务第二次读取数据时,数据不一致。
(说明:data 表有一条数据,事务A对data进行读取, 事务B对data进行数据新增 ,此时事务A读取只有一条数据,而最后实际data是有两条数据,就好象发生了幻觉一样情况成为幻读)
3、不可重复读
出现原因:读取数据的同时可以进行修改
(说明:事务A、事务B同时对data进行访问,事务A对data进行读取,事务B对data进行修改,当事务A第一次对data进行读取完后事务B提交,此时当事务A第二次读取该数据时的数据就与第一次读取的数据不同,这种情况称为不可重复读)- read_uncommitted(
读未提交
):可读取未提交事务的操作数据,最低的隔离级别,一般都没有用的。这种情况会出现脏读。 - read_committed(
读已提交
):一个事务等另一个事务提交之后才可进行读取,解决了脏读问题,但会出现不可重复读 - repeatable_read(
可重复读
):读取事务开启的时候不能对数据进行修改,解决了不可重复读问题,但是存在幻读问题 - serializable(
序列化
):是最高的事务隔离级别,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用
- read_uncommitted(
-
什么是快照读和当前读
快照读
:读取的是当前数据的可见版本,可能是会过期数据,不加锁的select就是快照读当前读
:读取的是数据的最新版本,并且当前读返回的记录都会上锁,保证其他事务不会并发修改这条记录。如update、insert、delete、select for undate(排他锁)、select lockin share mode(共享锁) 都是当前读
-
MVCC是什么
MVCC是多版本并发控制,为每次事务生成一个新版本数据,每个事务都由自己的版本,从而不加锁就决绝读写冲突,这种读叫做快照读。只在读已提交和可重复读中生效。
实现原理由四个东西保证,他们是- undolog日志:记录了数据历史版本
- readView: 事务进行快照读时产生的视图,记录了当前系统中活跃的事务id,控制哪个历史版本对当前事务可见
- 隐藏字段DB_TRC_ID: 最近修改记录的事务ID
- 隐藏字段DB_Roll_PTR: 回滚指针,配合undolog指向数据的上一个版本
-
MySQL有哪些索引
- 主键索引:一张表只能有一个主键索引,主键索引列
不能有空值
和重复值
- 唯一索引:唯一索引
不能有相同值
,但允许为空
- 普通索引:允许出现重复值
- 组合索引:对
多个字段
建立一个联合索引
,减少索引开销
,遵循最左匹配
原则 - 全文索引:myisam引擎支持,通过建立
倒排索引
提升检索效率,广泛用于搜索引擎
- 主键索引:一张表只能有一个主键索引,主键索引列
-
聚簇索引和非聚簇索引的区别
- 聚簇索引:将索引和值放在了一起,根据索引可以直接获取值,如果主键值很大的话,辅助索引也会变得很大
- 非聚簇索引:叶子节点存放的是数据行地址,先根据索引找到数据地址,再根据地址去找数据
他们都是
b+数
结构 -
B和B+数的区别,为什么使用B+数
- 二叉树:索引字段有序,
极端情况会变成链表
形式 - AVL数:树的
高度不可控
- B数:控制了树的高度,但是
索引值
和data
都分布在每个具体的节点
当中,若要进行范围查询,要进行多次回溯
,IO开销大 - B+树:
非叶子节点
只存储索引值
,叶子节点
再存储索引
+具体数据
,从小到大用链表连接在一起,范围查询可直接遍历不需要回溯
- 二叉树:索引字段有序,
-
MySQL有哪些锁
-
基于粒度:
- 表级锁:对整张表加锁,粒度大并发小
- 行级锁:对行加锁,粒度小并发大
- 间隙锁:间隙锁,锁住表的一个区间,间隙锁之间不会冲突只在可重复读下才生效,解决了幻读
-
基于属性:
- 共享锁:又称读锁,一个事务为表加了读锁,其它事务只能加读锁,不能加写锁
- 排他锁:又称写锁,一个事务加写锁之后,其他事务不能再加任何锁,避免了脏读问题
-
-
MySQL如果做慢查询优化
- 分析sql语句,是否加载了不需要的数据列
- 分析sql执行计划,字段有没有索引,索引是否失效,是否用对索引
- 表中数据是否太大,是不是要分库分表
-
哪些情况索引会失效
- where条件中有or,除非所有查询条件都有索引,否则失效
- like查询用%开头,索引失效
- 索引列参与计算,索引失效
- 违背最左匹配原则,索引失效
- 索引字段发生类型转换,索引失效
- mysql觉得全表扫描更快时(数据少),索引失效
-
Mysql内连接、左连接、右链接的区别
- 内连接(inner join):结合两张表的记录,返回相关的查询结果,返回的是两个表的
交集
部分。
select * from A a inner join B b on a.id=b.id
- 左连接(left join):左连接查询,左表的信息全部展示出来,右表只会展示符合搜索条件的信息,不足的地方记为NULL
select * from A a left join B b on a.id=b.id
- 右连接(rigth join):右连接查询,右表的信息全部展示出来,左表只会展示符合搜索条件的信息,不足的地方记为NULL
select * from A a right join B b on a.id=b.id
- 内连接(inner join):结合两张表的记录,返回相关的查询结果,返回的是两个表的
五、Spring系列
-
Bean的作用域
- Singleton:一个
IOC
容器只有一个 - Prototype:每次调用
getBean()
都会生成一个新的对象 - request:每个
http
请求都会创建一个自己的bean - session:同一个
session
共享一个实例 - application:整个
serverContext
只有一个bean - webSocket:一个
websocket
只有一个bean
- Singleton:一个
-
Bean的生命周期
- 通过构造方法创建bean实例(无参构造)
- 为bean的属性设置值和对其它bean引用(调用set方法)
- 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
- 调用bean的初始化方法(需要进行配置初始化的方法)
- 把bean实例传递bean后置处理的方法postProcessAfterInitialization
- bean可以使用了(对象获取到了)
- 当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法)
如果没有配置后置处理器,bean的生命周期将没有3和5
-
Spring 事务原理
spring事务有编程式和声明式,我们一般使用声明式,在某个方法上增加@Transactional
注解,这个方法中的sql
会统一成功或失败- 原理是:
- 当一个方法加上
@Transactional
注解,spring会基于这个类生成一个代理对象并将这个代理对象作为bean,当使用这个bean中的方法时,如果存在@Transactional
注解,就会将事务自动提交设为false,然后执行方法,执行过程没有异常就会提交,有异常就会回滚
- 当一个方法加上
- 原理是:
-
spring事务失效场景
- 事务方法所在的类没有加载到容器中
- 事务方法不是
public
类型 - 同一类中,一个没有添加事务的方法调用另外以一个添加事务的方法,事务不生效
- spring事务默认只回滚运行时异常,可以用
rollbackfor
属性设置 - 业务自己捕获了异常,那么事务会认为程序正常秩序
-
spring事务的隔离级别
default
:默认级别,使用数据库自定义的隔离级别
其它四种隔离级别与mysql一样 -
spring事务的传播行为
- spring的7种传播行为:
required
:(默认传播行为),它是Spring里面默认的事务传播行为,也就新当前存在事务就加入到当前事务去执行,如果不存在事务就创建一个事务
例如:方法A调用方法B,它们用同一个事务。(如果B没有事务,它们会用同一个事务。)(只要有一个回滚,整体就会回滚)requires_new
:它不管是否存在事务,它都会新开启一个事务来执行,新老事务相互独立的,外部事务抛出异常,并不会影响内部事务的一个正常提交
例如:方法A调用方法B,它们用不同的事务。(B不会用A的事务,会新增事务。)supports
:表示支持当前的事务,如果当前不存在事务,就以非事务的方式去执行
例如:方法A调用方法B,如果A没有事务,那么B就以非事务运行。
如果A有事务就以A事务为准。如果A没有事务,那么B就会以非事务执行。mandatory
:它是一个强制的事务执行,如果当前不存在事务就抛出一个异常
支持当前事务,如果当前没有事务就会抛出异常。
例如:方法A调用方法B,如果方法A没有事务,那么就会抛出异常。not_supported
:表示以非事务的方式来运行,如果当前存在事务,就需要把当前的事务挂起来。
例如:方法A调用方法B,方法B会挂起事务A以非事务方式执行。never
:就是以非事务执行,如果存在事务,抛出异常。
总是以非事务执行,如果存在事务,那么就抛出异常。nested
:如果当前存在事务,就嵌套当前事务中去执行,如果当前没有事务,那么就新建一个事务,类似 requires_new这个样一个传播行为
例如:方法A中调用了方法B,B中try catch手动回滚,A不会回滚。
- spring的7种传播行为:
-
Spring IoC
-
IOC(Inversion of Control 即控制反转)将对象交给容器管理
我们要考虑:谁控制谁控制什么?为了是反转?哪些方面反转?- 是
容器
控制了对象
- 主要控制了
外部资源
及生命周期
- 由容器帮我们查找并注入依赖的对象,对象只能被动的接收依赖对象,依赖对象的获取被反转了
- 是
-
spring中提供了一种IOC容器,来控制对象的创建,无论是你创建对象,处理对象之间的依赖关系,对象的创建时间还是对象的创建数量,都是spring提供IOC容器上配置对象的信息就可以了。
-
IOC能做什么
: 由IOC容器帮对象找相应的依赖思想并注入,并不是由对象主动去找资源集中管理,实现资源的可配置和易管理降低了使用资源双方的依赖程度,解耦合
-
-
spring用了哪些设计模式
- 简单工厂模式
- spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定
- 工厂方法模式
- 通常由应用程序直接使用new创建新的对象,为了将对象的创建和使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。
- 一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。
- 单例模式
- 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
- spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。
- 适配器模式
在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器重的内容增强了代理方法的功能,实现的面向切面编程。 - 包装器模式
spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
6. 代理模式
为其他对象提供一种代理以控制对这个对象的访问。 从结构上来看和Decorator模式类似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增加职责。
7. 观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
8. 策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。这个模式使得了算法可独立于使用他的客户而变化。
- 简单工厂模式
-
springboot常用注解
@RestController :修饰
类
,该控制器会返回Json
数据
@RequestMapping(“/path”) :修饰类
,该控制器的请求路径
@Autowired : 修饰属性
,按照类型进行依赖注入
@PathVariable : 修饰参数
,将路径值映射到参数上
@ResponseBody :修饰方法
,该方法会返回Json数据
@RequestBody(需要使用Post提交方式) :修饰参数
,将Json数据封装到对应参数中
@Controller@Service@Compont: 将类注册到ioc
容器