java面试题集锦

请简要写出搭建java开发环境的步骤和java跨平台原理。

Java跨平台原理: java是运行jvm中,要想运行我们的java程序必须在我们的电脑上面安装一个jvm,因为java是利用jvm的原理,才实现的跨平台

Java开发环境需要些什么

1、适用于我们开发环境的jdk

2、对应开发环境eclipse,Idea

3、还需要web服务器(tomcat)

int和Integer都可以代表一个整数,这两者在使用上有什么区别吗?为什么JDK中要设计两个数据类型来表示同一种数据

Int 它是一个基本数据类型

Integer是int的一个包装类,它是引用数据类型,在java中给它提供了大量的方法与字段,Integer可以调用,int不可以调用,因为int基本数据类型,是不能调用方法与字段的

谈谈你对面向对象特征的理解并举例说明

封装: 封装的目的就是安全,防止外部人员 破坏性的访问

继承: 继承的目的,提高代码的复用性,子类只需要编写自己特有的功能

抽象:把现实生活中的对象,抽象为类

多态: 一种类型多种形态,屏蔽各子类的实现差异

谈谈你对抽象类和接口的理解。

抽象类: 它有普通方法,有构造方法,抽象方法,字段,它虽然有构造方法,但是不能实例化,类与抽象类的关系是继承关系, 并且只能是单继承

接口: 它内部成员只有 全局常量 都是public static final, 抽象方法 并且它的抽象方法都是 public abstract修饰的,类与接口之间的关系是实现关系 并且多实现,接口与接口之间是可以多继承的

请说说方法覆写和方法重载的区别
为什么要覆写:当父类的行为不满足子类需求的时候,子类就要覆写父类的方法
方法覆写:

\1. 方法签名必须一致

\2. 子类的返回值类型必须是父类的返回值类型的子类或者相等

\3. 子类的访问权限修饰符必须大于或者等于父类的访问权限修饰符

\4. 子类抛出的异常必须是父类抛出异常的子类或者相等(只针对于非运行时异常)

不能被子类覆写的:private,final,static所修饰的方法,字段没有覆写一说

为什么要进行方法重载:多个方法,功能差不多的时候,可以进行方法重载,因为减少程序员的记忆量

方法重载:

\1. 方法名相同,参数列表不同

\2. 必须要在同一个类中

\3. 与访问权限修饰符无关

\4. 与返回值类型无关

有了基本数据类型,为什么还需要包装类型?

int与Integer:
int与Integer都表示一个整数,而int是基本数据类型,而Integer是一个包装类,int是没有方法的
而Integer是有方法的

Java是一个面相对象的编程语言,基本类型并不具有对象的性质,为了让基本类型也具有对象的特征,就出现了包装类型(如我们在使用集合类型Collection时就一定要使用包装类型而非基本类型),它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。 另外,当需要往ArrayList,HashMap中放东西时,像int,double这种基本类型是放不进去的,因为容器都是装object的,这是就需要这些基本类型的包装器类了。

说一下"=="和equals方法究竟有什么区别?

==与equals都是比较的意思
==能用于基本数据类型也能用于引用数据类型,如果用于基本数据类型比较的是值,如果使用到引用数据类型比较的是地址
equals只能用于引用数据类型,它一般都是比较的是值

讲一下String和StringBuilder的区别(final)?StringBuffer和StringBuilder的区别?

String StringBuillder StringBuffer都是用来表示操作字符串

而String是一个固定字符串,StringBuffer与StringBuilder是一个可变的字符串,

String是内容不可变的字符串,

StringBuillder 与StringBuffer,是内容可以改变的字符串,

StringBuffer是线程安全的,StringBuilder是线程不安全的,StringBuilder的效率要高于StringBuffer

java中的集合

Java中的集合:分为value,key–vale(Conllection Map)两种。

存储值:分为List 和Set.

List:是有序的,可以重复的。

Set:是无序的,不可以重复的。根据equals和hashcode判断,也就是如果一个对象要存储在Set中,必须重写equals和hashCode方法。

存储key-value的为map.

ArrayList和LinkedList的区别

ArrayList底层使用时数组。LinkedList使用的是链表

数组查询具有所有查询特定元素比较快。而插入和删除和修改比较慢(数组在内存中是一块连续的内存,如果插入或删除是需要移动内存)。

链表不要求内存是连续的,在当前元素中存放下一个或上一个元素的地址。查询时需要从头部开始,一个一个的找。所以查询效率低。插入时不需要移动内存,只需改变引用指向即可。所以插入或者删除的效率高。

HashMap与HashTable的区别?HashTable和ConcurrentHashMap的区别?

相同点:HashMap和HasheTalbe都可以使用来存储key–value的数据。

区别:

HashMap是可以把null作为key或者value的,而HashTable是不可以的。

HashMap是线程不安全的,效率较高。而HashTalbe是线程安全的,效率较低。

我想线程安全但是我又想效率高?

通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。

实现一个拷贝文件的工具类使用字节流还是字符流?

不能确定,有可以能有字节流,比如:图片、声音、图像等,所以为考虑到通用性,一般都会使用字节流。

讲一下线程的几种实现方式?启动方式?区分方式?
实现方式

1、通过继承Thread类实现一个线程

2、通过实现Runnable接口实现一个线程

继承扩展性不强,java总只支持单继承,如果一个类继承Thread就不能继承其他的类了。

怎么启动?

Thread thread = new Thread(继承了Thread的对象/实现了Runnable的对象)

thread.setName(“设置一个线程名称”);

thread.start();

启动线程使用start方法,而启动了以后执行的是run方法。

怎么区分线程?

在一个系统中有很多线程,每个线程都会打印日志,我想区分是哪个线程打印的怎么办?

thread.setName(“设置一个线程名称”); 这是一种规范,在创建线程完成后,都需要设置名称。

有没有使用过线程并发库?

JDK5中增加了Doug Lea的并发库,这一引进给Java线程的管理和使用提供了强大的便利性。

java.util.current包中提供了对线程优化、管理的各项操作。该包提供了线程的运行,线程池的创建,线程生命周期的控制.

Java通过Executors提供四个静态方法创建四种线程池,:

*newCachedThreadPool:*创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool: 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

*newScheduledThreadPool :*创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor :创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

线程池的作用

1、限定线程的个数,不会由于线程过多导致系统运行缓慢或崩溃

2、线程池不需要每次都去创建或销毁,节约了资源、

3、线程池不需要每次都去创建,响应时间更快。

讲一下什么是设计模式?常用的设计模式有哪些?

设计模式就是经过前人无数次的实践总结出的,设计过程中可以反复使用的、可以解决特定问题的设计方法。

单例(饱汉模式、饥汉模式)

1、构造方法私有化,让出了自己类中能创建外其他地方都不能创建

2、在自己的类中创建一个单实例(饱汉模式是一出来就创建单实例,而饥汉模式只会在需要的时候才会创建)

3、提供一个方法获取该实例对象(创建时需要进行方法同步)

工厂模式:

Spring IOC就是使用了工厂模式,对象的创建交给一个工厂去创建。

代理模式:

Spring AOP就是使用的动态代理。

java web部分

讲一下http get和post请求的区别?

GET和POST都是http的请求方式,用户通过不同的http的请求方式完成对资源(url)的不同操作。

GET,POST,PUT,DELETE就对应着对这个资源的查 ,改 ,增 ,删 4个操作,具体点来讲GET一般用于获取/查询资源信息,而POST一般用于更新资源信息

1、Get请求提交的数据会在地址栏显示出来,而post请求不会再地址栏显示出来.

2、传输数据的大小:Get请求由于浏览器对地址长度的限制而导致传输的数据有限制。而POST请求不会因为地址长度限制而导致传输数据限制。

3、安全性,POST的安全性要比GET的安全性高。

简单说一下servlet的生命周期?

servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。

运行流程:

加载Servlet的class---->实例化Servlet----->调用Servlet的init完成初始化---->响应请求(Servlet的service方法)----->Servlet容器关闭时(Servlet的destory方法)

Servlet启动时,开始加载servlet生命周期开始。Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候(服务器关闭)调用其destroy方法。

Servlet API中forward() 与redirect()的区别?

1、forward是服务器端的转向而redirect是客户端的跳转。

2、使用forward浏览器的地址不会发生改变。而redirect会发生改变。

3、Forward是一次请求中完成。而redirect是重新发起请求。

4、Forward是在服务器端完成,而不用客户端重新发起请求,效率较高。

JSP和Servlet有哪些相同点和不同点?

JSP是Servlet技术的扩展,所有的jsp文件都会被翻译为一个继承HttpServlet的类。也就是jsp最终也是一个Servlet.这个Servlet对外提供服务。

Servlet和JSP最主要的不同点在于JSP侧重于视图,Servlet主要用于控制逻辑。

Servlet如果要实现html的功能,必须使用Writer输出对应的html,比较麻烦。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件,做界面展示比较方便而嵌入逻辑比较复杂。

jsp有哪些内置对象?作用分别是什么?
九个内置的对象:
request:

用户端请求,此请求会包含来自GET/POST请求的参数

response :

网页传回用户端的回应

pageContext :

网页的属性是在这里管理

session :

与请求有关的会话期

application servlet:

正在执行的内容

out :

用来传送回应的输出

config servlet:

的构架部件

page JSP:

网页本身

exception :

针对错误网页,未捕捉的例外

四大作用域:

pageContext ,request, session ,application ,可以通过jstl从四大作用域中取值.

Jsp传递值顺序:

request ,session ,application ,cookie也能传值

说一下session和cookie的区别?你在项目中都有哪些地方使用了?

Session和cookie都是会话(Seesion)跟踪技术。

Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。但是Session的实现依赖于Cookie,sessionId(session的唯一标识需要存放在客户端).

cookie 和session 的区别:

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

MVC的各个部分都有那些技术来实现?

M(Model) 模型 javabean

V(View) 视图 html jsp volicity freemaker

C(Control) 控制器 Servlet,Action

Jsp+Servlet+javabean 最经典mvc模式,实际上就是model2的实现方式,就是把视图和逻辑隔离开来

Model1的方式 jsp+service+dao

MOdel2的方式 jsp+servlet+service+dao

使用struts2和springmvc这样的mvc框架后,jsp+核心控制器+action+javabean

数据库相关

数据库的分类及常用的数据库

数据库分为:关系型数据库和非关系型数据库

​ 关系型:mysql oracle sqlserver等

​ 非关系型:redis,memcache,mogodb,hadoop等

简单介绍一下关系数据库三范式?

​ 范式就是规范,就是关系型数据库在设计表时,要遵循的三个规范。

要想满足第二范式必须先满足第一范式,要满足第三范式必须先满足第二范式。

第一范式(1NF):

指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。列数据的不可分割

二范式(2NF):

要求数据库表中的每个行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。(主键)

满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。(外键)

反三范式,有的时候为了效率,可以设置重复或者可以推导出的字段, 订单(总价)和订单项(单价)

事务四个基本特征或 ACID 特性。
原子性:

表示事务内操作不可分割。要么都成功、要么都是失败.

一致性:

要么都成功、要么都是失败.后面的失败了要对前面的操作进行回滚。

隔离性:

一个事务开始后,不能后其他事务干扰。

持久性/持续性:

表示事务开始了,就不能终止。

事务是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。

一个转账必须 A账号扣钱成功,B账号加钱成功,才算正真的转账成功。

事务必须满足四大特征:原子性,一致性,隔离性持久性/持续性

mysql数据库的默认的最大连接数?
最大连接数:

在数据库安装时都会有一个默认的最大连接数为100

为什么需要最大连接数?

特定服务器上面的数据库只能支持一定数目同时连接,这时候我们一般都会设置最大连接数(最多同时服务多少连接)。

说一下msyql的分页?Oracle的分页?
为什么需要分页?

在很多数据是,不可能完全显示数据。进行分段显示.

Mysql的分页:是使用关键字limit来进行分页的 limit offset,size 表示从多少索引去多少位.

Oracle的分页:大部分情况下,我们是记不住了。说思路,要使用三层嵌套查询。

Oracle的分页是使用了三层嵌套查询。如果在工作中使用了,可以到原来的项目中拷贝或上网查询。

简单讲一下数据库的存储过程的使用场景?
数据库存储过程具有如下优点:
1、存储过程只在创建时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,因此使用存储过程可以大大提高数据库执行速度。
2、通常,复杂的业务逻辑需要多条 SQL 语句。

这些语句要分别地从客户机发送到服务器,当客户机和服务器之间的操作很多时,将产生大量的网络传输。如果将这些操作放在一个存储过程中,那么客户机和服务器之间的网络传输就会大大减少,降低了网络负载。

3、存储过程创建一次便可以重复使用,从而可以减少数据库开发人员的工作量。
4、安全性高:

存储过程可以屏蔽对底层数据库对象的直接访问,使用 EXECUTE 权限调用存储过程,无需拥有访问底层数据库对象的显式权限。

正是由于存储过程的上述优点,目前常用的数据库都支持存储过程,例如 IBM DB2,Microsoft SQL Server,Oracle,Access 等,开源数据库系统 MySQL 也在 5.0 的时候实现了对存储过程的支持。

用jdbc怎么调用存储过程?
贾琏欲执事:

1.加载驱动

2.获取连接

3.设置参数

4.执行

5.释放连接

常用SQL
简单说一下你对jdbc的理解?

Java database connection java数据库连接.数据库管理系统(mysql oracle等)是很多,每个数据库管理系统支持的命令是不一样的。

Java只定义接口,让数据库厂商自己实现接口,对于我们者而言。只需要导入对应厂商开发的实现即可。然后以接口方式进行调用.(mysql + mysql驱动(实现)+jdbc)

写一个简单的jdbc的程序。写一个访问oracle数据的jdbc程序?
贾琏欲执事:
加载驱动:

(com.mysql.jdbc.Driver,oracle.jdbc.driver.OracleDriver)

获取连接:

(DriverManager.getConnection(url,usernam,passord))

设置参数:

Statement PreparedStatement

​ cstmt.setXXX(index, value);

执行 :

executeQuery executeUpdate

释放连接:

(是否连接要从小到大,必须放到finnaly)

JDBC中的PreparedStatement相比Statement的好处
1:PreparedStatement是预编译的,比Statement速度快
2:代码的可读性和可维护性:

虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次

3:安全性:

PreparedStatement可以防止SQL注入攻击,而Statement却不能。

好处:

如果你使用预编译语句你传入的任何内容就不会和原来的语句发生任何匹配的关系,只要全使用预编译语句你就用不着对传入的数据做任何过虑。而如果使用普通的statement,有可能要对drop等做费尽心机的判断和过虑。

redis部分

Redis支持哪几种数据类型?

String、List、Set、Sorted Set、hashes

Redis有哪几种数据淘汰策略?
volatile-lru:

从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:

从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:

从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru:

从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:

从数据集(server.db[i].dict)中任意选择数据淘汰

no-enviction(驱逐):

禁止驱逐数据

redis

确定驱逐某个键值对后,会删除这个数据并,并将这个数据变更消息发布到本地(AOF 持久化)和从机(主从连接)。

Redis集群方案应该怎么做?都有哪些方案?

1.twemproxy,大概概念是,它类似于一个代理方式,使用方法和普通redis无任何区别,设置好它下属的多个redis实例后,使用时在本需要连接redis的地方改为连接twemproxy,它会以一个代理的身份接收请求并使用一致性hash算法,将请求转接到具体redis,将结果再返回twemproxy。使用方式简便(相对redis只需修改连接端口),对旧项目扩展的首选。 问题:twemproxy自身单端口实例的压力,使用一致性hash后,对redis节点数量改变时候的计算值的改变,数据无法自动移动到新的节点。

12.codis,目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在 节点数量改变情况下,旧节点数据可恢复到新hash节点。

3.redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。

4.在业务代码层实现,起几个毫无关联的redis实例,在代码层,对key 进行hash计算,然后去对应的redis实例操作数据。 这种方式对hash层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。

Redis集群方案什么情况下会导致整个集群不可用

有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用。

Redis有哪些适合的场景

(1)、会话缓存(Session Cache)

(2)、全页缓存(FPC)

(3)队列

Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。

(4),排行榜/计数器

(5)发布/订阅

(6)实时防攻击系统

Redis如何设置密码及验证密码?

设置密码:config set requirepass 123456

授权密码:auth 123456

Redis集群的主从复制模型是怎样的?

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品

Redis集群最大节点个数是多少?

16384个。

Redis集群如何选择数据库?

Redis集群目前无法做数据库选择,默认在0数据库。

Redis回收进程如何工作的?

1,一个客户端运行了新的命令,添加了新的数据。

2,Redi检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。

3,一个新的命令被执行,等等。

4,所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。

如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。

分布式Redis是前期做还是后期规模上来了再做好?为什么?

既然Redis是如此的轻量(单实例只使用1M内存),为防止以后的扩容,最好的办法就是一开始就启动较多实例。即便你只有一台服务器,你也可以一开始就让Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。

一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来说这操作起来可能比较麻烦,但是从长久来看做这点牺牲是值得的。

这样的话,当你的数据不断增长,需要更多的Redis服务器时,你需要做的就是仅仅将Redis实例从一台服务迁移到另外一台服务器而已(而不用考虑重新分区的问题)。一旦你添加了另一台服务器,你需要将你一半的Redis实例从第一台机器迁移到第二台机器。

一个Redis实例最多能存放多少的keys?List、Set、Sorted Set他们最多能存放多少元素

理论上Redis可以处理多达232的keys,并且在实际中进行了测试,每个实例至少存放了2亿5千万的keys。我们正在测试一些较大的值。

任何list、set、和sorted set都可以放232个元素。

换句话说,Redis的存储极限是系统中的可用内存值。

Redis常见性能问题和解决方案?

(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件

(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次

(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内

(4) 尽量避免在压力很大的主库上增加从库

(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3…

这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

全文检索部

在并发情况下,Elasticsearch如果保证读写一致?

1,可以通过版本号使用乐观并发控制,以确保新版本不会被旧版本覆盖,由应用层来处理具体的冲突;

2,另外对于写操作,一致性级别支持quorum/one/all,默认为quorum,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点上重建。

3,对于读操作,可以设置replication为sync(默认),这使得操作在主分片和副本分片都完成后才会返回;如果设置replication为async时,也可以通过设置搜索请求参数_preference为primary来查询主分片,确保文档是最新版本。

Elasticsearch在部署时,对Linux的设置有哪些优化方法?
  1. 64 GB 内存的机器是非常理想的, 但是32 GB 和16 GB 机器也是很常见的。少于8 GB 会适得其反。

  2. 如果你要在更快的 CPUs 和更多的核心之间选择,选择更多的核心更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。

  3. 如果你负担得起 SSD,它将远远超出任何旋转介质。 基于 SSD 的节点,查询和索引性能都有提升。如果你负担得起,SSD 是一个好的选择。

  4. 即使数据中心们近在咫尺,也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。

  5. 请确保运行你应用程序的 JVM 和服务器的 JVM 是完全一样的。 在 Elasticsearch 的几个地方,使用 Java 的本地序列化。

  6. 通过设置gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time可以在集群重启的时候避免过多的分片交换,这可能会让数据恢复从数个小时缩短为几秒钟。

  7. Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。最好使用单播代替组播。

  8. 不要随意修改垃圾回收器(CMS)和各个线程池的大小。

  9. 把你的内存的(少于)一半给 Lucene(但不要超过 32 GB!),通过ES_HEAP_SIZE 环境变量设置。

  10. 内存交换到磁盘对服务器性能来说是致命的。如果内存交换到磁盘上,一个 100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出 swapping 对于性能是多么可怕。

  11. Lucene 使用了大量的文件。同时,Elasticsearch 在节点和 HTTP 客户端之间进行通信也使用了大量的套接字。 所有这一切都需要足够的文件描述符。你应该增加你的文件描述符,设置一个很大的值,如 64,000。

Elasticsearch和Lucene的区别

Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中。而Elasticsearch是分布式的实时分析搜索引擎。

Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:

分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。

实时分析的分布式搜索引擎。

可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。

Bulk一次最大处理多少数据量?

bulk会把将要处理的数据载入内存中,所以数据量是有限制的

最佳的数据量不是一个确定的数值,它取决于你的硬件,你的文档大小以及复杂性,你的索引以及搜索的负载。

一般建议是1000-5000个文档,如果你的文档很大,可以适当减少队列,大小建议是5-15MB,默认不能超过100M,可以在es的配置文件中修改这个值http.max_content_length: 100mb

在es的使用中创建索引不设置ID用什么命令

POST ES内置ID创建

post用于局部更新:接受一个局部文档参数 doc,它会合并到现有文档中,对象合并在一起,存在的标量字段被覆盖,新字段被添加。且需要_update的后缀

Elasticsearch常用的DSL查询标签有哪些
Query查询上下文:

在Query查询上下文中,查询会回答这个问题–“这个文档匹不匹配查询条件,它的相关性高么?”

除了决定文档是够匹配,针对匹配的文档,查询语句还会计算一个_score相关性分值,分数越高,匹配度越高,默认返回是越靠前。这里关于分值的计算不再介绍,以后再做介绍。

Filter过滤器上下文:

在Filter过滤器上下文中,查询会回答这个问题–“这个文档是否匹配”

这个结果要么“不是”要么“是”,不会计算分值问题,也不会关心返回的排序问题,这样性能方面就比Query查询高了。

range 范围查询

terms:跟term有点类似,但可以同时指定多个条件

exists: 此索引中包含指定字段的所有数据(即此字段值不为空)

missing:此索引中不包含指定字段的所有数据(即此字段的值为空)

bool过滤:用来合并多个过滤条件的查询结果的布尔逻辑,必须包含must和should中的一个或多个。它包含以下一些操作

must: 相当于and

must_not: 相当于 not

should: 相当于or(连接多个匹配条件,列表形式)

Elasticsearch怎么创建索引(基础重点)

Elasticsearch -> 索引库Indices -> 类型Types -> 文档Documents -> 字段Fields

ES集群可以包含多个索引(indices)(数据库),每一个索引库中可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。

前端部分

简单说一下html,css,javascript在网页开发中的定位?

HTML 超文本标记语言 定义网页的结构

CSS 层叠样式表,用来美化页面

JavaScript主要用来验证表单,做动态交互(其中ajax)

简单介绍一下Ajax?

什么是Ajax? 异步的javascript和xml

作用是什么?通过AJAX与服务器进行数据交换,AJAX可以使网页实现布局更新。

这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

怎么来实现Ajax XmlHttpRequest对象,使用这个对象可以异步向服务器发送请求,获取获取响应,完成局部更新。Open send responseText/responseXML 局部响应.

使用场景 登陆失败时不跳转页面,注册时提示用户名是否存在,二级联动等等使用场景

js和jQuery的关系

jQuery是一个js框架,封装了js的属性和方法。让用户使用起来更加便利。

,并且增强了js的功能.

使用原生js是要处理很多兼容性的问题(注册事件等),由jQuery封装了底层,就不用处理兼容性问题。

原生的js的dom和事件绑定和Ajax等操作非常麻烦,jQuery封装以后操作非常方便。

jQuery的常用选择器?

ID选择器 通过ID获取一个元素

Class选择器 通过类(css)获取元素

标签选择器 通过标签获取元素

通用选择器(*) 获取所以的元素

div.myCls 获取有myCls这个类的div

层次选择器

​ 儿子选择器 > 获取下面的子元素

​ 后代选择器 空格 获取下面后代,包括儿子、孙子等后代

属性选择器

​ Tag[attrName=’test’] 获取有属性名为xxxx并且属性的值为test的所有xxx标签

​ 吃饭

​ 睡觉

Input[name=’hobby’],表示获取属性名为name并且name属性值为hobby的的所有input标签元素

Jquery的Ajax和原生Js实现Ajax有什么关系

jQuery中的Ajax也是通过原生的js封装的。封装完成后让我们使用起来更加便利,不用考虑底层实现或兼容性等处理。

如果采用原生js实现Ajax是非常麻烦的,并且每次都是一样的。如果我们不使用jQuery我们也要封装Ajax对象的方法和属性。有像jQuery这些已经封装完成,并经过很多企业实际的框架,比较可靠并且开源。我们就不需要封装,直接使用成熟的框架(jQuery)即可.

简单说一下html5?你对现在的那些新技术有了解?

Html5是最新版本的html,是在原来html4的基础上增强了一些标签。

Html增加一些像画板、声音、视频、web存储等高级功能。但是html5有一个不好的地方,那就是html5太强调语义了,导致开发中都不知道要选择那个标签。

在做页面布局是,无论头部、主题、导航等模块都使用div来表示,但是html5的规范,需要使用不同的标签来表示。(header footer等)

你对现在的那些新技术有了解

Html5 css3等

简单说一下css3?

Css3是最新版本的css,是对原理css2的功能增强。

Css3中提供一些原来css2中实现起来比较困难或者不能实现的功能。

​ 1、盒子圆角边框

​ 2、盒子和文字的阴影

​ 3、渐变

​ 4、转换 移动、缩放、旋转等

​ 5、过渡、动画都可以使用动画。

​ 6、可以使用媒体查询实现响应式网站。

Css3最大缺点就是要根据不同的浏览器处理兼容性。对应有一些处理兼容性的工具。不用担心.

bootstrap是什么?

BootStrap是一个移动设备优先的UI框架。我们可以不用谢任何css,js代码就能实现比较漂亮的有交互性的页面。我们程序员对页面的编写是有硬伤的,所有要自己写页面的话就要使用类似于bootstrap这样的UI框架。

平时用得很多的:

1、模态框

2、表单,表单项

3、布局

4、删格系统

框架部分

什么是框架?

框架(Framework)是一个框子——指其约束性,也是一个架子——指其支撑性。

好处:

框架本身一般不完整到可以解决特定问题,但是可以帮助您快速解决特定问题;

框架天生就是为扩展而设计的;

框架里面可以为后续扩展的组件提供很多辅助性、支撑性的方便易用的实用工具(utilities)

MVC模式

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

最简单的、最经典就是Jsp(view) +Servlet(controller) + JavaBean(model)

逻辑流程:

1、当控制器收到来自用户的请求

2、控制器调用JavaBean完成业务

3、完成业务后通过控制器跳转JSP页面的方式给用户反馈信息

4、Jsp个 用户做出响应。

​ 控制器都是核心

MVC框架

为了解决传统MVC模式(Jsp + Servlet + JavaBean)的一些问题而出现的框架。

现在比较常用的MVC框架有:

struts

webwork

Struts2

Spring MVC

简单讲一下struts2的执行流程?

一个请求在Struts2框架中的处理大概分为以下几个步骤:

1、客户端浏览器发送请求

2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin);

3、接着FilterDispatcher(StrutsPrepareAndExecuteFilter)被调用,FilterDispatcher

(StrutsPrepareAndExecuteFilter)询问ActionMapper来决定这个请求是否需要调用某个Action;

4、如果ActionMapper决定需要调用某个Action,FilterDispatcher

​ (StrutsPrepareAndExecuteFilter)把请求的处理交给ActionProxy;

5、ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类;

6、ActionProxy创建一个ActionInvocation的实例。

7、ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。

8、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2框架中继承的标签。在这个过程中需要涉及到ActionMapper。

面试:

1、浏览器发送请求,经过一系列的过滤器后,到达核心过滤器(StrutsPrepareAndExecuteFilter).

2、StrutsPrepareAndExecuteFilter通过ActionMapper判断当前的请求是否需要某个Action处理,如果不需要,则走原来的流程。如果需要则把请求交给ActionProxy来处理

3、ActionProxy通过Configuration Manager询问框架的配置文件(Struts.xml),找到需要调用的Action类;

4、创建一个ActionInvocation实例,来调用Action的对应方法来获取结果集的name,在调用前后会执行相关拦截器。

5、通过结果集的Name知道对应的结果集来对浏览器进行响应。

大体流程:

拦截、判断、寻找、执行、响应

Struts2中的拦截器,你都用它干什么?

java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。

​ 在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。

面试:

​ struts2中的的功能(参数处理、文件上传、字符编码等)都是通过系统拦截器实现的。

如果业务需要,当然我们也可以自定义拦截器,进行可插拔配置,在执行Action的方法前后、加入相关逻辑完成业务。

使用场景:

1、用户登录判断,在执行Action的前面判断是否已经登录,如果没有登录的跳转到登录页面。

2、用户权限判断,在执行Action的前面判断是否具有,如果没有权限就给出提示信息。

3、操作日志…

简单讲一下SpringMVC的执行流程?
  1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;

  2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;

  3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)

  4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

​ HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

​ 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

​ 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

​ 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

​ 5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;

​ 6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中ViewResolver)返回给DispatcherServlet ;

​ 7. ViewResolver 结合Model和View,来渲染视图

​ 8. 将渲染结果返回给客户端。

面试:

1、 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获(捕获)

2、 DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;(查找handler)

3、 DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller), Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象(执行handler)

4、DispatcherServlet 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver) (选择ViewResolver)

5、通过ViewResolver 结合Model和View,来渲染视图,DispatcherServlet 将渲染结果返回给客户端。(渲染返回)

快速记忆技巧:

核心控制器捕获请求、查找Handler、执行Handler、选择ViewResolver,通过ViewResolver渲染视图并返回

说一下struts2和springMVC有什么不同?

目前企业中使用SpringMvc的比例已经远远超过Struts2,那么两者到底有什么区别,是很多初学者比较关注的问题,下面我们就来对SpringMvc和Struts2进行各方面的比较:

1.核 心控制器(前端控制器、预处理控制器):对于使用过mvc框架的人来说这个词应该不会陌生,核心控制器的主要用途是处理所有的请求,然后对那些特殊的请求 (控制器)统一的进行处理(字符编码、文件上传、参数接受、异常处理等等),spring mvc核心控制器是Servlet,而Struts2是Filter。

2.控制器实例:Spring Mvc会比Struts快一些(理论上)。Spring Mvc是基于方法设计,而Sturts是基于对象,每次发一次请求都会实例一个action,每个action都会被注入 属性,而Spring更像Servlet一样,只有一个实例,每次请求执行对应的方法即可(注意:由于是单例实例,所以应当避免全局变量的修改,这样会产生线程安全问题)。

3.管理方式:大部分的公司的核心架构中,就会使用到spring,而spring mvc又是spring中的一个模块,所以spring对于spring mvc的控制器管理更加简单方便,而且提供了全 注解方式进行管理,各种功能的注解都比较全面,使用简单,而struts2需要采用XML很多的配置参数来管理(虽然也可以采用注解,但是几乎没有公司那 样使用)。

4.参数传递:Struts2中自身提供多种参数接受,其实都是通过(ValueStack)进行传递和赋值,而SpringMvc是通过方法的参数进行接收。

5.学习难度:Struts更加很多新的技术点,比如拦截器、值栈及OGNL表达式,学习成本较高,springmvc 比较简单,很较少的时间都能上手。

6.intercepter 的实现机制:struts有以自己的interceptor机制,spring mvc用的是独立的AOP方式。这样导致struts的配置文件量还是比spring mvc大,虽然struts的配置能继承,所以我觉得论使用上来讲,spring mvc使用更加简洁,开发效率Spring MVC确实比struts2高。spring mvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上spring3 mvc就容易实现restful url。struts2是类级别的拦截,一个类对应一个request上下文;实现restful url要费劲,因为struts2 action的一个方法可以对应一个url;而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。spring3 mvc的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架方法之间不共享变量,而struts2搞的就比较乱,虽然方法之间 也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码,读程序时带来麻烦。

7.spring mvc处理ajax请求,直接通过返回数据,方法中使用注解@ResponseBody,spring mvc自动帮我们对象转换为JSON数据。而struts2是通过插件的方式进行处理

在SpringMVC流行起来之前,Struts2在MVC框架中占核心地位,随着SpringMVC的出现,SpringMVC慢慢的取代struts2,但是很多企业都是原来搭建的框架,使用Struts2较多。

说一下Spring中的两大核心?
Spring是什么?

spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架(相对于重量级的EJB),主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。

1、IOC(Inversion of Control )或DI(Dependency Injection)

​ IOC控制权反转

​ 原来:我的Service需要调用DAO,Service就需要创建DAO

​ Spring:Spring发现你Service依赖于dao,就给你注入.

​ 核心原理:就是配置文件+反射(工厂也可以)+容器(map)

2、AOP:面向切面编程

​ 核心原理:使用动态代理的设计模式在执行方法前后或出现异常做加入相关逻辑。

​ 我们主要使用AOP来做:

​ 1、事务处理

​ 2、权限判断

​ 3、日志

AOP是什么?你都拿它做什么?

1、AOP:面向切面编程

​ 核心原理:使用动态代理的设计模式在执行方法前后或出现异常做加入相关逻辑。

​ 我们主要使用AOP来做:

​ 1、事务处理 执行方法前,开启事务、执行完成后关闭事务、出现异常后回滚事务

​ 2、权限判断 在执行方法前,判断是否具有权限

​ 3、日志 在执行前进行日志处理

讲一下Spring的事务传播特性
PROPAGATION_REQUIRED:

如果存在一个事务,则支持当前事务。如果没有事务则开启

PROPAGATION_SUPPORTS:

如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行

PROPAGATION_MANDATORY:

如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

PROPAGATION_REQUIRES_NEW:

总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

PROPAGATION_NOT_SUPPORTED:

总是非事务地执行,并挂起任何存在的事务。

PROPAGATION_NEVER:

总是非事务地执行,如果存在一个活动事务,则抛出异常

PROPAGATION_NESTED:

如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

Propagation

Required 需要 如果存在一个事务,则支持当前事务。如果没有事务则开启

Supports 支持 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行

Mandatory 必要的 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

required_new 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

Not_support 总是非事务地执行,并挂起任何存在的事务。

Never 绝不 总是非事务地执行,如果存在一个活动事务,则抛出异常

Nested 嵌套的 如果有就嵌套、没有就开启事务

Spring事务的隔离级别

ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.

另外四个与JDBC的隔离级别相对应
ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。

除了防止脏读,不可重复读外,还避免了幻像读。

脏读:

指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据, 那么另外一 个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

不可重复读:

指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。 那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

幻觉读:

指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及 到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

什么是ORM?

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。那么,到底如何实现持久化呢?一种简单的方案是采用硬编码方式(jdbc操作sql方式),为每一种可能的数据库访问操作提供单独的方法。

这种方案存在以下不足:

1.持久化层缺乏弹性。一旦出现业务需求的变更,就必须修改持久化层的接口

2.持久化层同时与域模型与关系数据库模型绑定,不管域模型还是关系数据库模型发生变化,都要修改持久化曾的相关程序代码,增加了软件的维护难度。

ORM提供了实现持久化层的另一种模式,它采用映射元数据来描述对象关系的映射,使得ORM中间件能在任何一个应用的业务逻辑层和数据库层之间充当桥梁。Java典型的ORM框架有:Hibernate,ibatis(mybatis),speedframework。

ORM的方法论基于三个核心原则:

简单:以最基本的形式建模数据。

传达性:数据库结构被任何人都能理解的语言文档化。

精确性:基于数据模型创建正确标准化了的结构。

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象关系数据库存在的互不匹配的现象的技术。可以简单的方案是采用硬编码方式(jdbc操作sql方式),为每一种可能的数据库访问操作提供单独的方法。这种方法存在很多缺陷,使用使用ORM框架(为了解决解决面向对象关系数据库存在的互不匹配的现象的框架)来解决. Hibernate,ibatis(mybatis),

iBatis(mybatis)与Hibernate有什么不同?
相同点:

都是java中orm框架、屏蔽jdbc api的底层访问细节,使用我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。jdbc api编程流程固定,还将sql语句与java代码混杂在了一起,经常需要拼凑sql语句,细节很繁琐。

ibatis的好处:屏蔽jdbc api的底层访问细节;将sql语句与java代码进行分离;提供了将结果集自动封装称为实体对象和对象的集合的功能.queryForList返回对象集合,用queryForObject返回单个对象;提供了自动将实体对象的属性传递给sql语句的参数。

Hibername的好处:Hibernate是一个全自动的orm映射工具,它可以自动生成sql语句,并执行并返回java结果。

不同点:

1、hibernate要比ibatis功能强大很多。因为hibernate自动生成sql语句。

2、ibatis需要我们自己在xml配置文件中写sql语句,hibernate我们无法直接控制该语句,我们就无法去写特定的高效率的sql。对于一些不太复杂的sql查询,hibernate可以很好帮我们完成,但是,对于特别复杂的查询,hibernate就很难适应了,这时候用ibatis就是不错的选择,因为ibatis还是由我们自己写sql语句。

ibatis可以出来复杂语句,而hibernate不能。

3、ibatis要比hibernate简单的多。ibatis是面向sql的,不同考虑对象间一些复杂的映射关系。

Hibernate映射对象的状态

临时状态/瞬时状态(transient):刚刚用new语句创建,没有被持久化

不处于session中(没有使用session的方法去操作临时对象)。该对象成为临时对象

持久化状态/托管状态(persistent):已经被持久化,加入到session的缓存中。session是没有关闭该状态的对象为持久化对象。

游离状态/脱管状态(detached):已经被持久化,但不处于session中。

该状态的对象为游离对象。

删除状态(removed):对象有关联的ID,并且在Session管理下,但是已经被计划(事务提交的时候,commit())删除。如果没有事务就不能删除

相互转换

介绍一下Hibernate的缓存?

一、why(为什么要用Hibernate缓存?)

Hibernate是一个持久层框架,经常访问物理数据库。

为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。

缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。

为了提供访问速度,把磁盘或数据库访问变成内存访问。

二、what(Hibernate缓存原理是怎样的?)Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存。

1.Hibernate一级缓存又称为“Session的缓存”。

Session缓存内置不能被卸载,Session的缓存是事务范围的缓存(Session对象的生命周期通常对应一个数据库事务或者一个应用事务)。

一级缓存中,持久化类的每个实例都具有唯一的OID。

2.Hibernate二级缓存又称为“SessionFactory的缓存”。

由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。

第二级缓存是可选的,是一个可配置的插件,默认下SessionFactory不会启用这个插件。

Hibernate提供了org.hibernate.cache.CacheProvider接口,它充当缓存插件与Hibernate之间的适配器。

面试:

Hibernate中的缓存分一级缓存和二级缓存。

一级缓存就是Session级别的缓存,在事务范围内有效是,内置的不能被卸载。二级缓存是SesionFactory级别的缓存,从应用启动到应用结束有效。是可选的,默认没有二级缓存,需要手动开启。

​ 保存数据库后,在内存中保存一份,如果更新了数据库就要同步更新。

什么样的数据适合存放到第二级缓存中?

  1. 很少被修改的数据  帖子的最后回复时间

  2. 经常被查询的数据 电商的地点

  3. 不是很重要的数据,允许出现偶尔并发的数据

  4. 不会被并发访问的数据

  5. 常量数据

扩展:hibernate的二级缓存默认是不支持分布式缓存的。使用memcahe,redis等中央缓存来代替二级缓存。

简单讲一下webservice使用的场景?

webservice是一个SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言间的相互调用,通过Internet进行基于Http协议的网络应用间的交互。

1、异构系统(不同语言)的整合

2、不同客户端的整合 浏览器、手机端(android,ios.塞班)、微信单、PC端等终端来访问

1、实实在在的列子:

​ 天气预报:可以通过实现webservice客户端调用远程天气服务实现的。 单点登录:一个服务是所有系统的登录

微服务部分

为什么要用 Spring Boot?

· 独立运行

· 简化配置

· 自动配置

· 无代码生成和XML配置

· 应用监控

· 上手容易

Spring Boot 的核心配置文件有哪几个?它们的区别是什么?

Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。

application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。

bootstrap 配置文件有以下几个应用场景。

· 使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;

Spring Cloud 构建于 Spring Boot 之上,在 Spring Boot 中有两种上下文,一种是 bootstrap, 另外一种是 application, bootstrap 是应用程序的父上下文,也就是说 bootstrap 加载优先于 applicaton。bootstrap 主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。这两个上下文共用一个环境,它是任何Spring应用程序的外部属性的来源。bootstrap 里面的属性会优先加载,它们默认也不能被本地相同配置覆盖。

· 一些固定的不能被覆盖的属性;

· 一些加密/解密的场景;

Spring Boot 的配置文件有哪几种格式?它们有什么区别?

.properties 和 .yml,它们的区别主要是书写格式不同。

1).properties

app.user.name = javastack

2).yml

app:

user:

​ name: javastack

另外,.yml 格式不支持 @PropertySource 注解导入配置。

Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。

@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。

@ComponentScan:Spring组件扫描。

开启 Spring Boot 特性有哪几种方式?

继承spring-boot-starter-parent项目

导入spring-boot-dependencies项目依赖

Spring Boot 需要独立的容器运行吗

可以不需要,内置了 Tomcat/ Jetty 等容器。

运行 Spring Boot 有哪几种方式?

1)打包用命令或者放到容器中运行

2)用 Maven/ Gradle 插件运行

3)直接执行 main 方法运行

Spring Boot 自动配置原理是什么?

注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

Spring Boot 的目录结构是怎样的

这个目录结构是主流及推荐的做法,而在主入口类上加上 @SpringBootApplication 注解来开启 Spring Boot 的各项能力,如自动配 置、组件扫描等

你如何理解 Spring Boot 中的 Starters?

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。

Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。

1:Spring Boot官方的启动器都是以spring-boot-starter-命名的像mybatis的mybatis-spring-boot-starter。第三方的启动器不能以spring-boot开头命名

2:starters分类(了解)

(1) Spring Boot应用类启动器

spring-boot-starter(包含自动配置、日志、YAML的支持。)

spring-boot-starter-web(使用Spring MVC构建web 工程,包含restful,默认使用Tomcat容器。)

(2) Spring Boot生产启动器

spring-boot-starter-actuator(提供生产环境特性,能监控管理应用。)

(3) Spring Boot技术类启动器

spring-boot-starter-json(提供对JSON的读写支持)

spring-boot-starter-logging(默认的日志启动器,默认使用Logback。)

如何在 Spring Boot 启动的时候运行一些特定的代

果你想在Spring Boot启动的时候运行一些特定的代码,你可以实现接口 ApplicationRunner或者 CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个run方法。测试一下启动方法

Spring Boot 有哪几种读取配置的方式?

Spring Boot 可以通过 @PropertySource,@Value,@Environment, @ConfigurationProperties 来绑定变量

Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个

Spring Boot 支持 Java Util Logging, Log4j2, Lockback 作为日志框架,如果你使用 Starters 启动器,Spring Boot 将使用 Logback 作为默认日志框架,

SpringBoot 实现热部署有哪几种方式?

· Spring Loaded

· Spring-boot-devtools

你如何理解 Spring Boot 配置加载顺序?

在 Spring Boot 里面,可以使用以下几种方式来加载配置。

1)properties文件;

2)YAML文件;

3)系统环境变量;

4)命令行参数

Spring Boot 可以兼容老 Spring 项目吗,如何做?

可以兼容,使用 @ImportResource 注解导入老 Spring 项目配置文件。

Spring Boot 2.X 有什么新特性?与 1.X 有什么区别?

· 配置变更

· JDK 版本升级

· 第三方类库升级

· 响应式 Spring 编程支持

· HTTP/2 支持

· 配置属性绑定

· 更多改进与加强…

springcloud

Spring Cloud的服务注册和发现如何实现?

Eureka server提供服务注册和发现

​ Eureka Server提供服务注册服务。各个服务提供者节点启动后,会在Eureka Server中进行注册,这样Eureka server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到

Service Provider服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到。

Service Consumer服务消费方从Eureka获取注册服务列表,从而能够消费服务

项目部署

linux
docker

其他部分

有没有用过linux?你都用它来做什么?

常用:

Pwd 获取当前路径

Cd 跳转到目录

Su -u 切换到管理员

Ls ls 列举目录

文件操作命令:

文件

tail 查看

rm -rf

vi

文件夹

mkdir

rm -r

你是使用什么来连接远程的Linux服务器的?

使用xshell、putty等ssh客户端来连接服务器,使用xftp、winscp等sftp客户端来上传和现在文件。连接和上传、下载必须依赖于服务器的ssh、sftp服务,也就是linux服务器需要启动这两个服务。

有没有使用过云主机?

使用过,在原来的公司,我们没有使用自己的服务器,而是租用阿里的云主机。

没有使用过,但是有所了解。

云主机就是一些云服务运营商(阿里、华为、西部数码、新浪等),提供的远程的服务器功能,我们开发者或者企业只需按需付费就可以租用对应的服务器。

使用ssh和sftp来进行操作。

有没有做过数据库优化方面的事情?

做过mysql数据库的优化、其他数据库类似

定位:查找、定位慢查询

优化手段:

a) 创建索引:创建合适的索引,我们就可以现在索引中查询,查询到以后直接找对应的记录。

b) 分表 :当一张表的数据比较多或者一张表的某些字段的值比较多并且很少使用时,采用水平分表和垂直分表来优化

c) 读写分离:当一台服务器不能满足需求时,采用读写分离的方式进行集群。

d) 缓存:使用redis来进行缓存

e) 一些常用优化技巧

查找慢查询并定位慢查询?

在项目自验项目转测试之前,在启动mysql数据库时开启慢查询,并且把执行慢的语句写到日志中,在运行一定时间后。通过查看日志找到慢查询语句。

1、关闭数据库服务器(关闭服务)

2、把慢查询记录到日志中

3、设置慢查询时间

4、找出日志中的慢查询SQL 使用explain 慢查询语句,来详细分析语句的问题.

数据库优化之遵循范式?

数据库表设计时需要遵循方式

表的范式,是首先符合1NF, 才能满足2NF , 进一步满足3NF

1NF: 即表的列的具有原子性,不可再分解,即列的信息,不能分解.只要数据库是关系型数据库(mysql/oracle/db2/sysbase/sql server),就自动的满足1NF.关系型数据库中是不允许分割列的。

2NF:表中的记录是唯一的.通常我们设计一个主键来实现

3NF:即表中不要有冗余数据, 就是说,表的信息,如果能够被推导出来,就不应该单独的设计一个字段来存放.(外键)

反3NF :没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是: 在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余**。** 订单和订单项、相册浏览次数和照片的浏览次数

选择合适的存储引擎

在开发中,我们经常使用的存储引擎 myisam / innodb/ memory

MyISAM存储引擎

如果表对事务要求不高,同时是以查询和添加为主的,我们考虑使用myisam存储引擎. 比如 bbs 中的 发帖表,回复表.

INNODB存储引擎:

对事务要求高,保存的数据都是重要数据,我们建议使用INNODB,比如订单表,账号表.

Memory 存储

​ 我们数据变化频繁,不需要入库,同时又频繁的查询和修改,我们考虑使用memory, 速度极快.

问 MyISAM 和 INNODB的区别(主要)

  1. 事务安全 myisam不支持事务而innodb支持

  2. 查询和添加速度 myisam不用支持事务就不用考虑同步锁,查找和添加和添加的速度快

  3. 支持全文索引 myisam支持innodb不支持

  4. 锁机制 myisam支持表锁而innodb支持行锁(事务)

  5. 外键 MyISAM 不支持外键, INNODB支持外键. (通常不设置外键,通常是在程序中保证数据的一致)

数据库优化之创建合适的索引?

索引(Index)是帮助*DBMS高效获取数据的数据结构

分类:普通索引/唯一索引/主键索引/全文索引

普通索引:允许重复的值出现

唯一索引:除了不能有重复的记录外,其它和普通索引一样(用户名、用户身份证、email,tel)

主键索引:是随着设定主键而创建的,也就是把某个列设为主键的时候,数据库就会給改列创建索引。这就是主键索引.唯一且没有null值

全文索引:用来对表中的文本域(char,varchar,text)进行索引, 全文索引针对MyIsam

explain select * from articles where match(title,body) against(‘database’);【会使用全文索引】

索引使用小技巧?

索引弊端

1.占用磁盘空间。

2.对dml(插入、修改、删除)操作有影响,变慢。

使用场景:

a: 肯定在where条件经常使用,如果不做查询就没有意义

b: 该字段的内容不是唯一的几个值(sex)

c: 字段内容不是频繁变化.

具体技巧:
  1. 对于创建的多列索引(复合索引),不是使用的第一部分就不会使用索引。

alter table dept add index my_ind (dname,loc); // dname 左边的列,loc就是右边的列

explain select * from dept where dname=‘aaa’\G 会使用到索引

explain select * from dept where loc=‘aaa’\G 就不会使用到索引

  1. 对于使用like的查询,查询如果是’%aaa’不会使用到索引而‘aaa%’会使用到索引。

explain select * from dept where dname like ‘%aaa’\G不能使用索引

explain select * from dept where dname like ‘aaa%’\G使用索引.

所以在like查询时,‘关键字’的最前面不能使用 % 或者 _这样的字符.,如果一定要前面有变化的值,则考虑使用 全文索引->sphinx.

3、如果条件中有or,有条件没有使用索引,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须单独使用时能使用索引.

4、 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。

expain select * from dept where dname=’111’;

expain select * from dept where dname=111;(数值自动转字符串)

expain select * from dept where dname=qqq;报错

也就是,如果列是字符串类型,无论是不是字符串数字就一定要用 ‘’ 把它包括起来.

5、如果mysql估计使用全表扫描要比使用索引快,则不使用索引。 表里面只有一条记录

数据库优化之分表?

分表分为水平(按行)分表和垂直(按列)分表

根据经验,Mysql表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉;水平分表能够很大程度较少这些压力。

按行数据进行分表。

如果一张表中某个字段值非常多(长文本、二进制等),而且只有在很少的情况下会查询。这时候就可以把字段多个单独放到一个表,通过外键关联起来。

​ 考试详情,一般我们只关注分数,不关注详情。

水平分表策略:

1.按时间分表

这种分表方式有一定的局限性,当数据有较强的实效性,如微博发送记录、微信消息记录等,这种数据很少有用户会查询几个月前的数据,如就可以按月分表。

2.按区间范围分表

一般在有严格的自增id需求上,如按照user_id水平分表:

table_1 user_id从1~100w

table_2 user_id从101~200w

table_3 user_id从201~300w

3.hash分表

通过一个原始目标的ID或者名称通过一定的hash算法计算出数据存储表的表名,然后访问相应的表。

数据库优化之读写分离

一台数据库支持的最大并发连接数是有限的,如果用户并发访问太多。一台服务器满足不要要求是就可以集群处理。Mysql的集群处理技术最常用的就是读写分离。

主从同步

数据库最终会把数据持久化到磁盘,如果集群必须确保每个数据库服务器的数据是一直的。能改变数据库数据的操作都往主数据库去写而其他的数据库从主数据库上同步数据。

读写分离

使用负载均衡来实现写的操作都往主数据去,而读的操作往从服务器去。

数据库优化之缓存

在持久层(dao)和数据库(db)之间添加一个缓存层,如果用户访问的数据已经缓存起来时,在用户访问时直接从缓存中获取,不用访问数据库。而缓存是在操作内存级,访问速度快。

作用:减少数据库服务器压力,减少访问时间。

Java中常用的缓存有,

1、hibernate的二级缓存。该缓存不能完成分布式缓存

2、可以使用redis(memcahe等)来作为中央缓存。

​ 对缓存的数据进行集中处理

语句优化小技巧

DDL优化:

DDL优化:

1 、通过禁用索引来提供导入数据性能 。 这个操作主要针对有数据库的表,追加数据

//去除键

alter table test3 DISABLE keys;

//批量插入数据

insert into test3 select * from test;

//恢复键

alter table test3 ENABLE keys;

2、 关闭唯一校验

set unique_checks=0 关闭

set unique_checks=1 开启

3、修改事务提交方式(导入)(变多次提交为一次)

set autocommit=0 关闭

//批量插入

set autocommit=1 开启

DML优化(变多次提交为一次)

insert into test values(1,2);

insert into test values(1,3);

insert into test values(1,4);

//合并多条为一条

insert into test values(1,2),(1,3),(1,4)

DQL优化

Order by优化

  1、多用索引排序

2、普通结果排序(非索引排序)Filesort

group by优化

​ 是使用order by null,取消默认排序

子查询优化

在客户列表找到不在支付列表的客户

#在客户列表找到不在“支付列表”的客户 , 查询没买过东西的客户

explain

select * from customer where customer_id not in (select DISTINCT customer_id from payment); #子查询 – 这种是基于func外链

explain

select * from customer c left join payment p on(c.customer_id=p.customer_id) where p.customer_id is null – 这种是基于“索引”外链

Or优化

在两个独立索引上使用or的性能优于

1、 or两边都是用索引字段做判断,性能好!!

2、 or两边,有一边不用,性能差

3、 如果employee表的name和email这两列是一个复合索引,但是如果是 :name=‘A’ OR email=‘B’ 这种方式,不会用到索引!

limit优化

select film_id,description from film order by title limit 50,5;

select a.film_id,a.description from film a inner join (select film_id from film order by title limit 50,5)b on a.film_id=b.film_id

jdbc批量插入几百万数据怎么实现?

变每次提交为特定次数提交

使用批量操作

省出的时间可观。

像这样的批量插入操作能不使用代码操作就不使用,可以使用存储过程来实现。

有没有使用过redis? Redis是什么

Redis是一个key-value的nosql数据库.先存到内存中,会根据一定的策略持久化到磁盘,即使断电也不会丢失数据。支持的数据类型比较多。

主要用来做缓存数据库的数据和web集群时当做中央缓存存放seesion

Redis和memche的比较?

1、 Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。

2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。

3、虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘

简单说一下redis的使用场景?

缓存:

把经常需要查询的、很少修改数据,放到读速度很快的空间(内存),以便下次访问减少时间。减轻压力,减少访问时间.

计数器:

redis中的计数器是原子性的内存操作。

可以解决库存溢出问题.进销存系统库存溢出。

session缓存服务器:

web集群时作为session缓存服务器

缓存队列等

redis对象保存方式?

Json字符串:

需要把对象转换为json字符串,当做字符串处理。直接使用set get来设置或者或。

优点:设置和获取比较简单

缺点:没有提供专门的方法,需要把把对象转换为json。(jsonlib)

字节:

需要做序列号,就是把对象序列化为字节保存。

如果是担心JSON转对象会消耗资源的情况,这个问题需要考量几个地方,

第一点:就是使用的JSON转换lib是否就会存在性能问题。

第二点:就是数据的数据量级别,如果是存储百万级的大数据对象,建议采用存储序列化对象方式。如果是少量的数据级对象,或者是数据对象字段不多,还是建议采用JSON转换成String方式。

毕竟redis对存储字符类型这部分优化的非常好。具体采用的方式与方法,还要看你所使用的场景。

Redis数据淘汰机制

在 redis 中,允许用户设置最大使用内存大小 server.maxmemory,在内存限定的情况下是很有用的。譬如,在一台 8G 机子上部署了 4 个 redis 服务点,每一个服务点分配 1.5G 的内存大小,减少内存紧张的情况,由此获取更为稳健的服务。

内存大小有限,需要保存有效的数据?

redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

redis 提供 6种数据淘汰策略:

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

no-enviction(驱逐):禁止驱逐数据

Java访问Redis

1、使用jedis java客户端来访问redis服务器,有点类似通过jdbc访问mysql一样。

2、当然如果是spring进行集成时,可以使用spring data来访问redis,spring data只是对jedis的二次封装。jdbcTemplate jdbc关系一样

Redis集群

当一台数据无法满足要求,可以使用reids集群来处理,类似于mysql的读写分离。

简单介绍一下微信公共号的分类?

公众号:个人和企业都能申请

服务号:企业才能申请

企业号:企业才能申请

微信开发原理

微信公众平台开发者,通过接入认证的方式,让我们的服务器能处理来自微信服务器转发的微信用户的请求,处理完成后返回给微信服务器,有微信服务器对用户响应。

怎么把微信和业务平台绑定?

让微信用户也能完成注册用户的功能。

用户注册实体中包含一个微信号的字段,当我进行绑定时就是修改用户的微信号字段。

当然我们在进行菜单跳转到页面后,我们是无法直接获取微信号的。要通过微信网页授权来获取微信号

代码:

第一步:用户同意授权,获取code

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。

第二步:通过code换取网页授权****openId也就是我们微信号

获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

{ “access_token”:“ACCESS_TOKEN”,

"expires_in":7200,

"refresh_token":“REFRESH_TOKEN”,

“openid”:“OPENID”,

"scope":“SCOPE” }

项目和业务部分

项目分类

在公司中做的项目可以分为两种产品、项目.

项目:就是给一些公司接的项目,项目开发完成后。就交互,后面这个项目代码就不在维护了

产品:充分考虑扩展性和基本业务,来做一个产品。在这个产品上可以进行定制开发。

项目参与者

产品经理?PM?架构师(SE)?(开发PL? MDE?可能会有多个) (测试PL ? TSE可能会有多个) UI 资料

开发团队:开始代码能完成需求

测试团队:测试功能

UI:负责界面设计、静态代码的编写

资料:负责界面的文字描述。

QA :通过项目质量监控,和PM,SE同级

开发和UI和资料,协同设计和开发,开发完成后转测试(测试策略)交给测试团队进行测试,测试完成后会出一个测试报告。

项目流程

可行性分析和立项和开工会

需求分析

需求设计

项目开发(多个迭代)

​ 迭代开工会

​ 迭代设计

  	迭代开发

  	迭代测试

  	集成测试

  	迭代发布

​ 迭代总结

​ …不断迭代

项目验收

项目总结

业务注意事项

1、不要多个项目都说你同一个模块。如果要说,就说后面是进行改进。

在pss,crm,shopping都写权限模块

2、多写点业务

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值