hashmap的底层原理
hashmap的底层是通过数组+链表+红黑树实现的,在创建HashMap之前会先创建一个数组,默认长度为16,使用put存放数据时根据key的hash值(根据key的hash值%数组长度)确定在数组中的位置,得到的数据一定在长度之内,那么根据算出来的数据存在对应的位置,如果该位置为空则存入,否则去遍历链表看key是否一致,一致则视为同一个数据,覆盖,不同则将生成一个链表挂在数组的下面,使用get取值会先根据key的hash值并进行equals比较,对于hashmap来说hash碰撞的概率是很高的,所以引入了链表来存储,但是链表的查询效率是比较低的,如果每次存都要通过链表遍历的话效率慢,jdk1.8之后就引入了红黑树,就是当链表的长度超过8位并且数组的长度大于等于64时,就会自动将链表转换成红黑树,红黑树也是一种特殊的平衡二叉查找树,所以左边存放的是比根节点小的数据,右边存放比根节点大的数据,那么如果我们要存放的数据很多的话,也引入了扩容机制,当前长度*加载因子=……
就比如默认长度16*加载因子默认0.75=12,那么当存放第12个数据时,就会触发扩容机制,扩容为原来长度的两倍,也就是32个,是重新生成了一个数组而不是在之前的16之后加了,并把原来的数据拷贝过去,
对springboot的理解(运行原理)
我理解的springboot就是基于spring去实现的,对spring来说简化了开发、部署和维护,里边提供了自动配置,内嵌服务器,微服务的支持等,相对于spring来说都是更简便的,那springboot我觉得他就是约定大于配置的,就是有一个meta.info里有一个spring.factorys文件,里边就是key value的形式,来指定配置,自动加载之类的,在springboot项目的核心注解springbootapplication中有三个注解1、springbootconfigcation 2、enableautoconfiguation 3、ComponentScan 对于第一个注解springbootconfigcation注解来说就是将主类当成一个配置文件来使用,enableautoconfiguation 开启自动配置功能,告诉SpringBoot开启自动配置功能,这样自动配置才能生效,读取默认配置文件spring.factories文件,来完成默认配置信息的加载,ComponentScan 自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中,现在将我们在spring.factorys上有的和自己写的被springboot注解componentscan组件扫描到的那些加载到ioc容器中,后续直接通过di依赖注入@autowired来使用,我认为springboot给我的最直观的概念就是约定大于配置
分布式事务的理解和解决方案
分布式事务的几种解决方案-CSDN博客
分布式事务就是指多个数据库之前的数据一致问题
事务的ACID原则就是事务的原子性、一致性、隔离性、持久性,事务就是用来保证数据的一致性,要么全部成功要么全部失败,在spring的事务中我使用的是@Transication注解来实现的事务,但是现在我们的架构一般都是使用的微服务,微服务的特点就是分库,可能对于一个电商系统,当客户要购买商品,此时订单表中要添加一条记录,商品的库存需要变更,客户的余额需要减,等,那么对于这种的微服务系统传统的spring事务是无法解决的,此时就引入了分布式事务seata,在cap理论中我们知道不能同时满足cap,只能保证强制一致性或者最终一致性,seata有三个基本组件,TC协调者 TM事务管理者 RM资源管理器
第一种解决方案:基于XA协议的两阶段提交2PC,基于cap理论也可以知道如果要保证数据的强一致性会带来性能上的影响,从而影响到可用性
第二种解决方案:TCC补偿机制,最终一致性,损失了数据的强一致性然后通过异步补偿的机制去保证数据的最终一致性,适合用在并发量比较高的场景
对于mysql优化你都做过哪些
mysql优化的话是对于数据库层面的优化和sql语句的优化
数据库层面就是要考虑如果数据量特别大时要考虑分库分表
sql语句优化主要就是针对于慢sql做一些优化
在项目中我是这么定位慢sql的:开启慢查询日志,找到sql,然后用explain来进行分析参数有1、slow_query_log是否开启,默认是off不启用,2、log_output日志输出的位置,默认是文件保存,3、slow_query_log_file指定慢查询日志文件的路径和名字,4、long_query_time 超过多久才记录到慢查询日志,单位为秒,默认30s
1、杜绝使用select *来查询所有字段,前端需要什么我们就查询什么,当然在阿里规范里也明确规定了
2、小表驱动大表,我的理解就是当有一个学生表里面有20条数据,和分数表的关系肯定是一对多的,一个学生有多个分数,相对的在分数表中肯定有一个和学生关联的,那么我在连表查询时会把学员表放前面这样就是用20条数据去匹配成绩,这样就是小表驱动大表,如果是学生表在后就是大表驱动小表,性能较差,底层是一个连接缓冲区(join buffer),比如说我们选择小表驱动大表,此时会先把学生表前15条数据读取到连接缓冲区,然后用成绩表去匹配连接缓冲区的数据,记录匹配结果,然后清空,接着再从学生表读取15条记录放入连接缓冲区中,然后继续和成绩表匹配,接着记录匹配结果
3、尽量用连接查询代替子查询就是用join on的方式
4、group by,提升分组效率,我们会发现当使用group by时查询速度过慢,此时可以给我们要排序的那个字段加上索引,可以提高查询效率
5、批量操作,如果我们有多条记录需要插入到表中,在项目中循环往数据库中插入数据,那么会多次访问数据库,当我们试用了mybatis时就可以使用动态sql的方式进行优化,使用foreach标签
6、使用limit,如果说一个表中的数据量很大,此时全部查询严重影响性能,并且还可能内存溢出,使用limit来限制查询的条数,但是如果是limit 10000,9数据,对于mysql来说不管limit从第几页开始,都会从第一页进行扫描,也可以避免这种情况发生,我们可以给数据一个id每次自增,自增索引,那么想从第几页开始时就能直接找到了,提高了查询效率
7、join连表不宜过多,会导致查询效率下降,如果说join太多会增强耦合度,如果说后续要进行分库分表不利于后期维护
8、在mysql中如果有像身份证号、手机号之类的固定长度的字段我一般会选择使用char,char是定长的,固定长度的字符比如身份证手机号,可以考虑用char类型因为比varchar查找等方面要快
9、尽量避免模糊查询前端左右%的出现,违背最左前缀原则,如果说必须要使用,可以用反向索引,对于一些比如姓名、住址之类的字段,我们可以根据姓、名进行分字段,查询时可以直接等值查询
mybatis如何分页的
第一种是我们直接在mapper.xml里select语句的后面手动加上关键字limit,传递当前页和每页展示多少条数就好,第二种方式就是使用intercepter拦截器在select语句执行之前去动态的拼接分页语句,实现分页
mybatis的缓存
mybatis分为一级缓存和二级缓存,一级缓存是默认开启的,是一个sqlsession的范围,从创建到销毁,然后二级缓存可以跨sqlsession,一个命名空间namespace的范围,共享sqlsession,需要手动开启,可能在缓存中出现的问题就是数据的完整性和一致性问题,比如说数据库的数据变更之后,本地缓存没有感知到,那就造成了脏读的情况,特别是在分布式系统中需要去考虑这些问题,来确保数据的完整性
那你如何确定一个查询结果可以被缓存?哪些因素回影响一级缓存和二级缓存的命中率呢?
默认情况下,mybatis的一级缓存会对非flush_cache操作的进行缓存,只要查询没有标记不参与缓存,并且查询是在同一个sqlsession中进行的,那么查询结果就会被缓存
影响一级缓存和二级缓存的命中率呢有几个方面1、缓存粒度,粒度越细,命中率越高,2、数据变更的频率,数据更改越频繁缓存失效的几率越大,3、查询条件的多样性,即使是在同一个库表中查询,那么每次查询的条件都不同也可能会影响缓存的命中率,4、事务边界,一级缓存是在事务内有效事务结束后缓存会被清空
针对大型高并发系统,你会如何设计mybatis缓存策略以提升性能和降低数据库压力,有哪些注意事项?
缓存的分区和数据分片,根据业务需求对缓存进行分区提升命中率,对于数据量大的表可以考虑数据分片来解决,减少单一缓存的压力
如果发现mybatis的缓存与数据库不一致,可能的原因?怎么解决?
并发更新,缓存没有及时刷新所导致的问题,使用缓存锁机制去保证数据的完整和一致性,确保并发更新数据的一致性,设置合适的缓存过期策略,利用mybatis的flushcache=true属性,在执行写操作后强制清除相关缓存
分享一次你在项目中利用mybatis缓存机制优化的具体案例,包括遇到的问题以及解决方案
在一个高并发流量的购物中,我发现商品的查询频率比较高,我选择myabtis的二级缓存去缓存数据,我引入了消息队列,当被更改时先去更新数据库,在发送消息到队列,有专门的监听服务去负责清楚或更新缓存中的数据,确保了数据的一致性
线程池的拒绝策略
1、抛出异常来拒绝新任务的处理
2、不抛出异常来拒绝新任务的处理
3、丢弃最早的未处理的任务请求
4、调用执行自己的线程运行任务
支付宝
注册支付宝商家账号
完成实名认证和企业认证
登录支付宝开放平台,有一些参数如 商户appid、商户公钥、私钥、支付宝公钥、支付宝网关地址
将支付宝的sdk集成到我的项目中,通常涉及下载sdk包并添加到我的项目中
然后根据文档去调用支付宝提供的相应的api去完成支付
支付完成后,支付宝会异步通知商户后台订单的付款情况
支付宝提供了多种付款方式,比如扫描支付
不过在测试的时候我一般会选择沙箱环节,只有在测试无误之后才会去真正的调用支付宝支付
ThreadLocal有哪些使用场景
在登录成功之后会往ThreadLocal中存储 当前对象,后续每次请求经过时,都会在网关去获取ThreadLocal中的值
ThreadLocal有点类似于map类型的数据变量,ThreadLocal类型的变量每个线程都有自己的一个副本,某个线程对这个变量的修改不会影响其他线程副本的值,可以说ThreadLocal为我们提供了一个保证线程安全的新思路,需要注意的是一个ThreadLocal变量,其中只能set一个值,一个ThreadLocal只能存储一个object对象,如果需要存储多个object对象那么 就需要多个ThreadLocal
对接第三方接口要考虑什么
安全性问题
涉及到数据的跨网络传输为了防止数据被拦截和篡改需要采用安全的通信机制比如https协议以及通过数据签名去避免数据的篡改
接口的稳定性和可靠性
会直接影响用户体验和业务的流程
接口是否存在访问限制或者费用
什么是CompletableFuture
是java8之后引入的一个类,它可以解决异步执行任务和处理异步任务的结果,异步编程,CompletableFuture可以优化系统的性能和响应速度,可以将线程进行一个异步处理,等到异步任务执行之后会触发一个回调方法,可以在回调方法去看异步执行的结果,优化了future了阻塞等待问题 提供了thenapply thenaccept thenrun
接口优化
接口优化就是对一些接口做一个幂等性之类的
使用线程池
使用mq进行异步解耦
使用缓存中间件redis
避免声明式事务transication
mysql有哪些锁
锁的属性:共享锁、排他锁
基于锁的粒度分类:行级锁、表级锁、页级锁、记录锁、间隙锁、临建锁
锁的状态:意向共享锁、意向排他锁
共享锁又称为读锁:当一个事务位数据加上读锁之后,其他事务只能对该数据加读锁,而不能加写锁,直到所有读的操作释放之后才会加写锁,共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题
排他锁又称为写锁:当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,知道该锁释放之后,其他事务才能对数据进行加锁,排他锁的目的是在数据修改时,不允许其他人同时修改,也不允许其他人读取,避免了出现脏读问题
表锁:锁住的是整个表,当下一个事务访问该表时,必须等前一个事务释放了锁才能进行对表的访问
行锁:行锁值上锁的时候锁住的是某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问,特点:力度比较小,不容易冲突,相对表锁支持的并发要高
记录锁:属于行锁的一种,只不过记录锁的范围只是表中的某一条记录,记录锁时说事务在加锁后锁住的只是表的某一行记录,加了记录锁之后数据可以避免数据在查询的时候被修改的重复度问题,也避免了修改的事务未提前被其他事务读取的脏读问题
页锁:在行锁和表级锁之间,开销和加锁时间介于表锁和行锁之间,会出现死锁,锁定粒度介于表锁和行锁之间,并发度一般
间隙锁:在事务加锁后锁住的是某一个区间,当表的相邻id之间出现空袭则会形成一个区间,遵循左开右闭原则,范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在重复读的事务级别中
临建锁:innodb默认的锁,在记录锁和间隙锁的组合,临建锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,会把相邻的下一个区间也会锁住
jdk17新特性
字符串拼接
instanceof模式匹配
switch关键字
switch增强 可以使用,来完成多个条件匹配 并且将:替换成->来完成使用 instanceof 用来判断这个变量是否属于这个类 新增Record类 这个类是相当于lombok属性 但是只提供了get方法 没有set方法
jvm优化
1、对堆内存的优化
调整参数:xmx 最大内存大小、xms初始化内存大小,一般设置为最大值的一半
2、优化元数据空间
元数据空间用于存储java类信息 包括类、方法、字段等,元数据空间的大小也会对性能有影响,JDK8后九二一通过调整MaxMetaspaceSize来优化元数据空间的大小
设置元数据空间的最大值,默认为-1 意思是没有上限,可以根据实际应用程序的需求设置合理的最大值,我么设置的好像是256M
3、优化线程池
线程太多会占用过多的内存,降低程序性能,可以通过调整线程池的大小来优化线程池
4、调整垃圾回收机制
使用CMS垃圾回收器,使用concurrent Mark sweep GC可以提高垃圾回收效率
使用G1 GC 他们是一种较新的垃圾回收机制,可以自动调整堆内存大小,并能够实现更快的垃圾回收时间和更少的垃圾回收暂停时间
5、调整GC参数
设置对象的晋级年龄,可以根据实际需要将对象晋级年龄设置为合适的值,以便更好地控制对象的回收
禁用显式垃圾回收,显式垃圾回收是一种比较耗时的操作,会对程序的性能产生影响,因此,建议不要在程序中过于频繁的使用显式垃圾回收
6、优化类的加载
在java应用程序运行过程中,类的加载需要占用一定的时间和内存资源,可以通过调整类加载机制来优化程序性能
Traceclassunloading 追踪未使用的类,并卸载这些类,可以通过对未使用的类进行卸载,释放其所占用的内存资源,提高程序运行效率
tieredcomilation 分层编译 这种机制会根据java应用程序的执行状况进行优化,提高程序运行效率
mysql explain分析sql 都有哪些字段
select_type 查询语句执行的查询操作类 型
table 表名
rows 预计扫描的行数
type 查询所用的访问类型
key 实际查询用到的索引
key_len 所用到的索引长度
eq_ref 唯一性索引扫描
ref 非唯一性索引扫描
为什么sql语句不要过多的join
我认为主要有两个方面原因每个join操作,都需要对两个或多个表进行连接操作,这个操作可能会耗费大量的计算资源,join过多会导致sql的执行性能下降从而去影响整个系统的性能
可读性和维护性的问题,join操作会使sql语句变得复杂,难以理解和维护,特别是当join操作涉及到多个表的时候,sql语句的复杂度会呈现指数的增长,给代码的可读性和可维护性带来挑战
敏感数据怎么加解密和传输
安全方面
对称加密:通信双方共享同一个密钥
非对称加密:通过公钥和私钥两种密钥分别进行加密和解密
对于客户端和服务端的传输,可以采用非对称加密的方式实现
首先,客户端用提前分配好的公钥对数据加密然后再把密文传输到服务器端,服务器端通过密钥去解密,常见的非对称加密算法有两种,RSA、DSA,除了加密算法以外,还需要通过安全的通信协议来进行传输,我选择采用https协议,最后我们还需要确保公钥和私钥存储的安全性,防止被第三方拿到密钥以后能够破解内容
mysql update是行锁还是表锁
即可以是行锁也可以是表锁,具体要看where后的条件
where条件包含了索引列,并且只更新一条数据,那么就会加行锁
where条件中不包含索引列这个时候会加表锁
根据查询范围不同,mysql也会选择不同粒度的锁来避免幻读问题
比如针对主键索引的for update 操作 ,mysql会增加一个next-key lock来锁定id=10索引所在的区间
针对于索引区间的查询或者修改,mysql会自动对索引加间隙锁,来解决幻读问题
limit分页优化
使用limit,如果说一个表中的数据量很大,此时全部查询严重影响性能,并且还可能内存溢出,使用limit来限制查询的条数,但是如果是limit 10000,9数据,对于mysql来说不管limit从第几页开始,都会从第一页进行扫描,也可以避免这种情况发生,我们可以给数据一个id每次自增,自增索引,那么想从第几页开始时就能直接找到了,提高了查询效率