4种访问修饰符
访问权限 | 类 | 包 | 子类 | 其他包 |
---|---|---|---|---|
public | ∨ | ∨ | ∨ | ∨ |
protect | ∨ | ∨ | ∨ | × |
default | ∨ | ∨ | × | × |
private | ∨ | × | × | × |
数据库视图
一个表或多个表导出的虚拟的表,其内容由查询定义。具有普遍的表结构,但不能实现数据存储
我们在使用查询时,在很多时候我们要使用聚合函数,同时还要 显示其它字段的信息,可能还会需要关联到其它表,这时写的语句可能会很长,如果这个动作频繁发生的话,我们可以创建视图
优点:简化操作 安全 ,只能查到规定的数据*
存储过程
完成特定功能的SQL 语句集
sql语句先编译再执行的;而存储过程是已经编译好的代码,所以被调用或引用时,执行效率非常高。
使用:较复杂的数据库批处理的项目 代码量 ,效率 可维护性都比程序组装sql 好用
推荐不使用:
mysql使用率提高(存储过程比较弱)。只是现在行业环境不一样了,即便互联网盛行的情况下随便拉出来一个银行系统,都有很多的存储过程。因为缓存越来越成熟,所以会选择使用缓存去取代存储过程。
DB本身就是存储数据的,如果要把业务强行放进去,未免有些搞笑。
互联网公司 分表分库 需求变动比较频繁 ,性能瓶颈的时候能加服务器比数据库容易
创建存储过程的语法结构:
CREATE [OR REPLACE] procedure pro_name [(parameter1[,parameter2]...] is|as
begin
``plsql_sentences;
[exception]
``[dowith_sentences;]
end [pro_name];
–>pro_name:存储过程的名称,如果数据库中已经存在了此名称,则可以指定”OR PLACE”关键字来覆盖原来的存储过程;如果不想覆盖,可修改名称,这样就可以区分开了
–>parameter1: 存储过程被调用或执行时用到的参数。【注意:这个值不是存储过程内定义的内部变量,内部变量应该在is|as之后定义】
parameter1如果是输入参数,则需要在后面指定IN关键字;如果是输出参数,则需要在后面指定OUT关键字,在IN和OUT后面加的是参数的数据类型,不需要指定长度;【不明白不要紧,后面会举例说明;】
–>plsql_sentences:PL/SQL语句,存储过程中功能实现的主要代码
–>dowith_sentences:异常处理语句,是可选的PL/SQL语句(不需要可以不写
SOA和微服务架构
SOA面向服务的框架。
微服务是SOA的进一步发展,服务根据业务拆分。
序列化和反序列化
序列化 由于存在于内存中的对象都是暂时的,无法长期驻存,为了把对象的状态保持下来,这时需要把对象写入到磁盘或者其他介质中,这个过程就叫做序列化。
反序列化 反序列化恰恰是序列化的反向操作,也就是说,把已存在在磁盘或者其他介质中的对象,反序列化(读取)到内存中,以便后续操作,而这个过程就叫做反序列化。
- 序列化的应用情景
主要有以下情况(但不限于以下情况)
- 1)内存中的对象写入到硬盘;
- 2)用套接字在网络上传送对象;
- 3)通过RMI(Remote Method Invoke 远程方法调用)传输对象
对于超过3层的 if-else 的逻辑判断代码,可以使用卫语句、策略模式、状态模式等来实现
什么是函数式接口
所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。
/**
* 真正的业务处理
*/
@FunctionalInterface
public static interface RequestExecutor {
Object doExecute() throws BusinessException;
}
/**
* 请求模板
*/
public void templateRequest(RequestExecutor executor) {
// 获取response对象
HttpServletResponse response =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
try {
Object result = executor.doExecute();
writeAjaxJSONResponse(ResultMessageBuilder.build(true, "success!", result), response);
} catch (Exception e) {
logger.error("请求失败", e);
writeAjaxJSONResponse(ResultMessageBuilder.build(false, 500, "系统异常"), response);
}
}
/**
* controller部分代码
*/
@PostMapping(path = "/pageQuery")
public void pageQuery(@RequestBody Query query) {
templateRequest(() -> service.pageQuery(query));
}
/**
* service部分代码
*/
public PagedResult<VO> pageQuery(Query query);
用于某一特定的场景,但是有不同的处理逻辑的时候,比如导入数据,导入是共性,但是处理逻辑都不同
lambda表达式如何序列化
查看hashmap的源码
public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}
序列化对象是需要有实现序列化接口的。但Comparator并没有实现
我们知道&
是按位与操作
,但是两个数据类型按位与?没见过?
实际上,这是强制类型转换,转换成可序列化的Comparator<Map.Entry<K, V>>对象
。&的意思是且
的意思。
这种强制类型转换可以将一个对象直接转换为Serializable
对象。
泛型
解决不确定具体数据类型的问题
早期Java是使用Object来代表任意类型的,但是向下转型有强转的问题,这样程序就不太安全
生成字节码文件 会泛型擦除
<T extends Comparable<? super T>>
元素必须是实现了Comparable接口的类或者其子类,可以使用父类方法比较子类型
<T extends Comparable<? super T»
那些字段需要transient修饰
1.类中的字段 可以 根据其它字段 推导出来 主要为了节省存储空间
2.看业务需求,哪些字段不想被序列化
-
不同程序 导致值不同
- ==ObjectOutputStream:通过 writeObject()方法做序列化操作==
- ==ObjectInputStream:通过 readObject() 方法做反序列化操作==
Object.hashCode是nativate 不同的JVM里可能不一样
fail-fast机制
集合中常见的错误机制,通常出现在遍历集合元素过程中。
简单说就是优先考虑异常,发现异常直接停止上报。
提到java集合类中fail-fast机制,大概就是抛出ConcurrentModificationException这个异常了。 这里拿ArrayList的iterator()的源码说明一下
1、迭代器iterator()方法执行的时候int expectedModCount = modCount,
2、modCount是AbstractList定义的 protected transient int modCount = 0;
3、迭代器在调用 next()、remove() 方法时都是调用 checkForComodification() 方法,
该方法主要就是检测 modCount == expectedModCount ?
4、ArrayList 中无论 add、remove、clear 方法只要是涉及了改变 ArrayList 元素的个数的方法都会导致 modCount 的改变
部分源码
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;//调用iterator()的时候赋值
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
fail-safe解决之道
java.util.concurrent包下的容器都是fail-safe 对应ArrayList的类CopyOnWriteArrayList CopyOnWriteArrayList这个类设计思想是读写分离,写(add/remove)操作是copy一份副本,在这个副本里操作完成之后再用这个副本替换原件。 当然为了避免出现多个副本,写操作是需要加锁的。这个类适用于读多写特别少的情况,否则很容易OOM。
Copy-On-Write COW奶牛家族
第一:尽量设置合理的容量初始值,他扩容的代价很大、
第二:适合读多写极少的情况
ArrayList
ArrayList底层实现是数组。
当使用无参数构造函数创建ArrayList对象时,ArrayList对象中的数组初始长度为0(是一个空数组)。
ArrayList的扩容策略是每次都增加当前数组长度的一半(非固定分配)。
ArrayList的扩容方式是直接创建一个新的数组,并将数据拷贝到新数组中
面试官最爱的volatile关键字
1 . 保证了不同线程对该变量操作的内存可见性;
2 . 禁止指令重排序