map有哪些主要实现
map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。其中这四者的区别如下(简单介绍):
HashMap:我们最常用的Map,HashMap的值是没有顺序的,他是按照key的HashCode来实现的,就是根据key的HashCode 值来存储数据,根据key可以直接获取它的Value,同时它具有很快的访问速度。HashMap最多只允许一条记录的key值为Null(多条会覆盖);允许多条记录的Value为 Null。非同步的。
TreeMap: 能够把它保存的记录根据key排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。
Hashtable: 与 HashMap类似,不同的是:key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,只有hashtable是继承自Dictionary抽象类的,hashMap和treeMap都继承自AbstractMap抽象类,LinkedHashMap继承自hashMap。
LinkedHashMap: 保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。key和value均允许为空,非同步的。
arraylist,vector,linkedlist
1、ArrayList和Vector是采用数组方式存储集合中的元素,元素之间内存地址是连续的,此数组元素数大于实际存储的数据,以便增加和插入新数据。
2、ArrayList和Vector都允许直接序号索引元素,可以快速查找;但是插入和删除数据需要移动数据,所以效率低。
3、Vector由于使用了synchronized方法(线程安全),所以性能比ArrayList差。
4、LinkedList是使用链表结构保存集合中的元素,元素之间内存地址不连续。按序号索引数据需要进行向前或向后遍历,即需要进行寻执操作。LinkedList数据插入或删除不需要移动数据,具有较高的修改性能。
hashmap和hashtable
1.HashMap继承自AbstractMap类。但二者都实现了Map接口。
Hashtable继承自Dictionary类,Dictionary类是一个已经被废弃的类(见其源码中的注释)。父类都被废弃,自然而然也没人用它的子类Hashtable了。
2.HashMap线程不安全,HashTable线程安全
3.HashMap是没有contains方法的,而包括containsValue和containsKey方法;hashtable则保留了contains方法,效果同containsValue,还包括containsValue和containsKey方法。
4.Hashmap是允许key和value为null值的,用containsValue和containsKey方法判断是否包含对应键值对;HashTable键值对都不能为空,否则包空指针异常。
5.计算hash值方式不同
为了得到元素的位置,首先需要根据元素的 KEY计算出一个hash值,然后再用这个hash值来计算得到最终的位置。
①:HashMap有个hash方法重新计算了key的hash值,因为hash冲突变高,所以通过一种方法重算hash值的方法:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
1234
注意这里计算hash值,先调用hashCode方法计算出来一个hash值,再将hash与右移16位后相异或,从而得到新的hash值。
**②:Hashtable通过计算key的hashCode()**来得到hash值就为最终hash值。
它们计算索引位置方法不同:
HashMap在求hash值对应的位置索引时,index = (n - 1) & hash
。将哈希表的大小固定为了2的幂,因为是取模得到索引值,故这样取模时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
HashTable在求hash值位置索引时计算index的方法:
int index = (hash & 0x7FFFFFFF) % tab.length;
1
&0x7FFFFFFF的目的是为了将负的hash值转化为正值,因为hash值有可能为负数,而
&0x7FFFFFFF后,只有符号位改变,而后面的位都不变。
6.扩容方式不同(容量不够)
当容量不足时要进行resize方法,而resize的两个步骤:
①扩容;
②rehash:这里HashMap和HashTable都会会重新计算hash值而这里的计算方式就不同了(看5);
HashMap 哈希扩容必须要求为原容量的2倍,而且一定是2的幂次倍扩容结果,而且每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入;
而Hashtable扩容为原容量2倍加1;
7.解决hash冲突方式不同(地址冲突)
HashMap中,当出现冲突时可以:
1.如果冲突数量小于8,则是以链表方式解决冲突。
2.而当冲突大于等于8时,就会将冲突的Entry转换为**红黑树进行存储。**
3.而又当数量小于6时,则又转化为链表存储。
123
而在HashTable中, 都是以链表方式存储。
abstract class和interface区别
1.相同点
A. 两者都是抽象类,都不能实例化。
B. interface实现类及abstrct class的子类都必须要实现已经声明的抽象方法。
2. 不同点
A. interface需要实现,要用implements,而abstract class需要继承,要用extends。
B. 一个类可以实现多个interface,但一个类只能继承一个abstract class。
C. interface强调特定功能的实现,而abstract class强调所属关系。
D. 尽管interface实现类及abstrct class的子类都必须要实现相应的抽象方法,但实现的形式不同。interface中的每一个方法都是抽象方法,都只是声明的 (declaration, 没有方法体),实现类必须要实现。而abstract class的子类可以有选择地实现。
这个选择有两点含义:
一是Abastract class中并非所有的方法都是抽象的,只有那些冠有abstract的方法才是抽象的,子类必须实现。那些没有abstract的方法,在Abstrct class中必须定义方法体。
二是abstract class的子类在继承它时,对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现,也可以通过再次声明其方法为抽象的方式,无需实现,留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。
E. abstract class是interface与Class的中介。
interface是完全抽象的,只能声明方法,而且只能声明pulic的方法,不能声明private及protected的方法,不能定义方法体,也 不能声明实例变量。然而,interface却可以声明常量变量,并且在JDK中不难找出这种例子。但将常量变量放在interface中违背了其作为接 口的作用而存在的宗旨,也混淆了interface与类的不同价值。如果的确需要,可以将其放在相应的abstract class或Class中。
abstract class在interface及Class中起到了承上启下的作用。一方面,abstract class是抽象的,可以声明抽象方法,以规范子类必须实现的功能;另一方面,它又可以定义缺省的方法体,供子类直接使用或覆盖。另外,它还可以定义自己 的实例变量,以供子类通过继承来使用。
3.应用场景:
interface的应用场景:
A. 类与类之前需要特定的接口进行协调,而不在乎其如何实现。
B. 作为能够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹标识。
C. 需要将一组类视为单一的类,而调用者只通过接口来与这组类发生联系。
D. 需要实现特定的多项功能,而这些功能之间可能完全没有任何联系。
abstract class的应用场景:
A. 定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。可以用abstract class定义一组方法体,甚至可以是空方法体,然后由子类选择自己所感兴趣的方法来覆盖。
B. 某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中表示状态的变量来区别不同的关系。abstract的中介作用可以很好地满足这一点。
C. 规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现;而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能。
一 . 静态内部类可以有静态成员,而非静态内部类则不能有静态成员。
二 . 静态内部类的非静态成员可以访问外部类的静态变量,而不可访问外部类的非静态变量;
三 . 非静态内部类的非静态成员可以访问外部类的非静态变量。
springMVC 接收参数不能为null
跨域问题产生的原因怎么解决跨域?
浏览器安全的基石是"同源政策"(same-origin policy)
- 协议相同
- 域名相同
- 端口相同
随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制。
(1) Cookie、LocalStorage 和 IndexDB 无法读取。
(2) DOM 无法获得。
(3) AJAX 请求不能发送。
解决ajax
1.JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。
它的基本思想是,网页通过添加一个<script>
元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
首先,网页动态插入<script>
元素,由它向跨源网址发出请求。
2.WebSocket
WebSocket是一种通信协议,使用ws://
(非加密)和wss://
(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
3.CORS
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET
请求,CORS允许任何类型的请求。
不跨域行不行
行,可以设置请求上下文,可请求到,但是这种方式不能传参
list集合中存储全公司人员名称,按姓排序
jdbc连接数据,那七步
获取数据库连接对象(第一个参数:协议 + IP + 端口号 + 数据库的名字,第二个参数:要连接的数据库的用户名,第三个参数:要连接的数据库的密码)加载jdbc驱动,创建链接,获取执行sql语句的对象,执行sql语句,解析结果集,释放资源
冯诺依曼技术机体系
控制器、运算器、存储器、输入设备、输出设备
怎样创建静态常量和怎样对其赋值
public static final xxx
配置文件
配置常量类(@value;@component)
数据库三范式
第一范式:列具有原子性,一定要拆分到不可拆分为止
第二范式:在遵从一范式的基础上,表中字段必须要与主键有依赖关系
第三范式:在遵从二范式的基础上,表中的字段必须要与主键有直接依赖关系,不能间接依赖,如果有间接依赖,应该拆分成不同的表,然后使用外键做关联
编译时多态和运行时多态
编译时多态
方法重载都是编译时多态。根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。
方法覆盖表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。例如,以下声明p、m引用本类实例,调用toString()方法是编译时多态。
运行时多态
程序运行时,Java从实例所属的类开始寻找匹配的方法执行,如果当前类中没有匹配的方法,则沿着继承关系逐层向上,依次在父类或各祖先类中寻找匹配方法,直到Object类。寻找p.toString()匹配执行方法的过程如下图所示。
Int和Integer的区别
1、Integer是Int的包装类,Int是八种基本数据类型之一。
2、Integer变量必须实例化以后才可以使用,而Int变量不需要实例化。
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象,而Int是直接存储数据值。
4、Integer的默认值是null,Int的默认值是0。
什么是死锁?如何避免死锁?
所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。
A:java 死锁产生的四个必要条件
1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
下面几种方法可用以避免重装死锁的发生:
具有相同的加锁顺序
使用定时锁
死锁检测
什么是ORM
了解orm,先了解以下概念:
什么是“持久化”
持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。
什么是 “持久层”
持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联。
什么是ORM
即Object-Relationl Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。
mybatis里#{}和&{}的区别
#{}表示一个占位符号:
通过#{}可以实现preparedStatement向占位符中设置值,自动进行Java类型和jdbc类型转换。
#{}可以有效的防止SQL注入。
#{}可以接收键类型值或者pojo属性值。
如果parameterType传给单个简单类型值,#{}括号中可以是value或其他名称。
表
示
拼
接
S
Q
L
串
:
通
过
{}表示拼接SQL串: 通过
表示拼接SQL串:通过{}可以将parameterType传入的内容拼接在SQL中而不进行jdbc类型转换。
可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,
中
只
能
是
v
a
l
u
e
M
y
B
a
t
i
s
排
序
时
使
用
o
r
d
e
r
b
y
动
态
参
数
时
需
要
注
意
,
用
{}中只能是value MyBatis排序时使用order by 动态参数时需要注意,用
中只能是valueMyBatis排序时使用orderby动态参数时需要注意,用{}而不是#{}
写出一个线程安全的单例模式
public class Singleton {
private Singleton() {
}
//懒汉
private static Singleton singleton = null;
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
java数据结构
springMVC中后台如何获取前端传值
- Req.getparameter()
- 通过形参直接接收?形参接收是什么意思
- 通过对象接收
- 通过地址栏接收(@PathVariable)
mysql/oracle分页sql
mysql:limit a,b
oracle:rownum 结合子查询
mybatis常用标签
mybatis dao 怎么映射xml
通过namespace,id
springboot和spring的区别
简而言之,Spring框架为开发Java应用程序提供了全面的基础架构支持。它包含一些很好的功能,如依赖注入和开箱即用的模块,如:
- Spring JDBC
- Spring MVC
- Spring Security
- Spring AOP
- Spring ORM
- Spring Test
这些模块可以大大缩短应用程序的开发时间。例如,在Java Web开发的早期阶段,我们需要编写大量的重复代码来将记录插入到数据源中。但是通过使用Spring JDBC模块的JDBCTemplate,我们可以将它简化为只需几个简单配置或者几行代码。
Spring Boot基本上是Spring框架的扩展,它消除了设置Spring应用程序所需的复杂例行配置。
它的目标和Spring的目标是一致的,为更快,更高效的开发生态系统铺平了道路。以下是Spring Boot中的一些功能:
- 通过starter这一个依赖,以简化构建和复杂的应用程序配置。
- 可以直接main函数启动,嵌入式web服务器,避免了应用程序部署的复杂性,Metrics度量,Helth check健康检查和外部化配置。
- 尽可能的自动化配置Spring功能。
spring的组件
1、spring的核心类,核心组件有哪些,各有什么作用?
BeanFactory:产生一个新的实例,可以实现单例模式
BeanWrapper:提供统一的get及set方法
ApplicationContext:提供框架的实现,包括BeanFactory的所有功能
Spring 框架中的核心组件只有三个:Core、Context 和 Beans。它们构建起了整个 Spring 的骨骼架构。没有它们就不可能有 AOP、Web 等上层的特性功能。下面也将主要从这三个组件入手分析 Spring。
Spring 的设计理念
前面介绍了 Spring 的三个核心组件,如果再在它们三个中选出核心的话,那就非 Beans 组件莫属了,为何这样说,其实 Spring 就是面向 Bean 的编程(BOP,Bean Oriented Programming),Bean 在 Spring 中才是真正的主角。
Bean 在 Spring 中作用就像 Object 对 OOP 的意义一样,没有对象的概念就像没有面向对象编程,Spring 中没有 Bean 也就没有 Spring 存在的意义。 Spring 解决了一个非常关键的问题他可以让你把对象之间的依赖关系转而用配置文件来管理,也就是他的依赖注入机制。
核心组件如何协同工作
前面说 Bean 是 Spring 中关键因素,那 Context 和 Core 又有何作用呢?前面吧 Bean 比作一场演出中的演员的话,那 Context 就是这场演出的舞台背景,而 Core 应该就是演出的道具了。只有他们在一起才能具备能演出一场好戏的最基本的条件。当然有最基本的条件还不能使这场演出脱颖而出,还要他表演的节目足够的精彩,这些节目就是 Spring 能提供的特色功能了。
我们知道 Bean 包装的是 Object,而 Object 必然有数据,如何给这些数据提供生存环境就是 Context 要解决的问题,对 Context 来说他就是要发现每个 Bean 之间的关系,为它们建立这种关系并且要维护好这种关系。所以 Context 就是一个 Bean 关系的集合,这个关系集合又叫 Ioc 容器,一旦建立起这个 Ioc 容器后 Spring 就可以为你工作了。那 Core 组件又有什么用武之地呢?其实Core 就是发现、建立和维护每个 Bean 之间的关系所需要的一些列的工具,从这个角度看来,Core 这个组件叫 Util 更能让你理解。
string为什么用final修饰value
final是Java中的保留关键字,可以用来修饰类,方法和变量。其中,被final修饰的类不能被继承即不能拥有自己的子类,被final修饰方法不能被重写,final修饰的属性、变量初始化之后不能被修改。
String类的不可变性带来的好处总结主要有两点:
- 因为String类的不可变性,才能使得JVM可以实现字符串常量池;字符串常量池可以在程序运行时节约很多内存空间,因为不同的字符串变量指向相同的字面量时,都是指向字符串常量池中的同一个对象。这样一方面能够节约内存,另一方面也提升了性能。
- 因为String类的不可变性,从而保证了字符串对象在多线程环境下是线程安全的。如果String类是可变的,那么会引起很严重的安全问题。我们在很多情况下都是直接通过字符串传递数据,比如数据库的用户名密码、网络编程中的ip和端口,因为字符串是不可变的,所以它的值不能被修改,如果字符串是可变的,那么可以通过改变引用地址指向的值去修改字符串的值,从而导致安全漏洞
springcloud熔断的注解
@EnableHystrix
@DefaultProperties(defaultFallback = "attentionFallBack")
项目
项目有多少张表?后端几个人?你的订单服务写了哪些接口?下订单的流程?Redis只做了缓存吗?讲什么东西缓存起来了?存的什么数据类型?用什么值当key值?RabbitMq是什么,怎么用,如何实现的订单支付超时取消的功能?
==和equal的区别
1.最大的区别是,是运算符,equal是方法
2.比较基本类型,只能用,不能用equal,这里的==比较的是两个变量的值
3.比较String类型,==比较的是内存地址,equal比较的是值
4.比较对象,==和equal比较的都是内存地址,因为equal没有被重写,没有被重写的equal都是object的equal方法
Java中的String str=“abc”; String str=new String(“abc”);和String str = new String();的区别以及==与equals()的不同。
Java运行环境有一个字符串池,由String类维护。执行语句String str=“abc"时,首先查看字符串池中是否存在字符串"abc”,如果存在则直接将"abc"赋给str,如果不存在则先在字符串池中新建一个字符串"abc",然后再将其赋给str。执行语句String
str=new String(“abc”)时,不管字符串池中是否存在字符串"abc",直接新建一个字符串"abc"(注意:新建的字符串"abc"不是在字符串池中),然后将其付给str。前一语句的效率高,后一语句的效率低,因为新建字符串占用内存空间。
引用类型的一定是比较地址吗
???
springboot的自动装载机制
rabbitMq如何防止消息重复
1.AMQP 消费者确认机制
2.消费端处理消息的业务逻辑保持幂等性
以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。
rabbitMq消息确认机制中执行的回调函数做了什么
???
jvm内存划分
程序计数器
Java虚拟机栈
本地方法栈
Java堆
方法区
jvm里计时器的干什么的
?
你了解事务吗?
事务(Transaction):一般是指要做的或所做的事情,由 事务开始(begin transaction) 和 事务结束(end transaction) 之间执行的全体操作组成。
简单的讲就是:要么全部被执行,要么就全部失败。
- 原子性(Atomicity): 一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
- 一致性: 指事务执行前和执行后,数据是完整的。
- 隔离性: 一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性: 也称为永久性,一个事务一旦提交,它对数据库中数据的改变就应该是永久性的保存下来了。
transactional单服务控制
分布式用消息中间件来实现;或者用seata分布式事务
Oracle和MySQL有什么区别吗?
1、Oracle是大型数据库,而MySQL是中小型数据库。但是MySQL是开源的,但是Oracle是收费的,而且比较贵。
2、Oracle的内存占有量非常大,而mysql非常小
3、MySQL支持主键自增长,指定主键为auto increment,插入时会自动增长。Oracle主键一般使用序列。
4、MySQL字符串可以使用双引号包起来,而Oracle只可以单引号
5、MySQL分页用limit关键字,而Oracle使用rownum字段表明位置,而且只能使用小于,不能使用大于。
6、Oracle在处理长字符串的时候,长度是小于等于4000个字节,如果要插入更长的字符串,考虑用CLOB类型,插入修改记录前要做进行修改和 长度的判断,如果为空,如果长度超出返回操作处理.(CLOB类型是内置类型,它一般都作为某一行中的一列,有些数据库也有别名)
7、MySQL中0、1判断真假,Oracle中true false
8、MySQL中命令默认commit,但是Oracle需要手动提交
9、MySQL在windows环境下大小写不敏感 在unix,linux环境下区分大小写,Oracle不区分
mapper.xml里面懒加载的原理
mybatis 会循环处理结果集中返回的每行数据的,在处理之前首先会通过反射调用构造方法来创建 result 对象,结果集中的一行数据最终会映射为一个 result 对象(严格的来说是不对的,结果集中的一行数据在多表连接的情况下可能会映射为多个 result 对象,结果集中的一行数据在多表连接一对多的情况下结果集中的多行数据可能映射一个 result 对象,简单的单表查询结果集中的一行数据映射为一个 result 对象)。
其实在调用构造方法创建 result 对象的时候,构造方法还可能会有参数,需要先把结果集中的参数都提取出来,传给相应的构造方法通过反射创建对象。
mybatis 其实第一步是解析配置文件,把配置文件映射为 mybatis 的 Configuration 类,把配置文件的 xml 属性都映射为 Java 对象中的属性值。xml mapper 文件的处理比较复杂,< resultMap/> 标签映射为 ResultMap 对象, 标签中的< id/> 、< result/>、< association/> 等映射为 ResultMapping 对象。
接着再讲创建好 result 对象之后,mybatis 会循环 resultMappings(标签中的每个子标签都映射为一个 resultMapping,这些 resultMapping 组成了一个集合就是 resultMappings)集合,看有没有需要懒加载的属性,如果有的话,则会为这个 result 对象创建一个代理对象。
这个代理类继承了 result 对象所属的类(被代理类)并重写了被代理类的所有的方法,所以在代理对象上调用懒加载属性的 get 方法(getAuthor())时会触发懒加载动作,mybatis 这时就能发现需要去懒加载一个属性,然后去加载这个属性。
什么情况下才会出现需要懒加载的属性呢?只有 < association property=”author” column=”author_id” select=”selectAuthor” fetchType=”lazy”/>和 < collection property=”xxx” column=”xxx” select=”xxxx” fetchType=”lazy”/> 作为一个子标签出现在 < resultMap/> 标签(也不一定只是 < resultMap/> 标签,< collection/> 等标签事实上也算是一个 < resultMap/> 标签)之内才会出现需要懒加载的属性。select 属性和 fetchType=”lazy” 必须同时出现在 < collection/> 或 < association/> 属性中才需要懒加载,select 表示的是嵌套查询语句的 id ,fetchType=”lazy” 表示的是懒加载。
spring bean的作用域
常用的分页插件
pagehelper
mybatisplus也自带有分页方法
怎么配置tomcat
post,get的区别
- 请求缓存:GET 会被缓存,而post不会
- 收藏书签:GET可以,而POST不能
- 保留浏览器历史记录:GET可以,而POST不能
- 用处:get常用于取回数据,post用于提交数据;post也被一些ui框架使用于取回数据,比如kendo ui中的grid,二者使用因地制宜
- 安全性:post比get安全;这里的安全是相对性,并不是真正意义上的安全
- 请求参数:querystring 是url的一部分get、post都可以带上。 get的querystring(仅支持urlencode编码),post的参数是放在body(支持多种编码);query参数是URL的一部分,而GET、POST等是请求方法的一种,不管是哪种请求方法,都必须有URL,而URL的query是可选的,可有可无。
- 请求参数长度限制:GET方法提交的url参数数据大小没有限制,在http协议中没有对url长度进行限制(不仅仅是querystring的长度),这个限制是特定的浏览器及服务器对他的限制
接口幂等性
1.接口调用存在的问题
现如今我们的系统大多拆分为分布式SOA,或者微服务,一套系统中包含了多个子系统服务,而一个子系统服务往往会去调用另一个服务,而服务调用服务无非就是使用RPC通信或者restful,既然是通信,那么就有可能在服务器处理完毕后返回结果的时候挂掉,这个时候用户端发现很久没有反应,那么就会多次点击按钮,这样请求有多次,那么处理数据的结果是否要统一呢?那是肯定的!尤其在支付场景。
2.什么是接口幂等性
接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...,这就没有保证接口的幂等性
3.什么情况下需要保证接口的幂等性
在增删改查4个操作中,尤为注意就是增加或者修改,
A: 通过代码逻辑判断实现接口幂等性,只能针对一些满足判断的逻辑实现,具有一定局限性;如增加一个订单id或者增加一个支付状态
B: 使用token机制实现接口幂等性,通用性强的实现方法
token机制实现步骤: 1. 生成全局唯一的token,token放到redis或jvm内存,token会在页面跳转时获取.存放到pageScope中,支付请求提交先获取token 2. 提交后后台校验token,执行提交逻辑,提交成功同时删除token,生成新的token更新redis ,这样当第一次提交后token更新了,页面再次提交携带的token是已删除的token后台验证会失败不让提交 token特点: 要申请,一次有效性,可以限流 注意: redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用
数据库的事物隔离级别
Read uncommitted (读未提交):最低级别,以上问题均无法解决。
Read committed (读已提交):读已提交,可避免脏读情况发生。
Repeatable Read(可重复读):确保事务可以多次从一个字段中读取相同的值,在此事务持续期间,禁止其他事务对此字段的更新,可以避免脏读和不可重复读,仍会出现幻读问题。
Serializable (串行化):最严格的事务隔离级别,要求所有事务被串行执行,不能并发执行,可避免脏读、不可重复读、幻读情况的发生。
Linux的常用的指令?
cd 切换目录
ls或者ll 显示所有文件或者目录
mv 修改目录名称或者移动
cp 拷贝
rm 删除
touch 创建文件
cat 查看文件
tar-xvf 解压
ping 看能不能连通
更新数据怎样保证Redis里的数据与数据库一致?
- 更新的时候,先删除缓存,然后再更新数据库。
- 读的时候,先读缓存;如果没有的话,就读数据库,同时将数据放入缓存,并返回响应。
在高并发的场景下,可以先把“修改DB”的操作放到一个JVM队列,后面读请求过来之后,“更新缓存”的操作也放进同一个JVM队列,每个队列,对于一个作业线程,按照队列的顺序,依次执行相关操作,这样就可以保证“更新缓存”一定是在DB修改之后,以保证数据一致性
spingcloud有哪些组件,服务之间如何调用,接口怎么写。
redis 的缓存穿透,缓存击穿,缓存雪崩,之间的区别,以及怎样解决这些问题
sql优化
在项目中,SQL的调优对项目的性能来讲至关重要,所有掌握常见的SQL调优方式是必不可少的,下面介绍几种常见的SQL的调优方式,供借鉴.
1.要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引 2.(1)在经常需要进行检索的字段上创建索引,比如要按照表字段username进行检索,那么就应该在姓名字段上创建索引,如果经常要按照员工部门和员工岗位级别进行检索,那么就应该在员工部门和员工岗位级别这两个字段上创建索引。 (2)创建索引给检索带来的性能提升往往是巨大的,因此在发现检索速度过慢的时候应该首先想到的就是创建索引。 (3)一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。
在where字句中,如果索引列是计算或者函数的一部分,DBMS的优化器将不会使用索引而使用全表查询,函数 属于计算的一种,同时在in和exists中通常情况下使用EXISTS,因为in不走索引 效率低
程序中通常是根据用户的输入来动态执行SQL,这时应该尽量使用参数化SQL,这样不仅可以避免SQL注入漏洞 攻击,最重要数据库会对这些参数化SQL进行预编译,这样第一次执行的时候DBMS会为这个SQL语句进行查询优化 并且执行预编译,这样以后再执行这个SQL的时候就直接使用预编译的结果,这样可以大大提高执行的速度。
DBMS一般采用自下而上的顺序解析where字句,根据这个原理表连接最好写在其他where条件之前,那些可以 过滤掉最大数量记录。
每次执行SQL的时候都要建立网络连接、进行权限校验、进行SQL语句的查询优化、发送执行结果,这个过程 是非常耗时的,因此应该尽量避免过多的执行SQL语句,能够压缩到一句SQL执行的语句就不要用多条来执行。
避免使用HAVING字句,因为HAVING只会在检索出所有记录之后才对结果集进行过滤,而where则是在聚合前 刷选记录,如果能通过where字句限制记录的数目,那就能减少这方面的开销。HAVING中的条件一般用于聚合函数 的过滤,除此之外,应该将条件写在where字句中。
当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减 少哪些友列名歧义引起的语法错误。
当SQL语句需要union两个查询结果集合时,即使检索结果中不会有重复的记录,如果使用union这两个结果集 同样会尝试进行合并,然后在输出最终结果前进行排序,因此如果可以判断检索结果中不会有重复的记录时候,应 该用union all,这样效率就会因此得到提高。
简化SQL语句的重要方法就是采用临时表暂存中间结果,但是,临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在tempdb中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。 但是也得避免频繁创建和删除临时表,以减少系统表资源的消耗。
尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。 不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。
1.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描, 如:
可以在num上设置默认值0,确保表中num列没有null值, 然后这样查询:
可以这样查询:
4.不能前置百分
若要提高效率,可以考虑全文检索。
对于连续的数值,能用 between 就不要用 in 了:
6.如果查询的两个表大小相当,那么用in和exists差别不大。 in: 例如:表A(小表),表B(大表)
相反的
1.如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志
1.最高效的删除重复记录方法 ( 因为使用了ROWID)例子:
1.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
jwt的使用
JWT的结构:
header 部分主要是两部分内容,一个是 Token 的类型,另一个是使用的算法,比如下面类型就是 JWT,使用的算法是 HS256,就是SHA-256,和md5一样是不可逆的散列算法。
{
“alg”: “HS265”,
“typ”: “JWT”
}
Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也可以添加其它需要的内容。下面是标准字段:
iss:Issuer,发行者
sub:Subject,主题
aud:Audience,观众
exp:Expiration time,过期时间
nbf:Not before
iat:Issued at,发行时间
jti:JWT ID
Payload(有效负载): 包含声明(有关用户实体和其他数据的声明),使用Base64进行编码
Base64是一种可逆的编码,因此不要在负载里存入敏感数据!
{
“id”: “1”,
“name”: “BLU”,
“admin”: true
}
JWT 的最后一部分是Signature(签名):使用编码后的header和payload以及一个指定密钥,这个相当于是一个密码,这个密码秘密地存储在服务端。然后使用header中指定的算法(HS265)进行签名.
签名的作用是保证JWT没有被篡改过
客户端收到这个 Token 以后把它存储下来,下会向服务端发送请求的时候就带着这个 Token 。服务端收到这个 Token ,然后进行验证,通过以后就会返回给客户端想要的资源。验证的过程就是
根据传过来的token再生成一下第三部分Signature,然后两个比对一下,一致就验证通过。
springboot的启动流程
javaweb开发流程
网站架构
单机时代(纯依赖RDBMS)
优点:简单、快速迭代达成业务目标;
缺点:存在单点、谈不上高可用;
技术点:应用设计要保证可扩展;
单机时代+缓存出场
优点:简单有效、方便维护;
缺点:存在单点、谈不上高可用;
技术点:客户端(浏览器)缓存、前端页面缓存、页面片段缓存、本地数据缓存/数据库缓存、远程缓存;
- 页面缓存:客户端缓存,减少对网站的访问;
- 本地缓存:访问速度快,但数据量有限,减少对DB查询;
- 远程缓存:远程访问,可以集群,因此容量不受限制;
数据服务与应用分离
优点:简单有效、方便维护、提高不同Server对硬件资源的利用率;
缺点:存在单点、谈不上高可用;
技术点:文件服务器部署、数据库服务器,扩展数据访问模块;
分离后三台 Server 对硬件资源的需求各不相同:
- 应用服务器:需要更快更强大的 CPU;
- 数据库服务器:需要更快的硬盘和更大的内存;
- 文件服务器:需要更大的硬盘;
数据库读写分离
优点:简单有效、降低数据库单台压力;
缺点:读写分离,增加程序难度,架构变复杂,维护难度增加;
技术点:数据库主从同步部署,扩展数据访问模块,实现读写分离;
应用出现瓶颈 负载均衡集群
优点:增加服务器和HA机制,系统性能及可用性得到保证;
缺点:应用之间缓存、Session一致性问题;
技术点:负载均衡;
通过集群解决高并发、海量数据问题的常用手段,实现系统的可伸缩性。通过负载均衡调度器,可将用户访问分发到集群中的某台 Server 上,应用服务器的负载压力不再成为整个网站的瓶颈。
集中式缓存 Session集中存储
优点:应用之间缓存、Session一致,存储无限制,可以扩展;
缺点:不如本地缓存访问快,缓存服务器、Session服务器等仍存在单点问题;
技术点:缓存服务器部署、Session集中存储方案;
使用动静分离
优点:减轻应用负载压力,针对静态文件缓存;
缺点:静态文件缓存更新失效问题;
技术点:动静分离、静态文件缓存方案;
使用反向代理和CDN加速网站响应:CDN 和反向代理的基本原理都是缓存,区别在于:
- CDN部署在网络提供商的机房;
- 反向代理则部署在网站的中心机房;
使用 CDN 和反向代理的目的都是尽早返回数据给用户,一方面加快用户访问速度,另一方面也减轻后端服务器的负载压力。
使用反向代理和 CDN 加速网站响应
优点:减轻应用负载压力,异地缓存有效解决不同地方用户访问过慢的问题;
缺点:成本大幅增加,架构进一步复杂化,也维护难度进一步增大,静态文件缓存更新失效问题;
技术点:CDN、反向代理方案;
使用NoSQL和搜索引擎
优点:降低DB依赖;
缺点:单点问题,谈不上高可用;
技术点:NoSQL、搜索引擎、分布式;
到目前为止,一个能够承载日均百万级访问量的中型网站架构基本介绍完了。
如何保证高可用
在做扩展满足了基本的性能需求后,我们会逐渐关注“可用性”(也就是我们通常听别人吹牛时说的SLA、几个9)。如何保证真正“高可用”,也是个难题。
对关键应用/服务,做集群冗余负载,这也是保证高可用比较常用的手段:
- 文件系统、数据库系统集群;
- 静态内容服务器集群;
- CDN服务器集群;
- 反向代理服务器集群;
- 负载均衡调度器集群;
- 分布式NoSQL服务器集群;
- 搜索引擎服务器集群;
- 分布式缓存服务器集群;
- 分布式Session服务器集群;