java面向对象有哪些特征?
-
封装
封装隐藏了类的内部实现机制,封装的代码可重复使用,增加了代码的复用性
-
继承
子类拥有父类的属性和方法,增加了代码的复用性
-
多态
增加了代码的可移植性,健壮性,灵活性,消除类型之间的耦合关系
ArrayList和LinkedList区别?
ArrayList和LinkedList都实现了List接口
-
ArrayLit
ArrayList底层是数组,查询快,线程不安全
-
LinkedList
LinkedList底层是双向链表,添加和删除快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引,线程不安全
java中接口和抽象类有哪些区别?
- 相同
- 不能够实例化
- 可以将抽象类和接口类型作为引用类型
- 接口的实现类和抽象类的子类只有全部实现了接口或抽象类中的方法才可以被实例化
- 不同点
- 抽象类可以有构造方法,接口中不能有构造方法
- 抽象类中可以有普通成员变量,接口中没有普通成员变量
- 抽象类中可以包含静态方法,接口中不能包含静态方法
- 一个类可以实现多个接口,但只能继承一个抽象类
- 接口可以被多重实现,抽象类只能被单一继承
ACID四大特性?
-
原子性:一个事物中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复到事务开始前的状态,就像这个事务从来没有执行过一样
-
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度,串联性以及后续数据库可以自发性地完成预定的工作
-
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交,读提交,可重复读和串行化
-
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
ACID是靠什么保证的?
- 原子性由undolog日志来保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
- 一致性是由其他三大特性保证,程序代码要保证业务上的一致性
- 隔离性是由MVCC来保证
- 持久性由redolog来保证,mysql修改数据的时候会在redolog中记录一份日志数据,就算数据没有保存成功,只要日志保存成功了,数据仍不会丢失
HashMap和HashTable的区别是什么?
- HashMap线程不安全,HashTable线程安全
- HashMap允许空值,空key,HashTable不允许空值,空key
- HashMap中hash数组的默认大小是16,增长方式是2的指数倍,HashTable中hash数组的默认大小是old*2+1
- HashMap继承自AbstractMap类,HashTable继承Dictionary(地歪特)类
Mybatis的优缺点有哪些?
- 优点
- 简单易学,容易上手(相比如hibernate)基于sql编程
- 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
- 很好的与各种数据库兼容,开发人员不需要考虑数据库的差异性
- 提供了很多第三方插件(分页插件/逆向工程)
- 能够与Spring很好的集成
- MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,接触sql与程序代码的耦合,便于统一管理和优化,并可重用
- 提供XML标签,支持编写动态SQL语句
- 提供映射标签,支持对象与数据库的ORM字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 缺点
- SQL语句编写工作量大,对开发人员编写SQL语句有一定要求
- SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库
Mybatis中#{}和${}的区别是什么?
- #{}是预编译处理,${}是字符串替换
- Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值
- Mybatis在处理${}时,就是把#{}替换成变量的值
- 使用#{}可以有效的防止SQL注入,提高系统安全性
Mysql的隔离级别有哪些?
- READ UNCOMMITTED 读取未提交内容
- 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读
- READ COMMITTED 读取提交内容
- 这是大多数数据库系统的默认隔离级别(但不是Mysql默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读,因为同一个事务的其他实例在该实例处理期间可能会有新的commit,所有同一select可能返回不同结果
- REPEATABLE READ 可重读
- 这是Mysql默认隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读。简单的说,幻读指当用户读取某一范围数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的 “幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC)机制解决了该问题
- Serializable 可串行化
- 这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争
Mysql索引的数据结构
Mysql主要用到两种结构:B+Tree索引和Hash索引
- InnoDb存储引擎 默认是 B+Tree索引
- Memory(面么瑞)储存引擎 默认是 Hash索引
对比:
- hash类型索引:查询单条快,范围查询慢
- btree类型索引:b+树,层数越多,数据量指数级增长,范围查询快,更适合排序等操作
SQL优化
1、查询语句中不要使用select *
2、尽量减少子查询,使用关联查询(left join,right join,inner join)代替
3、减少使用 in 或者 not in,使用 exists,not exists 或者关联查询语代替
4、or的查询尽量用 union 或者 union all 代替(在确认没有重复数据或者不用剔除重复数据时,union all 会更好)
5、应尽量避免在where子句中使用 != 或 <>操作符,否则该引擎放弃使用索引而进行全表扫描
6、应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num is null 可以在num上设置默认值 0,确保表中num列没有null值,然后这样查询:select id from t where num =0
Mysql执行计划怎么看?
在企业的应用场景中,为了知道优化SQL语句的执行,需要查看SQL语句的具体执行过程,以加快SQL语句的执行效率。
可以使用explain + SQL语句来模拟优化器执行SQL查询语句,从而知道mysql是如何处理sql语句的
-
执行计划中包含的信息
-
id
select查询是序列号,包含一组数字,表示查询中执行select子句或者操作表的顺序
id号分为三种情况:
1.如果id相同,那么执行顺序从上到下
2.如果id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
3.id相同和不同的,同时存在:相同的可以认为是一组,从上往下顺序执行,在所有组中,id值越大,优先级越高,越先执行
-
table
显示的查询表名,如果查询使用了别名,那么这里显示的是别名,如果不涉及对数据表的操作,那么这里显示为null,如果显示为尖括号括起来的就表示这个是临时表,后边的N就是执行计划中的id,表示结构来自于这个查询产生。如果是尖括号括起来的<union M,N>,与类似,也是一个临时表,表示这个结果来自与union查询的id为M,N的结果集
-
type
type显示的是访问类型,访问类型表示我是以何种方式去访问我们的数据,最容易想的是全表扫描,直接暴力的遍历一张表去寻找需要的数据,效率非常低下,访问的类型有很多,效率从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般情况下,得保证查询至少达到range级别,最好能达到ref
--all:全表扫描,一般情况下出现这样的sql语句而且数据量比较大的话那么就需要进行优化 explain select * from emp --index:全索引扫描这个比all的效率更好,主要有两种情况,一种是当前的查询时覆盖索引,即我们需要的数据在索引中就可以索取,或者是使用了索引进行排序,这样就避免数据的重排序 explain select empno from emp --range:表示利用索引查询的时候限制了范围,在指定范围内进行查询,这样避免了index的全索引扫描,适用的操作符:=,<>,>,>=,<,<=,is null,between,like,or,in() explain select * from emp where empno between 500 and 600 --index_subquery:利用索引来关联子查询,不再扫描全表 explain select * from emp where emp.job in (select job from t_job) --unique_subquery:该连接类型类似与index_subquery,使用的是唯一索引 explain select * from emp e where e.deptno in (select distinct deptno from dept) --index_merge:在查询过程中需要多个索引组合使用,没有模拟出来 explain select * from rental where rental_date like '2020-08-24 08:12:50' and inventoryid = 1 and customerid = 9 --ref_or_null:对于某个字段即需要关联条件,也需要null值的情况下,查询优化器会选择这种访问方式 explain select * from emp e where e.mgr is null or e.mgr = 9 --ref:使用了非唯一性索引进行数据的查找 create index idx_3 on emp(deptno); explain select * from emp e,dept d where e.deptno = d.deptno --eq_ref:使用唯一性索引进行数据查找 explain select * from emp,emp2 where emp.empno = emp2.empno --const:这个表至少有一个匹配行 explain select * from emp where empno = 3 --system:表只有一行记录(等于系统表),这个const类型的特例,平时不会出现
-
key
查询真正使用到的索引,select_type为index_merge时,这里可能出现两个以上的索引,其他的select_type 这里只会出现一个
-
rows
这里是执行计划中估算的扫描行数,不是精确值
-
extra
查询关键信息
-
Spring,SpringMVC,SpringBoot的区别是什么?
- spring和springMvc
- spring是一个一站式的轻量级的java开发框架,核心是控制反转(IOC)和面向切面(AOP),针对于开发的WEB层(springMvc),业务层(Ioc),持久层(jdbcTemplate)等都提供了多种配置解决方案
- springMvc是spring基础之上的一个MVC框架,主要处理web开发的路径映射和视图渲染,属于spring框架中WEB层开发的一部分
- springMvc和springBoot
- spirngMvc属于一个企业WEB开发的MVC框架,涵盖面包括前端视图开发,文件配置,后台接口逻辑开发等,XML,config等配置相对比较繁琐复杂
- springBoot框架相对于springMvc框架来说,更专注于开发微服务后台接口,不开发前端视图,同时遵循默认优于配置,简化了插件配置流程,不需要配置XML,相对springMvc,大大简化了配置流程
SpringBoot自动装配原理
SpringMVC的执行流程?
SpringMVC执行流程原理
1、用户发送请求到前端控制器DispatcherServlet。
2、DispatcherServlet接收到请求后调用HandlerMapping处理器映射器。
3、处理器映射器找到具体的处理器(可以根据xml配置,注解进行查找),生成处理器对象一并返回给DispatcherServlet。
4、DispatcherServlet调用HandlerAdapter处理器适配器。
5、HandlerAdapter经过适配器调用具体的处理器(Controller,也叫后端控制器)。
6、Controller执行完成后返回ModelAndView给HandlerAdapter处理器适配器。
7、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、ViewReslover解析后返回具体View给DispatcherServlet前端控制器。
10、DispatcherServlet根据View进行视图渲染,将模型数据填充至视图中。
11、DispatcherServlet前端控制器将结果响应给用户。
SpringMvc的九大内置组件有哪些?
1、HandlerMapping
根据request找到相应的处理器。因为Handler(Controller)有两种形式,一种是基于类的Handler,另一种是基于Method的Handler
2、HandlerAdapter
调用Handler的适配器。如果把Handler(Controller)当作工具的话,那么HandlerAdapter就相当于干活的工人
3、HandlerExceptionResolver
对异常的处理
4、ViewResolver
用来将String类型的视图名和Locale解析为View类型的视图
5、RequestToViewNameTranslator (全斯雷特)
有的Handler(Controller)处理完后没有设置返回类型,比如是viod方法,这时就需要从request中获取viewName
6、LocaleResolver (洛kiao瑞扫f儿)
从request中解析出Locale。Locale表示一个区域,比如zh-cn,对不同的区域的用户,显示不同的结果,这就是i18n(SpringMVC中有具体的拦截器LocaleChangeInterceptor)
7、ThemeResolver (飞母瑞扫f儿)
主题解析,这种类似于我们手机更换主题,不同的UI,CSS等
8、MultipartResolver
处理上传请求,将普通的request封装成MultipartHttpServletReqeust
9、FlashMapManager
用户管理FlashMap,FlashMap用于在redirect重定向中传递参数
Spring的核心是什么?
- Spring是一个开源框架,是一种生态
- Spring是为了简化企业开发而生的,使得开发变得更加优雅而简洁
- Spring是一个 IOC 和 AOP 的容器框架
- IOC:控制反转,IOC是一种实现思想,DI是一种具体的实现方式(原来对象都是由我们来创建,现在都是交给容器创建的)
- DI:依赖注入
- AOP:面向切面编程
Spring框架中的单例Bean是线程安全的么?
Spring中的Bean对象默认是单例的,框架并没有对bean进行多线程的封装处理
如果Bean是有状态的,那么就需要开发人员自己来保证线程安全的保证,最简单的办法就是改变bean的作用域把singleton改成prototype,这样每次请求bean对象就相当于是创建新的对象来保证线程的安全
有状态就是由数据存储的功能
无状态就是不会存储数据,你想一下,我们的controller,service和dao本身并不是线程安全的,只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制遍历,这是自己线程的工作内存,是最安全的
因此在进行使用的时候,不要再bean中声明任何有状态的实例变量或者类变量,如果必须如此,也推荐大家使用ThreadLocal把变量编程线程私有,如果bean的实例变量或者类变量需要多个线程之间共享,那么就只能使用synchronized,lock,cas等这些实现线程同步的方法了
Spring框架中使用了哪些设计模式及应用场景
1、工厂模式,在各种BeanFactory以及ApplicationContext创建中都用到了
2、模板模式,在各种BeanFactory以及ApplicationContext实现中也都用到了
3、代理模式,Spring AOP 利用了 AspectJ AOP实现的!AspectJ AOP的底层用到了动态代理
4、策略模式,加载资源文件的方式,使用了不同的方法,比如:ClassPathResource,FileSystemResource,ServletContextResource,UrlResource但他们都有共同的接口Resource;在AOP的实现中采用了两种不同的方式,JDK动态代理和CGLIB代理
5、单例模式,比如在创建bean的时候
6、观察者模式,spring中的ApplicationEvent,ApplicationListener,ApplicationEventPublisher
7、适配器模式,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter,AfterReturningAdapter
8、装饰者模式,源码中类型带Wrapper或者Decorator的都是
Spring事务的隔离级别有哪些?
spring的事务隔离级别就是数据库的隔离级别,有以下几种:
read uncommitted 读取未提交
read committed 读取已提交
repeatable read 可重读
serializable 可串行化
在进行配置的时候,如果数据库和spring代码中的隔离级别不同,那么以spirng的配置为主
Spring支持的bean作用域有哪些?
1、singleton
使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回都是同一个Bean实例
2、prototype
使用该属性定义Bean时,IOC容器可以创建多个Bean的实例,每次返回都是一个新的实例
3、request
该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境
4、session
该属性仅用于Http Session,同一个Session共享一个Bean实例,不同Session使用不同的实例
5、global-session
该属性仅用于Http Session,同session作用域不同的是,所有的session共享一个Bean实例
SpringBoot的核心注解是哪个?它主要由哪几个注解组成的?
启动类上面的注解是@SpringBootApplication,它也是SpringBoot的核心注解,主要组合包含了以下3个注解:
1、@SpringBootConfiguration:组合了@Configuration注解,实现配置文件的功能。
2、@EnableAutoConfiguration:打开自动配置的功能,可可以关闭某个自动配置的选项,如关闭数据源自动配置功能:@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
3、@ComponentScan:spring组件扫描
如何理解SpringBoot配置加载顺序?
在SpringBoot里面,可以使用以下几种方式来加载配置。
1、properties文件;
2、YAML文件;
3、系统环境变量;
4、命令行参数;
等等…
Mysql中索引类型有哪些?以及对数据库性能的影响?
1、普通索引:允许被索引的数据列包含重复的值
2、唯一索引:可以保证数据记录的唯一性
3、主键索引:是一个特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字primary key来创建
4、组合索引:索引可以覆盖多个数据列
5、全文索引:通过建立倒排索引,可以极大的提升检索效率,解决判断字段是否包含的问题,是目前搜索引擎使用的一种关键技术
索引可以极大的提高数据的查询速度
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能
但是会降低插入,删除,更新表的速度,因为在执行这些写操作的时候,还要操作索引文件
怎么处理MySQL的慢查询?
1、开启慢日志查询,准确定位到哪个sql语句出现了问题
2、分析sql语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写
3、分析语句的执行计划,然后获得其使用索引的情况,只会修改语句或者修改索引,使得语句可以尽可能的命中索引
4、如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表
什么是嵌入式服务器,为什么使用嵌入式服务器?
在springboot框架中,大家应该发现了有一个内嵌的tomcat,在之前的开发流程中,每次写好代码之后必须要将项目部署到一个额外的web服务器中,只有这样才可以运行,这个明显要麻烦很多,而使用springboot的时候,你会发现在启动项目的时候可以直接按照java应用程序的方式来启动项目,不需要额外的环境支持,也不需要tomcat服务器,这是因为在springboot框架中内置了tomcat.jar,来通过main方法启动容器,达到一件开发部署的方式,不需要额外的任何其他操作
什么是bean的自动装配,它有哪些方式?
bean的自动装配指的是bean的属性值在进行注入的时候通过某种特定的规则和方式去容器中查找,并设置到具体的对象属性中,主要有五种方式:
- no - 缺省情况下,自动配置是通过 “ref” 属性手动设定,在项目中最常用
- byName - 根据属性名称自动装配,如果一个bean的名称和其他bean的属性的名称是一样的,将会自动装配它
- byType - 按数据类型自动装配,如果bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它
- constructor - 在构造函数参数的byType方式
- autodetect - 如果找到默认的构造函数,使用 “自动装配用构造”;否则,使用 “按类型自动装配”
说说你对AOP的理解?
AOP全程叫做 Aspect Oriented Programming 面向切面编程。它是为解耦而生的。
任何一个系统都是由不同的组件组成的,每个组件负责一块特定的功能,当然会存在很多组件是跟业务无关的,例如日志,事务,权限等核心服务组件,这些核心服务组件经常融入到具体的业务逻辑中,如果我们为每一个具体业务逻辑操作都添加这样的代码,很明显代码冗余太多,因此我们需要将这些公共的代码逻辑抽象出来编程一个切面,然后注入到目标对象(具体业务)中去,AOP正是基于这样的一个思路实现的,通过动态代理的方式,将需要注入切面的对象进行代理,在进行调用的时候,将公共的逻辑直接添加进去,而不需要修改原有业务的逻辑代码,只需要在原来的业务逻辑基础之上做一些增强功能即可。
说说你对IOC的理解?
索引的设计原则有哪些?
在进行索引设计的时候,应该保证索引字段占用的空间越小越好,这只是一个大的方向,还有一些细节点需要注意下:
1、适合索引的列是出现在where子句中的列,或者连接子句中指定的列
2、基数较小的表,索引效果差,没必要创建索引
3、在选择索引列的适合,越短越好,可以指定某些列的一部分,没有必要用全部的字段的值
4、不要给表中的每一个字段都创建索引,并不是索引越多越好
5、定义有外键的数据列一定要创建索引
6、更新频繁的字段不要有索引
7、创建索引的列不要过多,可以创建组合索引,但是组合索引的列的个数不建议太多
8、大文本,大对象不要创建索引
Java中==和equals有哪些区别?
equals 和 == 最大的区别是一个是方法,一个是运算符
==:如果比较的对象是基本数据类型,则比较的是数值是否相等,如果比较的是引用数据类型,则比较的是对象的地址值是否相等
equals():用来比较方法两个对象的内容是否相等
注意:equals方法不能用于基本数据类型的变量,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址
Java中异常处理机制有哪些?
java的异常处理是通过5个关键词来实现的:try,catch,throw,throws和finally
在java应用中,异常的处理机制分为声明异常,抛出异常和捕获异常
throw和throws的区别:
1、位置不同:
throw:方法内部
throws:方法的声明处
2、内容不同
throw + 异常对象 (检查异常,运行时异常)
throws + 异常的类型 (可以多个类型,用,拼接)
3、作用不同:
throw:异常出现的源头,制造异常
throws:在方法的声明处,告诉方法的调用者,这个方法中可能会出现我声明的这些异常,然后调用者对这个异常进行处理。要么自己处理要么再继续向外抛出异常
String,StringBuffer,StringBuilder
-
String
String是不可改变的,底层用final修饰,每拼接字符,都会指向新的内存地址
-
StringBuffer
StringBuffer是线程安全的,底层是数组
-
StringBuilder是线程不安全的,底层是数组,效率要比StringBuffer高
什么是token,什么是jwt,如何基于token进行身份验证?
token需要查库验证token是否有效,而jwt不用查库或者少查库,直接在服务端进行校验,并且不用查库。因为用户的信息及加密信息在第二部分payload和第三部分签证中已经生产,只要在服务端进行校验就行,并且校验也是jwt自己实现的
-
token
概念:令牌,是访问资源的凭证
token的认证流程:
1、用户输入用户名和密码,发送给服务器
2、服务器验证用户名和密码,正确的话就返回一个签名过的token(token可以认为就是个长长的字符串),浏览器客户端拿到这个token。
3、后续每次请求中,浏览器会把token作为http header发送给服务器,服务器验证签名是否有效,如果有效就认证成功,可以返回客户端需要的数据。
-
jwt
概念:jwt是json web token缩写,它将用户信息加密到token里,服务器不保存任何用户信息,服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。
组成:
wt包含三个部分:Header头部,Payload负载和Signature签名。由三部分生成token,三部分之间用 “.” 号做分割。例如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Redis
Redis的数据类型及使用场景
1、String
最常规的 set/get 操作,value 可以是String 也可以是数字,一般做一些复杂的计数功能的缓存。
2、Hash
这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段,我在做单点登录的时候,就是用这种数据结构存储用户信息,以CookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似Session的效果。
3、List
使用List的数据结构,可以做简单的消息队列的功能,另外,可以利用lrange命令,做基于Redis的分页功能,性能极佳,用户体验好。
4、Set
因为Set堆放的是一堆不重复的集合,所以可以做全局去重的功能。我们的系统一般都是集群部署,使用JVM自带的Set比较麻烦,另外,就是利用交集,并集,差集等操作,可以计算共同喜好,全部的喜欢,自己独有的喜好等功能。
5、Sorted Set
Sorted Set 多了一个权重参数Score,集合中的元素能够按Score进行排序,可以做排行榜应用,取TOP N操作,Sorted Set可以用来做延时任务。
Redis的过期策略和内存淘汰机制?
Redis采用的是定期删除 + 惰性删除策略
1、为什么不用定时删除策略?
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源,在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略。
2、定期删除 + 惰性删除如何工作?
定期删除,Redis默认每个100ms(100毫秒,0.1秒)检查,有过期key则删除,需要说明的是,Redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查,如果只采用定期删除策略,会导致很多key到时间没有删除,于是,惰性删除派上用场了。
3、采用定期删除 + 惰性删除就没有其他问题了么?
不是的,如果定期删除没有删除掉key,并且你也没及时去请求key,也就是说惰性删除也没生效,这样,Redis的内存会越来越高,那么就应该采用内存淘汰机制。
在 redis.config 中有一行配置:
# maxmemory-policy volatile-lru
Redis和数据库双写一致性问题
先更新数据库,再删除缓存,延时双删
Redis缓存穿透,缓存击穿,缓存雪崩区别和解决方案
1、缓存穿透:
如果每次都去查一个 “缓存和数据库中都不存在的数据 (如id = -1的数据)”,因为缓存中不存在,那么每次请求都会访问数据库,从而导致缓存失去意义,高并发的情况下就可能导致数据库崩溃,这就是缓存穿透。
缓存穿透解决方案:
缓存空值,如果查询数据库返回的数据为空,我们仍然把这个空值放到redis缓存中,只是将它的过期时间设置的很短,另外为了避免不必要的内存消耗,可以定期清理空值的key。
2、缓存击穿:
说缓存击穿之前,我们先来了解一个概念 ------ 热点key,某个访问非常频繁,访问量非常大的一个缓存key,我们叫做热点key。
缓存击穿是指某个热点key在失效的瞬间(一般是缓存时间到期),持续的大并发请求穿破缓存,直接打到数据库,就像一个屏障上凿开了一个洞,造成数据库压力瞬间增大,这就是缓存击穿。
缓存击穿解决方案:
设置热点key永不过期,也可以手动清除缓存。
3、缓存雪崩:
缓存雪崩是指缓存由于某些原因整体或者大量失效,导致大量请求打到后端数据库,从而导致数据库崩溃,整个系统崩溃 ,发生灾难。
缓存雪崩解决方案:
通过设置不同的过期时间,来错开缓存过期,从而避免缓存集中失效。
WebSocket
Http和WebSocket的区别?
http是短连接,因为请求之后,都会关闭连接,下次重新请求数据,需要再次打开连接。WebSocket协议是一种长连接,只需要通过一次请求来初始化连接,然后所有的请求和响应都是通过TCP连接进行通信。
WebSocket中的常用注解有哪些?
@ServerEndpoint类似于servlet中的 @RequestMapping
@OnOpen类似于servlet中的init() 初始化
@OnClose类似于servlet中的destroy() 销毁
@OnMessage类似于servlet中的service请求 (意思就是发送数据的方式 @doPost() / @doGet() 组合)
Vue
1、beforeCreate(创建前)
在实例初始化之后,数据观测和事件配置之前被调用,此时组件的选项对象还未创建,el和data并未初始化,因为无法访问methods,data,computed等上的方法和数据。
2、created(创建后)
实例已经创建完成之后被调用,在这一步,实例已完成以下配置:数据观测,属性和方法的运算,完成了data数据的初始化。
3、beforeMount(挂载前)
挂载开始之前被调用,相关的render函数首次被调用(虚拟DOM),实例已完成以下的配置:编译模板,把data里面的数据和模板生成xml,完成了el和data初始化,注意此时还没有挂载html到页面上。
4、mounted(挂载完成)
挂载完成,也就是模板中的html渲染到html页面中,此时一般可以做一些ajax操作,mounted只会执行一次。
5、beforeUpdate(数据更新前)
在数据更新之前被调用,发生在虚拟DOM重新渲染和打补丁之前,可以在该钩子中进一步地更改状态,不会触发附加地重渲染过程。
6、updated(更新后)
在由于数据更改导致虚拟DOM重新渲染和打补丁时会调用,调用时,组件DOM已经更新,所有可以执行依赖于DOM的操作,然后在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,该钩子在服务区端渲染期间不被调用。
7、beforeDestroy(销毁前)
在实例销毁之前调用,实例仍然完全可用。
-
这一步还可以用this来获取实例。
-
一般在这一步做一些重置的操作,比如清除掉组件中的定时器和监听的dom事件
8、destroyed(销毁后)
在实例销毁之后调用,调用后,所有的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用。
Http
Http和Https有什么区别?
1、https协议需要ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80.后者是443。
4、http的连接很简单,是无状态的;https协议是由ssl + http协议构建的可进行加密传输,身份认证的网络协议,比http协议安全。
Shiro
Nginx
Nginx有哪些负载均衡策略?
负载均衡,即是代理服务器将接收的请求均衡的分发到各服务器中。
1、指定权重(weight)轮询(默认,常用)
指定轮询几率,可以给不同的后端服务器设置一个权重值(weight),weight和访问比率成正比。
接收到的请求按照权重分配到不同的后端服务器,即使在使用过程种,某一台后端服务器宕机,Nginx会自动将该服务器剔除出队列,请求受理情况不会受到任何影响。
这种方式用户调整不同的服务器上请求的分配率;权重数据越大,被分配到请求的几率越大;该权重值,主要是针对实际工作环境中不同的后端服务器硬件配置进行调整的,多用于后端服务器性能不均的情况。
upstream dynamic_upstream{
#ip地址1服务器的访问概率:30%
server ip地址1 weight = 3;
#ip地址2服务器的访问概率:70%
server ip地址2 weight = 7;
}
2、ip_hash (常用)
上述方式存在一个问题,在负载均衡系统中,假如用户在某台服务器上登录了,那么该用户第二次请求的时候,由于负载均衡,每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,Session信息就丢失了!
这种情况可以采用ip_hash指令解决,如果客户已经访问了某个服务器A,当用户再次访问时,会将请求按访问ip的hash结果分配,自动定位到该服务器A。这样每个访客ip会固定访问一个后端服务器,可以解决session不能跨服务器的问题。
upstream dynamic_upstream{
ip_hash; #保证每个访客固定访问一个后端服务器
server ip地址1;
server ip地址2;
}
3、least_conn 最少连接数
把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn就可以达到更好的负载均衡效果。
upstream dynamic_upstream{
least_conn; #把请求转发给连接数较少的后端服务器
server ip地址1;
server ip地址2;
}
4、fair (第三方)
智能调整调度算法,动态根据后端服务器的请求处理到响应的时间进行均衡分配,响应时间短处理效率高的服务器分配到请求的概率高,响应时间长处理效率低的服务器分配到的请求少。
需要注意的是Nginx默认不支持fair算法,如果要使用这种调度算法,请安装upstream_fair模块。
upstream dynamic_upstream{
fair; #实现响应时间短的优先分配
server ip地址1;
server ip地址2;
}
妆主会信息科技
Mybatis执行流程
1、mybatis中xml解析是通过SqlSessionFactoryBuilder.build()方法
2、初始化mybatis(解析xml文件构成Configuration对象)并初始化SqlSessionFactory对象
a. 在解析xml时会同时根据其节点做出相应的初始化操作
b. 关键节点:settings,typeAliases,mappers
3、通过SqlSessionFactory.openSession()方法打开一个SqlSession对象
a. SqlSessionFactory对象的作用是里面存了全局的配置信息以及初始化环境和DataSource,DataSource对象可以用来开辟连接,SqlSessionFactory对象是用 来保存全局信息并且打开数据库连接
b. 在打开SqlSession对象的时候就会开辟一个连接对象并传给SqlSession对象,和数据库打交道的操作入口在于SqlSession对象
4、通过SqlSession.getMapper()根据传入的Mapper对象类型动态代理并返回一个动态代理后的Mapper对象
5、由SqlSession.select()/update(),MapperProxy对象的invoke()方法执行后在执行excecure方法,再根据情况选择select/update
6、Executor(is泽q特)执行Query/queryFormDatabase,在前面经过参数名封装和缓存查询之后(缓存为空),会调用queryFromDatabase方法去数据库当中查
7、SimpleExecurot执行doQuery()方法,初始化prepareStatement并且给#{}参数赋值
8、StatmentHandler执行query()方法,执行sql语句
9、ResultHandler.handleResultSets()方法封装结果集
ResultMap和ResultType的区别?
ResultMap是自己指定返回值与对象及对象内部属性名和数据库列名的绑定
ResultType是直接返回值与别名库当中java对象的映射
单体架构,分布式,微服务区别
jdbc执行流程
1、注册驱动
2、获取Connection连接
3、执行预编译
4、执行SQL
5、封装结果集
6、释放资源
vue子父组件传值
props 和 emit。父组件向子组件传递数据是通过props传递的,子组件传递给父组件是通过 emit触发事件来做到的。
vue自己封装过函数没有
阿里云oss图片遇到过跨域没有没有,怎么解决的
thymeleaf语法用了哪些
-
th属性:
1、th:text 文本替换
2、th:utext 支持html的文本替换
3、th:value 属性赋值
4、th:each 遍历循环元素
5、th:if 判断条件,类似的还有th:switch,th:case等
6、th:attr 设置标签属性,多个属性可以用逗号分割
-
标准表达式语法:
1、${…} 变量表达式
2、@{…} 链接表达式
-
常用的内置对象
1、ctx:上下文对象
2、vars:上下文变量
3、locale:上下文的语言环境
4、request:(仅在web上下文)的HttpServletRequest对象
5、response:(仅在web上下文)的HttpServletRespone对象
6、session:(仅在web上下文)的HttpSession对象
7、servletContext:(仅在web上下文)的ServletContext对象
你了解过哪些设计模式
Mybatis底层用的是什么动态代理
jdk动态代理
Redis的指令,函数
怎么设置nginx的反向代理
设计表要注意哪些点
1、满足表的三大范式
2、基本除中间表外,每个表至少含字段id,createtime(创建时间),updatetime(更新时间),如果需求为逻辑删除的话,需要加is_delete(逻辑删除状态),creator(创建人),updater(更新者)
3、建立对应索引
4、字段允许适当冗余,以提高查询性能,但必须考虑数据一致。
mysql用过哪些函数
-
聚合函数
1、avg() 返回指定列的平均值
2、count() 返回指定列中非null值的个数
3、min() 返回指定列的最小值
4、max() 返回指定列的最大值
5、sum() 返回指定列的所有值之和
-
字符串函数
1、concat() 字符串连接
2、length() 返回字符串的字符数
3、trim() 返回字符串首部和尾部的所有空格
-
日期和时间函数
1、now() 返回当前的日期和时间
2、year() 返回日期date的年份
-
加密函数
1、decode(str,key) 使用key作为密钥解密加密字符串str
2、md5() 计算字符串str的MD5校验和
-
控制流函数
1、case when[test1] then [result] … else [default] end 如果testn是真,则返回resultn,否则返回default
-
系统信息函数
1、database() 返回当前数据库名
2、user() 返回当前登录用户名
3、version() 返回mysql服务器版本
自己封装过哪些方法,原理是什么?
/**
* 判断是否为空
* @param obj
* @return
*/
public static boolean isEmpty(Object obj){
if(obj instanceof CharSequence){
return StringUtils.isBlank((String)obj);
}else if(obj instanceof Collection){
Collection coll = (Collection) obj;
return coll == null || coll.size() == 0;
}else if(obj instanceof Map){
Map map = (Map) obj;
return map == null || map.size() == 0;
}else if(obj instanceof Object[]){
Object[] array = (Object[]) obj;
return array == null || array.length == 0;
}
return obj == null;
}
百家医道
SpringBoot中事务注解详解
@Transactional spring事务注解
1、简单开启事务管理
@EnableTransactionManagement //启动注解事务管理,等同于xml配置方式的 <tx:annotation-driven/>
2、事务注解详解
默认遇到 throw new RuntimeException("…") 会回滚
需要捕获的 throw new Exception("…") 不会回滚
指定回滚:
@Transactional(rollbackFor=Exception.class)
public void methodName(){
//不会回滚
throw new Exception("...");
}
指定不回滚:
@Transactional(noRollbackFor=Exception.class)
public ItemDaoImpl getItemDaoImpl(){
//会回滚
throw new RuntimeException("注释");
}
如果有事务,那么加入事务,没有的话新建一个(默认)
@Transactional(propagation=Propagation.REQUIRED)
容器不为这个方法开启事务
@Transactional(propagation=Propagation.NOT_SUPPORTED)
readOnly=true只读,不能更新,删除
@Transactional(propagation=Propagation.REQUIRED,readOnly=true)
设置超时时间
@Transactional(propagation=Propagation.REQUIRED,timeout=30)
设置数据库隔离级别
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT)
银行转账问题,出现锁问题,如何解决
冒泡排序
1、数组从小到大排序
int[] data = {9,3,5,1,7};
int len = data.length;
for(int i=0; i<len-1; i++){
for(int j=0; j<len-1-i;j++){
//判断大小
if(data[j] > data[j+1]){
//执行替换
int temp = data[j+1];
data[j+1] = data[j];
data[j] = temp;
}
}
}
System.out.print(Arrays.toString(data));// [1,3,5,7,9]
2、List从小到大排序
List<Integer> data = Arrays.toList(9,3,5,1,7);
int len = data.size();
for(int i=0; i<len-1; i++){
for(int j=0; j<len-1-i; j++){
//判断大小
if(data.get(j) > data.get(j+1)){
//进行替换
int temp = data.get(j+1);
data.set(j+1,data.get(j));
data.set(j,temp);
}
}
}
System.out.print(data);// [1,3,5,7,9]
茹量科技
讲一下反射
递归算法
多个系统使用redis实现单点登录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9U7HGgJJ-1635983510148)(F:\Typora笔记\studyImage\redis解决单点登录.jpg)]
系统A登录后,系统B不需要登录,例如:淘宝,天猫
1、系统A,用户登录之后将信息以key,value的形式存入到redis,key为唯一标识符,value为用户对象,key可以是token,可以是uuid,设置有效期
2、还要将数据标识符key,存储到浏览器中,cookie或者sessionStore,方便其他系统取出用户数据
3、系统B从cookie中拿到存储的key,从reids中去查找,如果存在,则通过key在redis中对应查询用户信息,如果不存在,则重新登录
4、用拦截器查询reids中的用户信息是否过期
关雎网络
jsp内置对象有哪些?
1、request
2、response
3、session
4、application
5、out
6、pageContext
7、config
8、page
9、exception
HashMap底层结构及实现
Mybatis中的 #{}预编译是怎么实现的
调用PreparedStatement的set方法来赋值
使用MyBatis的mapper接口调用时有哪些要求?
1、Mapper接口方法名和mapper.xml中定义的每个sql的id相同
2、Mapper接口方法的输入参数类型和mapper.xml中定义的每个parameterType的类型相同
3、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
4、Mapper.xml文件的namespace即是mapper接口的类路径
生成订单后未支付,是如何取消的
我们都经常在淘宝上买东西,当我们提交订单后,如果某个时间段之内我们没有支付,淘宝肯定不会帮我们一致保留那个订单,如果超过半小时我们未支付的话,淘宝会自动帮我们取消订单,在没有用消息队列之前,我们可以通过设置一个定时任务,设定一个定时规则去轮询数据库查询超过半个小时而且未支付的订单,然后修改订单状态为已取消,这也是一个解决方案,但是需要轮询数据库,增加了对数据库的压力
鞋米商城客户那边有个财务系统,需要和我们的后台管理系统的单点,解决思路?
我们解决思路是通过redis实现sso,
1、登录系统后,生成一个token,将token作为key,用户信息作为value存入redis中
2、设置缓存的过期时间,半小时,模拟session效果
3、将token写入cookie中,如果cookie被禁用,则写入sessionStore
4、从cookie中取出token,如果token不存在,则要求登录
5、如果cookie存在,则登录成功,重新设置缓存的过期时间
讲一下项目
添加购物车如何在不登录的情况下,将商品信息进行保存
在用户将商品添加到购物车时,把商品规格id,下单数量存入到cookie中,设置cookie有效期为半小时,登录之后再将cookie中数据写入到数据库
解决跨域
@CrossOrigin
Jquery选择器有哪些?
一、基本选择器
1、ID选择器 #id
描述:根据给定的id匹配一个元素,返回单个元素
示例:$("#test") 选取 id 为 test 的元素
2、类选择器 .class
描述:根据给定的类名匹配元素,返回元素集合
示例:$(".test") 选取所有class为test的元素
3、元素选择器 element
描述:根据给定的元素名匹配元素,返回元素集合
示例:$(“p”) 选取所有的
元素
4、*
描述:匹配所有的元素,返回元素集合
示例:$("") 选取所有的元素
5、selector1,selector2,selectorN
描述:将每个选择器匹配到的元素合并后一起返回,返回合并后的元素集合
示例:$(“p,span,p.myClass”) 选取所有
, 和class为myClass的
标签的元素集合
二、层次选择器
层次选择器根据层次关系获取特定元素
1、后代选择器
示例:$(“p span”) 选取
元素里的所有的元素 (注:后代选择器选择父元素所指定选择的元素,不管是儿子级,还是孙子级)
2、子选择器$(“parent > child”)
示例:$(“p>span”) 选择
元素下的所有元素 (注:子选择器只选择直属于父元素的子元素)
3、同辈选择器 $(“prev+next”)
描述:选择紧接在prev元素后的next元素,返回元素集合
示例:$(".one+p") 选取class的one的下一个
同辈元素集合
三、过滤选择器
1、基本过滤选择器
1. :first
描述:选取第一个元素,返回单个元素
示例:$(“p:first”) 选取所有
元素中第一个
元素
2. :last
描述:选取最后一个元素,返回单个元素
示例:$(“p:last”) 选取所有
元素中最后一个
元素
3. :not(selector)
描述:去除所有与给定选择器匹配的元素,返回元素集合
示例:$(“input:not(.myClass)”) 选取class不是myClass的元素
4. :even
描述:选取索引是偶数的所有元素,索引从0开始,返回元素集合
5. :odd
描述:选取索引是奇数的所有元素,索引从0开始,返回元素集合
6. :eq(index)
描述:选取索引等于index的元素,索引从0开始,返回单个元素
7. :gt(index)
描述:选取索引大于index的元素,索引从0开始,返回单个元素
8. :lt(index)
描述:选取索引小于index的元素,索引从0开始,返回元素集合
9. :focus
描述:选取当前获取焦点的元素
form序列化表单值
serialize()方法通过序列化表单值。 $(“form”).serialize();
serializeArray()方法通过序列化表单值。返回 Json对象, $(“form”).serializeArray();
AOP中有哪几种增强?
1、前置增强 @Before
2、返回增强 @AfterReturning
3、后置增强 @After
4、异常增强 @AfterThrowing
5、环绕增强 @Around
AOP中相关概念释义
1、切面(Aspect)一个横切关注点的模块化,这个关注点可能会横切多个对象。它是横切关注点的另一种表达方式。
2、连接点(Joinpoint)在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候,在Spring AOP中,一个连接点表示一个方法的执行,即所有方法都可以嵌入横切逻辑。
3、切入点(Pointcut)匹配连接点的断言。它通常是一个表达式,有专门的语法,用于指明在哪里(或者说在哪些方法调用上)嵌入横切逻辑
4、通知(Advice)在切面的某个特定的连接点上执行的动作,也就是我们前面提到的横切逻辑,如日志处理逻辑,事务处理逻辑,切入点致命在哪里嵌入横切逻辑,通知指明切入上面,即干什么。
5、目标对象(Target Object)被一个或者多个切面所通知的对象,也被称作被通知对象
6、代理对象(Proxy Object)AOP框架创建的对象,它和目标对象遵循同样的接口,使用它的方式和使用目标对象的方式是一样的,但是它是目标对象的增强版,”通知“中的代码执行将会被代理对象的方法调用触发,在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
execution为切入点
Mysql中动态sql有哪些?
1、if语句
2、where语句
3、choose(when,otherwise)语句
4、trim语句
5、sql片段
<!-- 定义sql片段 -->
<sql id="conditSql">
<if test="userName != null and userName.trim()!=''">
and userName = #{userName}
</if>
<if test="sex !=null and sex.trim()!=''">
and sex = #{sex}
</if>
</sql>
<!-- 引用sql片段 -->
<select id="searchList" resultType="user" parameterType="com.entity.User">
select * from user
<where>
<!-- 引入sql片段,如果refid指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="conditSql"></include>
</where>
</select>
6、foreach语句
JDK1.8新特性
1、Lambda表达式
2、函数式接口
3、Stream API
Stream操作的三个步骤,
- 创建stream
- 中间操作(过滤,map)
- 终止操作
4、新的日期API / LocalData / LocalTime / LocalDateTime