compareTo() 方法和 equals() 方法有什么区别?
compareTo() 方法和 equals() 方法都是用于比较两个字符串的
但是有2点不同
1、equals()可以接收一个Object类型的参数,而compareTo()只能接收一个String类型的参数
2、equals()返回值为Boolean,而compareTo()的返回值为int
当equals() 方法返回true时,或者compareTo()方法返回0时
,则表示两个字符串完成的相等
其他String的重要方法
indexOf():查找字符串首次出现的下标位置
lastIndexOf():查询字符串最后出现的下标位置
contains():查询字符串中是否包含另一个字符串
toLowerCase():把字符串全部转换成小写
toUpperCase():把字符串全部转换成大写
length():查询字符串的长度
trim():去掉字符串首尾的空格
replace():替换字符串中的某些字符
split():把字符串分割并返回字符串数组
join():把字符串数组转为字符串
format():字符串占位符作用
valueOf():获取当前字符在整个字符串的位置
== 和 equals 的区别?
== 对于基本数据类型来说,是用于比较“值”是否相等,而对于引用类型来说,是用于比较引用地址是否相同
String 采用final修饰的好处?
安全,高效
String和StringBuffer、StringBuilder 的区别?
String 类型是不可变的,所以在字符串拼接的时候使用String的话性能会很低
因此需要使用另一个数据类型StringBuffer,它提供了append和insert方法用于字符串的拼接,并且使用synchronized来保证线程安全
jdk1.5之后提供了StringBuilder (不加锁)的数据类型来提高效率
String 常见的创建方式有两种
1、String s1 = "java";// 直接赋值的方式
2、String s2 = new String("java"); // new String 的方式
两者在JVM的存储区域是截然不同的
结果返回 true
介绍下什么是Spring框架的DI和IOC?
IOC 控制反转,指将对象的创建权,反转到Spring容器
DI 依赖注入,指Spring创建对象的过程中,将对象依赖属性通过配置进行注入,不能单独存在,需要在IOC的基础上完成操作
依赖注入(DI)和控制反转(IOC)是从不同的⻆度描述的同一件事情,通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦
Spring里面 bean的scope作用域有哪些?
singleton:单例例, 默认值,调用getBean方法返回是同一个对象,实例会被缓存起来,效率比较高,当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean
prototype: 多例,调用getBean方法创建不同的对象,会频繁的创建和销毁对象造成很大的开销
其他少用 (作用域 只在 WebApplicationContext)
request :每个Http请求都会创建一个新的bean
session: 每个Http Session请求都会创建一个新的bean
global session(基本不用)
xml 示例
<!--<bean id="video" class="net.vincent.sp.domain.Video" scope="singleton"> -->
<bean id="video" class="net.vincent.sp.domain.Video" scope="prototype">
<property name="id" value="9"/>
<property name="title" value="Spring 5.X课程" />
</bean>
private static void testScope(ApplicationContext context){
Video video1 = (Video)context.getBean("video");
Video video2 = (Video)context.getBean("video");
//靠匹配内存地址,== 是匹配内存地址
System.out.println( video1 == video2 );
}
能否说下什么是AOP, 使用场景有哪些?
Aspect Oriented Program 面向切面编程, 在不改变原有逻辑上增加额外的功能
AOP思想把功能分两个部分,分离系统中的各种关注点
核心关注点
业务的主要功能
横切关注点
非核心、额外增加的功能
用户下单为例子
核心关注点:创建订单
横切关注点:记录日志、控制事务
- 好处
1、减少代码侵入,解耦
2、可以统一处理横切逻辑
3、方便添和删除横切逻辑
什么是AOP 的 横切、通知、连接点、切入点、切面 ?
横切关注点
对哪些方法进行拦截,拦截后怎么处理,这些就叫横切关注点
比如 权限认证、日志、事物通知 Advice
在特定的切入点上执行的增强处理
比如你需要记录日志,控制事务 ,提前编写好通用的模块,需要的地方直接调用连接点 JointPoint
要用通知的地方,业务流程在运行过程中需要插入切面的具体位置,一般是方法的调用前后,全部方法都可以是连接点切入点 Pointcut
不能全部方法都是连接点,通过特定的规则来筛选连接点, 就是Pointcut,选中那几个你想要的方法
在程序中主要体现为书写切入点表达式(通过通配、正则表达式)过滤出特定的一组
JointPoint连接点
过滤出相应的 Advice 将要发生的joinpoint地方切面 Aspect
通常是一个类,里面定义 切入点+通知 , 定义在什么地方; 什么时间点、做什么事情
通知 advice指明了了时间和做的事情(前置、后置等)
切入点 pointcut 指定在什么地方干这个事情
web接口设计中,web层->网关层->服务层->数据层,每一层之间也是一个切面,对象和对象,方法和方法之间都是一个个切面目标 target
目标类,真正的业务逻辑,可以在目标类不知情的条件下,增加新的功能到目标类的链路上织入 Weaving
把切面(某个类)应用到目标函数的过程称为织入
什么是静态代理?
- 由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件就已经存在
- 通过将目标类与代理类实现同一个接口,让代理类持有真实类对象,然后在代理类方法中调用真实类方法,在调用真实类方法的前后添加我们所需要的功能扩展代码来达到增强的目的
- A -> B -> C
优点
- 代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可
- 方便增加功能,拓展业务逻辑
缺点
- 代理类中出现大量冗余的代码,非常不利于扩展和维护
- 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度
什么是动态代理,spring aop是用什么代理?
在程序运行时,运用反射机制动态创建而成,无需手动编写代码,SpringAOP里面常用的是 JDK动态代理、CGLIB动态代理
JDK动态代理和CGLib动态代理的区别?
JDK动态代理,要求目标对象实现一个接口 ,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以用CGLib动态代理
JDK动态代理是自带的,CGlib需要引入第三方包
CGLib动态代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展
CGLib动态代理基于继承来实现代理,所以无法对final类、private方法和static方法实现代理
Spring AOP中的代理使用的默认策略?
- 如果目标对象实现了接口,则默认采用JDK动态代理
- 如果目标对象没有实现接口,则采用CgLib进行动态代理
- 如果目标对象实现了接口,程序里面依旧可以指定使用CGlib动态代理
Mybatis加载的流程是什么?
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心
SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得
SqlSessionFactoryBuilder 可以从 XML 配置文件或一个预先配置的 Configuration 实例例来构建出 SqlSessionFactory 实例
工厂设计模式里面需要获取SqlSession ,里面提供了在数据库执行 SQL 命令所需的所有方法
${}
和#{}
的区别是什么?
#{}
是预编译处理理,${}
是字符串替换Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理{}替换成变量的值
使用#{}可以有效的防止SQL注入,提高系统安全性
有没用过Mybatis一级缓存,能否介绍下?
一级缓存的作用域是SQLSession,同一个SqlSession中执行相同的SQL查询(相同的SQL和参数),第一次会去查询数据库并写在缓存中,第二次会直接从缓存中取
基于PerpetualCache 的 HashMap本地缓存,默认开启一级缓存
失效策略:当执行SQL时候两次查询中间发生了增删改的操作,即insert、update、delete等操作commit后会清空该SQLSession缓存; 比如sqlsession关闭,或者清空等
有没用过Mybatis二级缓存,能否介绍下?
二级缓存是namespace级别的,多个SqlSession去操作同一个namespace下的Mapper的sql语句,多个SqlSession可以共用二级缓存,如果两个mapper的namespace相同,(即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中,但是最后是每个Mapper单独的名称空间)
基于PerpetualCache 的 HashMap本地缓存,可自定义存储源,如 Ehcache/Redis等 默认是没有开启二级缓存
操作流程
第一次调用某个namespace下的SQL去查询信息,查询到的信息会存放该mapper对应的二级缓存区域
第二次调用同个namespace下的mapper映射文件中,相同的sql去查询信息,会去对应的二级缓存内取结果
失效策略略:执行同个namespace下的mapepr映射文件中增删改sql,并执行了commit操作,会清空该二级缓存
注意:实现二级缓存的时候,MyBatis建议返回的POJO是可序列化的, 也就是建议实现Serializable接口
缓存淘汰策略:会使用默认的 LRU 算法来收回(最近最少使用的)
一级缓存和二级缓存同时启用,查询顺序是怎样的?
优先查询二级缓存->查询一级缓存->数据库
什么是Mybatis3.X的懒加载?
按需加载,先从单表查询,需要时再从关联表去关联查询,能大大提高数据库性能, 并不不是所有场景下使用懒加载都能提高效率
哪些查询配置支持懒加载?
- resultMap里面的 association、collection 有延迟加载功能
<resultMap id="VideoOrderResultMapLazy" type="VideoOrder">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="out_trade_no" property="outTradeNo"/>
<result column="create_time" property="createTime"/>
<result column="state" property="state"/>
<result column="total_fee" property="totalFee"/>
<result column="video_id" property="videoId"/>
<result column="video_title" property="videoTitle"/>
<result column="video_img" property="videoImg"/>
<!--
select: 指定延迟加载需要执行的statement id
column: 和select查询关联的字段
-->
<association property="user" javaType="User" column="user_id"
select="findUserByUserId"/>
</resultMap>
<!-- 一对一管理查询订单, 订单内部包含用户属性懒加载-->
<select id="queryVideoOrderListLazy" resultMap="VideoOrderResultMapLazy">
select
o.id id,
o.user_id ,
o.out_trade_no,
o.create_time,
o.state,
o.total_fee,
o.video_id,
o.video_title,
o.video_img
from
video_order o
</select>
<select id="findUserByUserId" resultType="User">
select * from user where id=#{id}
</select>
什么是接口幂等性?接口幂等性问题有哪些常见的解决方案?
接口幂等性简单来说就是本来应该执行一次接口操作,不论是因为一些人为原因也好,网络不佳系统故障原因也好,接口就是被重复调用了,那么添加了接口幂等性保障的接口,重复调用时就会自动识别你这次来执行已经不是第一次了,就一定不会让你执行成功
解决方案
唯一索引:在数据表中对一些具有唯一性业务属性的字段建立唯一索引
去重表:每次执行接口逻辑前先往去重表中插入一条唯一记录
状态机:根据当前的对象的状态判断当前是否可以执行接口的逻辑
其中去重表的方案,暴露的问题就比较明显,因为它的本质就是往数据库中先插入一条数据,数据库插入操作是非常不适合于高并发的场景的,如mysql数据库的单机能承载的并发也才几千,当并发高达几十万甚至上百万时,mysql数据库直接就被打垮了,此时就需要换一些能承载高并发的系统如redis,我们完全可以把插入一条数据的操作给写到redis中,这样既同样也能达到去重的目的,同时也还能承载高并发的业务场景