赞
踩
基本数据类型转换规则大的数据类型转换为小的数据类型需要强制转换反之可以自动转换。
byte short int long float double
基本数据类型8个 string不是基本数据类型 也不能被继承因为有final修饰
int 4字节 float f = 3.14f/F; float类型后面跟f
++i是先计算i的值,然后再使用这个值,而i++是先使用i,然后再计算i++.
Java中所有定义的基本类型或对象都必须初始化才能输出值不然编译会报错
递归就是方法里调用自身 数组未赋值输出0
Father father = new son()父类类型的引用指向一个子类的对象 即为多态 该引用只能调用父类中定义的方法和变量;
如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;
(动态连接、动态调用)变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。
constructor构造器即类的构造器每个类都有 默认的为无参无返回值无void方法 方法名与类名相同
singleton单例模式 确保只有单个对象被创建 懒汉不会产生垃圾对象
懒汉:先判断该对象是否已经实例化(判空),若已实例化直接返回该类对象 否则实例化。线程不安全 需要在判断空后加锁synchronized 使用volatile修饰对象防止指令重排,因为需要两次判空,且对类对象加锁,该懒汉式写法也被称为:Double Check(双重校验) + Lock(加锁)
饿汉:类在加载时实例化静态对象private static Singleton instance = new Singleton()然后返回对象 容易产生垃圾对象 类加载时就初始化浪费内存
反射(newInstance()和序列化(将对象写到文件后readObject()读对象)导致懒饿汉对象不唯一,使用枚举实现
工厂模式 简单工厂父类类型的引用指向一个子类的对象 工厂方法定义一个抽象的接口让子类决定实例化哪个类 抽象工厂提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
适配器模式:220V/44=5V 220v转换成5v的电压 例Spring MVC DispatcherServlet 需要获取对应类型的 Controller。SpringAop中每 Advice通知都要封装成对应的拦截器返回给容器,需要使用适配器模式对 Advice 进行转换
选择排序:拿第一个元素循环判断赋最小的值 然后交换位置 反复
快速排序:小于pivot的所有数移动到其左边,大于pivot的数移动到右边,完成对pivot的排序后,继续在pivot的左右两个子区间进行快速排序。
在Tomcat容器中配置数据库数据源的文件是server.xml
编译java文件命令javac
i + 1 < i int 的最大值, 加 1 后变为负数
java可以跨平台因为java代码不是直接运行在CPU上,而是运行在java虚机(简称JVM)上的
javabean:这个Java类必须具有一个无参的构造函数,属性必须私有化。这个类的属性使用getter和setter来访问
public->protected->default->private
hasNext()不是 Object 类的方法toString是所有对象都有的方法
Java 创建对象的几种方式:
(1) 用 new 语句创建对象,这是最常见的创建对象的方法
(2) 调用对象的 clone()深拷贝方法
(3) 反射调用 java.lang.Class 或者 java.l ang.reflect.Constructor 类的 newInstance()实例方法
(4) 反序列化调用 java.io.ObjectInputStream 对象的 readObject()方法
1、包装类是对象,拥有方法和字段,对象的调用都是通过引用对象的地址;基本类型不是?
2、包装类型是引用的传递;基本类型是值的传递?
3、声明方式不同:基本数据类型不需要new关键字
包装类型需要new在堆内存中进行new来分配内存空间?
4、存储位置不同:基本数据类型直接将值保存在值栈中;
包装类型是把对象放在堆中,然后通过对象的引用来调用他们?
5、初始值不同:int的初始值为 0 boolean的初始值为false?
包装类型的初始值为null?
向ArrayList,LinkedList中放数据的时候,只能放Object类型的,基本类型放不进去
重载和重写和隐藏
重载 方法的重载参数类型个数顺序不同的同名函数 不关心返回值
重写/继承/覆盖override函数名参数列表返回值类型都一致 抽象类中的抽象方法必须重写,
隐藏/重定义 父类和子类函数名相同 不关心参数列表跟返回值
值传递和引用传递,Java 编程语言只有值传递参数 除set和add外都不会改变实参
在调用方法时,若要使方法改变实参的值用对象作为参数:形参p:echo(Point p)临时名称,实参x:A.echo(x)简单来讲就是用对象为参数在方法内会改变外面的对象的值而值不会
值传递:对于基本类型和包装类,传递的时候,将实参值复制,方法内获得的形参与实参没有关系,只是值相同,称为值传递,在方法中修改形参不影响实参;
引用传递:对于对象,传递的时候,将实参引用复制,形参与实参引用相同,指向的是同一个对象,称为引用传递,在方法中修改形参会影响实参
浅拷贝复制其引用地址,当引用指向的值改变时也会跟着变化;而深拷贝复制变量值相当于新建一个同值的新对象,对象的修改并不会影响另一个对象。clone方法是浅拷贝可以重写clone实现不完全的深拷贝,因为对象里的引用类型变量经常出现层层调用关系
如果是值类型则比较值是否相等;如果是引用类型则判断对象地址是否相等。
equals底层用的,但对于包装类对equals方法进行了重写比较两个对象的内容是否相等
当为Integer i=-128~127时,在自动装箱过程中是取自常量池中的数值所以内存地址相等,但new Integer(1)是新地址
String str = “hello"它是java中唯一不需要new 就可以产生对象的途径,叫直接量; 先在内存中找是不是有hello这个对象,有就让str指向那个hello没有hello就创建一个新的对象保存"hello”. str1==str2
String str=new String (“hello”)就是直接新建一个对象保存"hello"
equals相同hashCode也相同 equals不相同hashCode不一定不同(自定义对象内相同成员)
重写equals当将自定义对象放到 map或者 set中时;set会先调用 hashCode方法进行比较,equals不相同hashCode相同这样就会将重复对象存入 map或者 set中。
重写hashcode方法后,修改成员字段数值会影响hashcode值影响到在哈希表中的位置,致使remove方法无法找到原来的对象,但是对象在哈希表中有引用,hash对象又没有被释放。垃圾回收器发现其还有引用,又不会回收该对象。于是,内存泄漏了(内存空间使用完毕之后未回收)如果要修改,先从哈希表中删除该对象,修改后再放入哈希表。
String的hashCode算法:第一个字符转为int类型的值31+第二个字符int类型的值类推,先判断后面有没有字符在31
String和StringBuffer,StringBuilder的区别
字符串分两类:一类是字符串常量String;另一类是字符串变量StringBuffer
String类型其对象内部需要维护三个成员变量char[] chars,int startlndex,int length。其内容一旦声明后对象本身是不可改变的,改变的只是其内存的指向 及修改其引用
String在java里是固定长度,能用“+”连接因为:String s = “asdf”;当定义这个变量时,根据Java的对象池机制,JVM-java虚拟机会在内存的堆栈中的某一个地址分配一个字符串常量 asdf ,即追加字符后,就不是原先的对象了所以使用‘+’连字符s = s+“x”;后,JVM又在堆栈中生成了新的字符串常量。
StringBuffer类线程安全 内容可以改变 不像String直接通过赋值完成对象实例化,须通过构造方法的方式完成 进行字符串处理时不生成新的对象,在内存使用上要优于String
StringBuilder方法线程不安全 因为在扩容时append方法中count用的+=也没有在方法上使用 synchronized 不能同步访问 但单线程下速度快于StringBuffer
final、finally与finalize的区别
final可以用来修饰类,方法和变量:修饰类时不能被继承 final方法不能被重写,可被重载 final常量赋值后其引用地址不能变 值可以变
finally异常处理的一部分 只要执行了try就一定执行finally code会在try的return之前执行 除非被System.exit(0)终止Java 虚拟机的运行
finalize()在gc启动 及垃圾回收 一般不需要去实现
Collection(集合):容器,用于存放对象(引用类型。基本类型需要自动装箱) 基本数据类型转换为包装器类
Array(数组):它使用索引在数组中搜索和读取数据是很快的。Array获取数据的时间复杂度是O(1),但是要删除数据却是开销很大的,因为这需要重排数组中的所有数据。
List(集合):元素有序,元素可以重复 (有索引)。 允许多个null是不连续的存储结构, List的每个节点都有着一个Next属性,这个属性则记录着他的下一个节点的地址。
Set(集):元素无序,不可重复 (没有索引)。 遍历只能用Iterator迭代器和增强for, 不能使用普通for遍历:无法使用下标取值
ArrayList(数组列表): 查询快,增删慢。 允许null线程不安全 多线程add会有数组越界的异常
LinkedList(链表): 查询慢,增删快。
HashSet(哈希表): 查询快,增删慢。 无序允许null(底层就是Map)存放的引用类型需重写hashCode()和equals()方法。
TreeSet自然顺序递增排序
LinkedHashSet(哈希链表): 查询慢,增删快。 有序的,存放顺序和取出顺序一致。
CopyOnWriteArrayList读多写少的并发场景 写锁不会阻塞读 add元素时先lock锁复制一份list然后添加元素再改变指针指向,删除同理
paralleStream帕尔劳 使用默认的ForkJoinPool,线程数量就是处理器数量。改变其线程数System.setProperty设置系统ForkJoinPool线程 会影响到其他调用ForkJoinPool数。或构建自己的FJP new ForkJoinPool(2)
处理非线程安全对象或+=会导致结果不准
strea().reduce(0, (subtotal, element) -> subtotal + element)归并函数瑞do斯(第一个参数用来保存归并参数的初始值,也是Stream 为空默认返回值。参2定义带两个参数的函数,参1是上个归并函数的返回值,参2是Strem 中下一个元素,也可以Integer::sum/String::concat)
线程安全的list Vector SynchronizedList和SynchronizedRandomAccessList CopyOnWriteArrayList
HashTable synchronizedMap ConcurrentHashMap
HashMap HashTable TreeMap的原理以及区别
这三个都对Map接口进行了实现
HashTable基于哈希表(数组+链表实现 采用synchronized同步方法是安全的线程,性能低因为锁的是整个哈希表,读读互斥,有序他不仅实现了Map接口也实现了Dictionary(滴克新呢锐 接口,不许key与Value为Null
TreeMap基于红黑树 线程不安全 允许value为空,key不能为空(内部按照key排序,默认按照键的自然顺序进行升序排序,若要进行降序排序则需要在构造集合时候传递一个比较器
HashMap链表+数组+红黑树 是不安全的线程 方法不同步,允许键和值为null(如果key 为 null 的话, hashCode = 0)通过哈希表对内部映射关系快速查找 无顺序HashMap不允许有重复的键
HashSet的底层实现是HashMap,不能有重复的元素 内部是无序的,只能通过迭代的方式获得。
HashMap和TreeMap都继承自AbstractMap,不同的是HashMap实现的是Map接口,而TreeMap实现的是NavigableMap接口,NavigableMap是SortedMap的一种,实现了对Map中key的排序。
HashMap底层基于hashing原理,key和value都可以是null,通过put()和get()储存获取对象,HashMap的优势就是crud的时间复杂度都是 O1)所以速度快
线程不安全,因为put没有加锁 Entry可能形成环形链表,get(key)时计算的位置是这个环形链表,如果没有key对应的值会一直遍历这个环形链表,因为源码中是遍历到null才退出循环,环形链表没有null结果就是死循环
get:调用getNode(hash(key),key)获取位置判断数组非空数组大于0,头节点是否为空。头结点满足返回条件?不满足则判断桶中不止一个节点,next否红黑树,不是就遍历寻找节点equals
HashMap.put():
根据key通过哈希算法与运算得出数组下标,判断map为空则resize() 初始化↓
1.7(数组链表时间复杂度O(n)如果数组下标位置元素不为空,则会先判断当前插入元素hash值以及两者key是否一致返回原值value。else:存数据前判断扩容:存放新值时map元素的个数>=阈值(默认16负载因子0.75阈值12且存放entry的时候数据发生hash碰撞(当前key计算的hash值换算出来数组下标位置已经存在值就调用resize()扩容为两倍:transfer()把原来数组元素放入新数组,后生成Entry对象头插法添加到当前位置的链表中
1.8(数组链表红黑树(二分法搜索时间复杂度O(log n)如果数组下标位置元素为空,则将key和value封装为Node对象(hash key value next)放入该位置。不为空判断当前Node的类型是红黑树Node(TreeNodes)还是链表Node
红黑树Node将key和value封装为一个红黑树节点并添加到红黑树中去 过程中判断红黑树中存在当前key则更新value
Node对象是链表节点将key和value封装为一个链表Node并通过尾插法插入到链表的最后位置去,尾插法需要遍历链表中判断是否存在当前key存在则更新value,当遍历完链表后将新链表Node插入到链表尾存数据后判断链表长>=8进入treeifyBin():如果数组长度小于64就扩容为两倍否则:会将该链表转为红黑树,最后再判断数组元素个数大于12就扩容。resize() 中当红黑树节点小于或等于6以后会恢复成链表形态(中间隔个7防止两者频繁转换
使用头插法的原因:新加入的键值对被查找访问的概率更高
使用尾插法的原因:因为尾插法可以统计链表长度是否大于8转化为红黑树
使用红黑树的原因:相比于平衡二插排序树,红黑树只有在最长路径>最短路径*2时才触发旋转操作。时间复杂度O(log n)优于O(n)
解决hash冲突:链式寻址法:存在冲突的key以单向链表的方式存储,1.8版本中是通过链式寻址法以及红黑树优化Hash表的链表过长时间复杂度增加的问题
一致性哈希算法,相较于hash算法解决了增减/崩缓存服务器的问题,并提供了虚拟节点解决负载均衡
普通hash算法hash(id)%3判断数据缓存至3台服务器 增删服务器影响数据获取
一致性算法hash(服务器的IP)% 232计算服务器位置后用hash(id)%232获得位置缓存往后计算遇到第一个服务器,增删服务器不影响原数据存放 引入服务器的虚拟节点使数据更均匀分配至各服务器
ConcurrentHashMap与HashTable最大的区别就是ConcurrentHashMap对大table中每个位置加了锁 键值都不允许为null table数组为2的幂次 key均匀分布,减少hash冲突
对于SynchronizedMap封装HashMap的put方法加上互斥锁保证安全性,CHM在1.8中取消了segments字段,采用了CAS+volatile
1.7版本中cmap的put先判断是否需要扩容后根据key找到对应的Segmentm,再往Segment中加锁的put键值对,利用自旋锁去尝试获取锁,利用再入锁的方式锁住Segment,保证只有一个线程操作Segment,不会形成环形链表
1.8取消了Segment,第一层是HashEntry。当链表达到一定长度会以红黑树代替和HashMap一样.put的时候采用了CAS+synchronized保证线程安全
putVal3参冲突是否替换,KV非空判断后空数组首次initTable懒汉式扩容,非初始化扩容时发现正在扩容,且当前元素所在的桶元素已经迁移完成了就协助扩容然后数据迁移,最后加S锁put值跟hmap一样
初始化扩容用CAS将SIZECTL值修改为-1表示正在扩容后double check数组是否初始化后初始容量16
mysql三大范式
原子性 数据库表中的每一列都不可以再拆分
消除部分依赖 表中的每列都和主键相关
消除传递依赖 两张表要通过外键关联,不保存冗余字段。例如:不能在“员工表”中存储“部门名称”。
五大约束 主键唯一性 默认 外键 非空约束 检查约束限制某一列的取值范围
mysql优化延时关联:select … where id in (select id from…limit 10000,30);在索引覆盖的场景下效率更高
或者join分页SELECT * FROM a
AS t1 JOIN (SELECT id FROM a
ORDER BY id desc LIMIT “.(
p
a
g
e
−
1
)
∗
page-1)*
page−1)∗pagesize.”, 1) AS t2
WHERE t1.id <= t2.id ORDER BY t1.id desc LIMIT $pagesize;
mysql索引失效问题
1联合索引查询时的条件列不是联合索引中的第一个列(不满足最左匹配原则
3条件语句中使用or或字符串类型没用“”或数学运算
4未覆盖索引(select*)时使用前置通配符(%三)尽量用后置(张%)
6索引字段上使用 !=, not,<>、in、not exists
、is null、is not null、mysql的内置函数
8优化器觉得全表扫描要比使用索引快,则不使用索引(索引查出来的数据未超过表的30%的数据 也可以force index强制使用索引
9left join或者right join关联的字段编码格式不一样,可能导致索引失效
最左匹配原则:当我们创建一个联合索引的时候,如(k1,k2,k3),相当于创建了(k1)(k1,k2)(k1,k2,k3)三个索引,联合索引不满足最左原则,索引会失效
脏读:事务使用另外一个事务未提交的数据
不可重复读:事务中的两次读数据之间,另一个事务修改数据
幻读:事务对表中的全部数据行进行了修改,第二个事务向表中插入了一行新数据。第一个事务发现表中还有没有修改的数据行
更新丢失:事务更新数据把另一个事务的数据更新覆盖
不可重复读和幻读的区别:
不可重复读重点在于update和delete,而幻读的重点在于insert
Mysql的四种隔离级别
读未提交事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读、不可重复读和幻读
读已提交(Oracle默认级别)事务只能读取另一个事务已经提交的数据。该隔离级别可以防止脏读,推荐
可重复读(Mysql默认级别)事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读
串行操作所有事务依次执行,这样事务之间就完全不可能产生干扰,该级别可以防止脏读、不可重复读以及幻读,这将严重影响程序的性能
修改MySQL系统参数来控制事务的隔离级别SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
MyISAM和InnoDB
MyISAM不支持实物无外键,只支持表级锁:读锁会阻塞写,写锁会阻塞读和写,加锁解锁都是自动的
如果同时需要读操作和写操作,那么MyISAM会优先让写操作的连接获取到写锁,这也是MyISAM表不适合有大量写入操作和读操作应用的缘由,改和删很慢
InnoDB支持事物,支持外键,表级锁和行级锁 id自增会往后延续 myisam会填充
行锁、表锁、排他锁等都是悲观锁select…for update
慢查询解决:加索引。用慢查询日志slow_query_log,确认SQL语句是否占用过多资源,用explain查询执行计划、对group by、order by、join等语句优化,如果数据量实在太大考虑分库分表,用redis缓存储或走es索引
mybatis一级缓存: 基于 PerpetualCache (per排球catch)的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
(2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;
(3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear 掉并重新更新,如果开启了二级缓存,则只根据配置判断是否刷新。
mybatis分页原理逻辑分页:Mybatis是如何通过我们设置的RowBounds肉棒死 来返回分页结果的
原理:首先是将所有结果查询出来,然后通过计算offset和limit,只返回部分结果,操作在内存中进行,所以也叫内存分页。
弊端:当数据量大的时候,肯定是不行的
物理分页:直接为sql添加limit
拦截器PageHelper,调用了startPage后,他会通过PageInterceptor对其后的第一个执行sql进行拦截拼接上limit语句
一对一用association、一对多collection
mybatis如何连接数据库 创建database.properties填写jdbc连接信息 然后在resource下创建mybatisconfig.xml关联刚刚的信息
Mybatis将sql执行结果封装为目标对象并返回:
第一种是使用标签resultMap,逐一定义数据库列名和对象属性名之间的映射关系。
第二种是使用sql列的别名功能,将列的别名书写为对象属性名。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
mybatis防止sql注入# 启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;
执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,
¥直接字符串拼接 # 会带引号
#是占位符, 会对SQL进行预编译,相当于?; 不需要关注数据类型。一般做参数传递,都会使用#{}
是做
s
q
l
拼接例如表名称的变化
,
有
S
Q
L
注入的隐患
是做sql拼接 例如表名称的变化, 有SQL注入的隐患
是做sql拼接例如表名称的变化,有SQL注入的隐患{} 必须自己判断数据类型 但可以过滤字符来解决
函数AVG平均值 CEIL/FLOOR向上/下取整 having聚合函数
springmvc流程用户发送请求到前端控制器。页面控制器接收到请求后,进行功能处理。前端控制器收回控制权,然后根据返回的逻辑视图名。前端控制器再次收回控制权,将响应返回给用户
1.客户端发送请求到后台服务器;
2.springmvc核心控制器DispatcherServlet统一接收请求,并根据请求的url找到HandlerMapping映射的Controller;
3.Controller里面调用业务方法完成业务处理,包括与持久层交互,完成数据持久化;
4.Controller处理完业务方法后返回对应的ModelAndView(模型视图)对象,包含了返回的页面以及数据模型;
5.DispatcherServlet接收返回的ModelAndView对象,通过ViewResolver视图解析器找到对应的界面并进行页面渲染,最后页面在前端呈现出来。
SpringMVC中的中心控制Servlet是DispatcherServle类
SpringBean不是线程安全的 原型bean每个对象都是新的不存在线程安全问题,但在单例bean里存在共享资源问题需要线程锁控制
request作用域的Bean、事务管理、任务调度、AOP都用到了ThreadLocal
spring作用域
singleton : 唯一bean实例,默认都是单例
prototype : 每次请求创建新的bean实例
request : 每次HTTP请求产生新的bean仅在当前HTTPrequest内有效
session : 每次HTTP请求产生新的bean仅在当前HTTPsession内有效
global-session: 全局 session 作用域
生命周期:实例化 属性注入 初始化 销毁
spring循环依赖通过三级缓存Map<String, ObjectFactory<?>> singletonFactories提前拿到未初始化的对象,如果对象实现了AOP需要通过三级缓存的ObjectFactory才能提前产生最终的需要代理的对象。
spring设计模式:简单工厂 工厂方法 单例模式 适配器模式
@ComponentScan发现扫描包并将包下面的类加载进Spring容器作为Spring Bean
@Configuration + @Bean将自定义的配置类也加载入Spring容器中作为SpringBean
@EnabledAutoConfiguration、@Import(AutoConfigurationIpmortSelector)、@AutoConfigurationPackage三个注解将Spring容器里面的Bean实现发现与加载
springboot全局事务@EnableTransactionManagement //开启事务支持
启动顺序1.初始化2.获取和启动监听器3.构造容器环境4.创建容器5.实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误6.准备容器7.刷新容器8.刷新容器后置处理
@PostConstruct和实现 ApplicationRunner 接口
DI依赖注入Spring容器负责将被依赖对象赋值给调用者的成员变量 这相当于调用者注入了他依赖的实例 这就是spring的依赖注入
ioc控制反转与DI含义相同 spring框架里spring容器负责控制程序之间的关系 而不是由调用者的程序代码直接控制 这样控制权由应用代码转移到spring容器 控制权就发生反转
AOP面向切面编程实现的TransactionManager
SpringAOP提供了两种事务实现方式:编程式事务、声明式事务
编程式事务:在代码中进行事务控制。优点:精度高。缺点:代码耦合度高
声明式事务@Transactional通过AOP代理实现 spring基于该类生成代理对象作为bean,调用这个代理对象的方法时有事务处理会先关闭事务的自动提交功能改为test代理逻辑提交 如果成功就提交失败则回滚
静态代理是在程序运行前就已经指定的继承对象代理
动态代理在程序运行期 创建目标对象的代理对象 并对目标的方法进行功能性增强 可以在使用代理对象前进行拦截
JDK动态代理 UserService proxy = (UserService) Proxy.newProxyInstance(us.getClass().getClassLoader(),us.getClass().getInterfaces(),handler);通过拦截器加反射的方式实现,代理的目标对象必须实现接口,Java自带
CGLib动态代理Enhancer.create()基于ASM实现,不能代理final
Bean实现接口时用Proxy代理否则CGLib 通过配置强用Proxy代理
@Transactional
默认配置下只有遇到RunTimeException和Error才会回滚。要想所有异常都回滚要加上rollbackFor=(EXception class) 参数value属性配置,可以指定当前事务通知对应的事务及其他数据源,不指定无法回滚其他数据源。
public权限方法才生效 方法没用final或static修饰 看Mysql当前表是否采用:InnoDB存储引擎,因为其他不支持事务
同一个类里A的无事务方法调用B的有事方法 异常在子方法出现,事务不生效因为用的this并不是代理对象 可以注入这个类然后F.s调用方法B 或吧B拿出来
当不在同一个类里,类A的无事务方法调用类B的有事方法,事务生效,且事务回滚范围仅限于类B的方法.并不会让类A里面的方法回滚
与try一起使用无法回滚:在catch中抛出 RuntimeException()异常或者在ctch里TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
事务的ACID:
原子性(Atomicity): 操作过程不可分割,要么都成功,要么都失败
一致性(Consistency):事物操作之后,操作前后数据不变;比如转账减少的跟增加的值不变
隔离性(Isolation): 多个事物之间的操作是分隔的,互不干扰,如果有多个事务去操作同一个数据的时候,就会事务并发问题(抢购 秒杀 等)
持久性(Durability): 成功的完成一个事物处理后,最终commit把数据将永久保存在数据库;
7种传播机制:有事务的方法a调用有事务的方法b
required默认传播类型:两个事务合为一个
supports:a有事务加入a 没有事务改为非事务提交(自动提交无回滚
mandatory:a有事务加入 没有就抛异常
requires_new:创建自己的事务 两个互不想干各自回滚
not supported:b直接自动提交 让a挂起等待b执行完
never:a有事务就抛异常 a没事务就自动提交
nested:A没有事务B创建事务执行 A有事务B事务嵌套在里面
动态数据源创建DynamicDataSource继承AbstractRoutingDataSource然后初始化targetDataSources和key为数据源标识(可以是字符串、枚举、都行,因为标识是Object)、defaultTargetDataSource即可
异常回滚DriverManager提供了getConnection()方法,通过getConnection()创建连接将自动提交设置为false,再使用Connection的CreateStatement()方法生成Statement,运行SQL语句,调用connection的commit()方法提交,使用try catch包围,catch到异常的时候调用connection的rollback()方法回滚
@Autowired默认按类型装配byType(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
@Autowired () @Qualifier ( “baseDao” )
private BaseDao baseDao;
@Resource(这个注解属于J2EE的),默认按名称装配byName,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。如果指定name属性就只按名称装配
@Resource (name= “baseDao” )
private BaseDao baseDao;
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
@Reference是dubbo的注解也是注入,一般注入的是分布式的远程服务的对象,需要dubbo配置使用
@Valus读取配置文件
java中内存:
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.
2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。
3. 堆:存放所有new出来的对象。
4. 静态域:存放静态成员(static定义的
5. 常量池:存放字符串常量和基本类型常量(public static final
6. 非RAM存储:硬盘等永久存储空间?
启动session会生成唯一sessionid然后服务器开辟一块内存对应sessionid 服务器再将sessionid写入cookie 服务器内有一进程监视session活动 session超时或主动关闭 服务器就释放内存块 浏览器要用到session时 iis就读cookie的sessionid然后服务器坚持id对应内存是否有效 有则读取id无则建立新sessionid
Get获得数据 不安全数据被放在请求的URL 传输量小受URL长度限制
Post传递数据 将表单中的数据放在form的数据体中,按照变量和值相对应的方式,传递到action所指向URL 可以传大量数据
form表单是“键值对”的数据格式 自动构建数据结构
json是将整个传过去 适合数组/对象
转发:forward:/WEB-INF/jsp/mian.jsp 以前的request中存放的变量不会失效,就像把两个页面拼到了一起。携带请求数据 路径不变
重定向:redirect(瑞迪歪克特):/main.jsp 以前的request中存放的变量全部失效,产生了两次请求 并进入一个新的request作用域。不携带请求数据 路径改变
gc垃圾回收:确定对象可以回收后,jvm会在1cpu空闲自动进行回收2堆内存存储满了之后3调用System.gc()后回收
垃圾回收的四种算法:标记-清除算法 复制算法 标记-整理算法 分代收集算法
JDK9将String底层实现char[]改成了byte[]为了节省字符串占用的内存 GC 次数也会减少:用Latin-1 编码代替UTF-8,英文由两个字节变成一个字节
HTTP超文本传输协议
MongoDB:
$gt:大于
$lt:小于
$gte:大于或等于
$lte:小于或等于
Unsafe是不安全的类 可以绕过安全机制执执行底层操作内存如 分配和释放内存 直接设置和获取对象的字段值和compareAndSwapXXX()实现非阻塞的同步
雪花算法:在高并发下根据毫秒级时间戳生成高效生成不重复id 缺点依赖服务器时间 修改时间会导致重复
关于为什么HashMap的长度包括扩容后的长度都是2的次方这个问题,这个indexFor方法逻辑给出了答案。因为2的次方减一即(length - 1)得到的数其二进制样式差不多,前面有多少个0不一定,但后面一定是连续的1。比如(2-1)的二进制是000001,(2的三次方-1)的二进制是000111。而&(与运算)原则是有0就是0,都是1才是1。想象一下,比如000111这种二进制参与与运算,前三位即0的位置不管另一个二进制上对应位是什么都是0,即一种情况,而后三位即1的那位得看另一个二进制对应位置上是什么,即两种情况。很好理解,1越多,情况越多,即求出来的数组下标可能性越多,即散列越均匀,形成的链表越少,查询效率越高。理解这个小知识点很重要。
接口幂等性多次请求保证操作只执行一次:上锁
java异常体系
所有异常超类Thorwable(嗖儿伯。Error错误无法处理 一般是虚拟机JVM相关的问题,Exception异常分为两种,checked Exception(编译时异常也叫非运行时异常编译会报错,和 RuntimeException(运行时异常需要try catch或抛出去
并发:允许两个任务彼此干扰。统一时间点、只有一个任务运行,交替执行。
并行:在时间上是重叠的,两个任务在同一时刻互不干扰的同时执行。
串行:在时间上不可能发生重叠,前一个任务没执行完,下一个任务就只能等待。
线程安全当多个线程访问一个对象时如果不用进行额外的同步控制或其他的协调操作,调用这个对象的行为都可以获得正确的结果这个对象是线程安全的。如synchronized的StringBuffer
守护线程:为所有非守护线程提供服务的线程如gc垃圾回收,不能访问读写操作和计算逻辑,因为会在任何时候中断,不能把正在运行的线程设置成守护线程
Hashmap1.7扩容前也有可能存储更多值(超多16个值,最多可以存26个值)都还没有扩容。原理:前11个值全部hash碰撞,存到数组的同一个位置(虽然hash冲突,但是这时元素个数小于阈值12,并没有同时满足扩容的两个条件。所以不会扩容),后面所有存入的15个值全部分散到数组剩下的15个位置(这时元素个数大于等于阈值,但是每次存入的元素并没有发生hash碰撞,也没有同时满足扩容的两个条件,所以叶不会扩容),前面11+15=26,所以在存入第27个值的时候才同时满足上面两个条件,这时候才会发生扩容现象
字节码就是 Java 程序经过编译之类产生的.class 文件,只需要把 Java 程序编译成 Java 虚拟机能识别的 Java 字节码,不同的平台安装对应的 Java 虚拟机,这样就可以可以实现 Java 语言的跨平台
Java中四种引用类型
强引用:new出来的对象 gc不会回收,会导致内存泄漏
软引用:SoftReference包裹的对象,内存不足gc会回收,不会内存泄漏,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。当调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象,否则返回一个null
弱引用:WeakReference包裹的对象比软引用更弱只要gc发现就回收 生命周期更短
虚引用:PhantomReference包裹的对象跟没有引用一样随时会被gc回收
Bloom Filter是一种空间效率很高的随机数据结构,它的原理是,当一个元素被加入集合时,通过K个Hash函数将这个元素映射成一个位阵列(Bit array)中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检索元素一定不在;如果都是1,则被检索元素很可能在。这就是布隆过滤器的基本思想,在计算机科学中,我们常常会碰到时间换空间或者空间换时间的情况,即为了达到某一个方面的最优而牺牲另一个方面。Bloom Filter在时间空间这两个因素之外又引入了另一个因素:错误率。在使用Bloom Filter判断一个元素是否属于某个集合时,会有一定的错误率。也就是说,有可能把不属于这个集合的元素误认为属于这个集合(False Positive),但不会把属于这个集合的元素误认为不属于这个集合(False Negative)。在增加了错误率这个因素之后,Bloom Filter通过允许少量的错误来节省大量的存储空间。
nginx
正向代理:vpn(对方不知道是谁访问
反向代理:访问外部端口映射到内部端口(我不知道会访问到谁 default.comf内location{proxy_pass}
热部署:修改nginx.conf后生成新的worker进程处理新请求,等之前worker进程的请求处理完后kill
B-树与B+树的区别:
B-树内部节点是保存数据的;而B+树内部节点是不保存数据的,只作索引作用,它的叶子节点才保存数据。
B+树相邻的叶子节点之间是通过链表指针连起来的,B-树却不是。
查找过程中,B-树在找到具体的数值以后就结束,而B+树则需要通过索引找到叶子结点中的数据才结束
B-树中任何一个关键字出现且只出现在一个结点中,而B+树可以出现多次。
为什么索引结构默认使用B+树,而不是B-Tree,Hash哈希,二叉树,红黑树?
Hash哈希,只适合等值查询,不适合范围查询。
一般二叉树,可能会特殊化为一个链表,相当于全表扫描。
红黑树,是一种特化的平衡二叉树,MySQL 数据量很大的时候,索引的体积也会很大,内存放不下的而从磁盘读取,树的层次太高的话,读取磁盘的次数就多了。
B-Tree,叶子节点和非叶子节点都保存数据,相同的数据量,B+树更矮壮,也是就说,相同的数据量,B+树数据结构,查询磁盘的次数会更少。
1,串行:一个任务执行完,才能执行下一个任务
2.并行:两个任务同时执行
3,并发:两个任务整体看上去是同时执行,在底层,两个任务被折成了很多份,然后一个一个执行,站在更高的角度看来两个任务是同时在执行的
JDK:Java开发包提供了编译、运⾏Java程序所需的各种⼯具和资源,包括Java编译器、Java运⾏时环境,以及常⽤的Java类库等
JRE:Java运⾏环境,⽤于运⾏Java的字节码⽂件。JRE中包括了JVM以及JVM⼯作所需要的类库,普通⽤户⽽只需要安装JRE来运⾏Java程序,⽽程序开发者必须安装JDK来编译、调试程序。
JVM:Java虚拟机,是JRE的⼀部分,它是整个java实现跨平台的最核⼼的部分,负责运⾏字节码⽂件。
JVM线程共享区:堆和方法区,堆放对象 方法区: 类定义的成员变量常量静态变量方法
一个对象从加载到 JVM再到被GC清除都经历了什么过程:
类加载器用双亲委派机制把字节码文件内容加载到方法区,然后再根据加载完方法区中的类的信息在堆区为对象分配内存、初始化零值、设置对象头、执行 init 方法完成创建。先移除栈中的指针使对象没有根节点的引用,然后gc根据可达性分析判断对象能否回收最后钓鱼gc算法回收
STW: Stop-The-World是在垃圾回收算法执行过程当中将JVM内存冻结的应用程序停顿的一种状态。在stw下除gc外线程都停止且不可避免,只能减少停止时间
双亲委派模型(parents的直译多代相传):除顶层启动类加载器外的类加载器都应由自己的父类加载
类需要被加载时先委派给父类加载器,如果父类加载器无法加载则继续向上委派最终由启动类加载器进行加载,如果启动类加载器仍然无法加载就会抛出ClassNotFoundException.实现了类加载的层次化管理,保证了类的唯一性和安全
JDK自带有三个类加载器:bootstrap ClassLoader、ExtClassLoader、AppClassLoader。
启动类加载器BootStrapClassLoader是ExtClassLoader的父类加载器,默认负责加载%AVA_HOME%lib下的jar包和class文件
扩展类加载器ExtensionClassLoader是AppClassLoader的父类加载器,负责加载%JAVA_HOME%/Iib/ext文件夹下的jar包和class类
应用程序类加载器ApplicationClassLoader是自定义类加载器的父类,负责加载classpath下的类文件
RocketMQ为了保证发送有序SelectMessageQueueByHash()让同一个订单发送到同一个队列中,再使用同步发送,只有同个订单的创建消息发送成功,再发送支付消息
分布式锁解决的是分布式资源抢占的问题;分布式事务和本地事务是解决流程化提交问题
分布式锁应该具备哪些条件:互斥性;高可用的获取锁与释放锁;高性能的获取锁与释放锁;可重入性;非阻塞
SimpleDateFormat线程不安全 成员变量calendar.clear()和cal.set()操作非原子性,没有线程安全机制加锁或者每次使用新对象 不要static共享静态对象或DateTimeFormatter
Boolean 和 boolean的区别 默认值不同 false和null 阿里巴巴开发手册POJP的属性必须使用包装数据类型 如数据库查询结果可能为null 用基本数据类型接收有空指针风险
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。