Java面试整理(初级)

事务注解回滚:
结论一:对于@Transactional可以保证RuntimeException错误的回滚,如果想保证非RuntimeException错误的回滚,需要加上rollbackFor = Exception.class 参数;
结论二:try catch只是对异常是否可以被@Transactional 感知 到有影响。如果错误抛到切面可以感知到的地步,那就可以起作用。
结论三:由于REQUIRED属性,“两个事务”其实是一个事务,处理能力看报错时刻,是否添加了处理非RuntimeException的能力。

mybatis #,$
sql优化
索引
nigix
注册中心,配置中心,热更新
redis ,mangodb,mysql,存储结构 多级存储
1.8流式编程 stream
事务注解 针对特定异常进行回滚

$

工厂模式,策略模式
redis缓存雪崩 缓存穿透
MySQL优化 拆表了怎么查前五十
eureka
分布式的事务怎么管理
docker 数据挂载
lambda表达式,数组转数组,数组转map这些怎么转
jdk1.8新特性,有一个default关键字 我当时问到了
Spring如何开启事务,事务失效的原因
mysql的几种字段类型

还有除了nigix和事务注解,# $,1.8流式编程 stream,事务注解这几个常常问 其他的很多情况是看简历的

mybatis的#和$:
#占位符,是使用jdbc中的prepareStatement效率高没有sql注入的风险,#传入的参数在sql中显示为字符串(当成一个字符串),会自动对传入的数据加一个双引号
KaTeX parse error: Expected 'EOF', got '#' at position 197: … 大多数情况需要用#̲占位符,可以避免sql注入的风…占位符,例如:mybatis排序时使用order by 动态参数时需要注意,用$而不是#。

mysql存储结构:
https://www.cnblogs.com/yizhiamumu/p/16799990.html

sql优化:
https://blog.csdn.net/guoqi_666/article/details/122484535
1 避免使用select *
2 用union all代替union
3 小表驱动大表
4 批量操作
5 多用limit
6 in中值太多
7 增量查询
8 高效的分页
9 用连接查询代替子查询
10 join的表不宜过多
11 join时要注意
12 控制索引的数量
13 选择合理的字段类型
14 提升group by的效率
15 索引优化

redis:
https://blog.csdn.net/guorui_java/article/details/117194603
缓存雪崩,缓存穿透
缓存穿透:
1:大量请求根本不存在的key,大量请求达到了数据库,导致数据库的压力瞬间变大而卡死或者宕机
2:解决方案:
1:对空值进行缓存
类似于上面的例子,虽然数据库中没有id=2354的用户数据,但是在redis中对它进行缓存(key = 2354,value = null),
这样请求到达redis时候就会直接返回一个null的值给客户端,避免了大量无法访问的数据直接打在数据库上
2:使用布隆过滤器
使用bitMap作为布隆过滤器,将目前所有可以访问的资源通过简单的映射关系放入到布隆过滤器中(哈希计算),当一个请求来临的
时候先进行布隆过滤器的判断,如果有那么才进行放行,否则就直接拦截
3:网警
3:注意事项:
1:使用空值作为缓存的时候,key设置的过期时间不能太长,防止占用太多的redis资源
2:使用空值作为缓存只能防止黑客重复使用相同的id暴力攻击,但是如果黑客使用动态的无效id攻击就没有效果(需要配合网警)
3:使用布隆过滤器也是有哈希冲突的可能
缓存雪崩:
1:原因:redis中大量的key集体过期
2:举例:当redis中大量的key集体过期,可以理解为redis中的大部分数据都被清空了(失效了),那么这时候如果有
大量的并发请求来到,那么redis就无法进行有效的响应(命中率急剧下降),请求就都打到了数据库中,到时候
直接崩掉。
3:解决方案:
1:将失效时间分散开:使用自动生成随机数使得key的过期时间是随机的,防止集体过期
2:使用多级架构:使用nginx缓存+redis缓存+其他缓存,不同层使用不同层的缓存,可靠性更强
3:设置缓存标记:记录缓存数据是否过期,如果过期会触发通知另外线程在后台去更新实际的key
4:使用锁或者队列的方式:如果查不多就加上排他锁,其他请求只能进行等待
缓存击穿:
1:原因:redis中某个热点key过期,但是此时有大量的用户访问该过期key
2:举例:热搜等等
3:解决方案:
1:提前对热点数据进行设置
2:监控数据,适时调整
3:使用锁机制

Nginx:
https://blog.csdn.net/qq_58467694/article/details/125191080
1:什么是nginx?
Nginx是一个轻量级/高性能的反向代理web服务器,他实现非常高效的反向代理,负载均衡,可以处理2-3万并发连接数
官方检测能支持5w并发
2:为什么使用nginx?
1:跨平台,配置简单,反向代理,高并发连接
2:内置健康检查功能,如果有一个服务器宕机,会做一个健康检查,再发送的请求就不会发送到宕机的服务器了。重新将请求提交给其他节点上
3:支持GZIP压缩,稳定性高,接收用户请求是异步的
3:nginx怎么处理请求的?
nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的location,location就是实际地址
server{ # 第一个server区开始,表示一个独立的虚拟主机站点
listen 80; # 提供服务的端口,默认80
server_name locahost; # 提供服务的域名主机名
location / { # 第一个location区块开始
root html; # 站点的根目录,相当于nginx的安装目录
index index.html index.html; #默认的首页文件,多个用空格分开
}
}
4:什么是正向代理?什么是反向代理?
正向代理就是一个人发送一个请求直接就到达了目标的服务器
反向代理就是请求同意被nginx接收,nginx反向代理服务器接手之后,按照一定的规则分给了后端业务处理服务器进行处理了
正向代理服务器代理的是客户端,而反向代理服务器代理的是服务器端
使用反向代理服务器可以隐藏服务器的存在和特征。充当互联网云和web服务器之间的中间层

worker_processes  1;                					# worker进程的数量
events {                              					# 事件区块开始
    worker_connections  1024;            				# 每个worker进程支持的最大连接数
}                                    					# 事件区块结束
http {                               					# HTTP区块开始
    include       mime.types;            				# Nginx支持的媒体类型库文件
    default_type  application/octet-stream;     		# 默认的媒体类型x
    sendfile        on;       							# 开启高效传输模式
    keepalive_timeout  65;       						# 连接超时
    server {            								# 第一个Server区块开始,表示一个独立的虚拟主机站点
        listen       80;      							# 提供服务的端口,默认80
        server_name  localhost;       					# 提供服务的域名主机名
        location / {            						# 第一个location区块开始
            root   html;       						# 站点的根目录,相当于Nginx的安装目录
            index  index.html index.htm;      			# 默认的首页文件,多个用空格分开
        }          										# 第一个location区块结果
        error_page   500502503504  /50x.html;     		# 出现对应的http状态码时,使用50x.html回应客户
        location = /50x.html {          				# location区块开始,访问50x.html
            root   html;      							# 指定对应的站点目录为html
        }
    }  
    
    nginx开启:./nginx
    nginx重启:nginx -s reload
    nginx关闭:nginx -s stop

nginx负载均衡算法:
    1:轮询:每个请求按时间顺序逐一分配到不同的后端服务器
        upstream backserver{
            server 192.168.0.12; 
            server 192.168.0.13; 
        }
    2:权重:weight的值越大分配到的访问概率越高
        upstream backserver{
            server 192.168.0.12 weight = 2; 
            server 192.168.0.13 weight = 3; 
        }
    3:ip_hash(ip绑定):每个请求按访问IP的哈希结果分配,使来自同一个IP的访客固定访问一台后端服务器,并且可以有效解决动态网页存在的session共享问题
        upstream backserver{
            ip_hash;
            server 192.168.0.12 weight = 2; 
            server 192.168.0.13 weight = 3; 
        }
		

Nginx是如何实现高并发的?
    简单来讲,就是:异步,非阻塞,使用了epoll和大量的底层代码优化
    nginx采用一个master进程,多个worker进程的模式。
    1:master进程主要负责收集,分发请求。当一个请求过来时,master拉起一个worker进程负责处理这个请求。
    2:master进程也要负责监控worker的状态,保证高可靠性
    3:worker进程一般设置为跟cpu核心数一致。nginx的worker进程跟apache不一样。apche的进程在同一时间只能处理一个请求,所以它会开很多个进程,几百甚至几千个。而nginx的woker进程在同一时间可以处理额请求数只受内存限制,因此可以处理多个请求。
Nginx的四大功能是什么?
    正向代理:在客户端配置代理服务器,通过代理服务器进行互联网访问
    反向代理:我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,再返回给客户端
            此时反向代理服务器和目标服务器对外就是一个服务器,暴漏的是代理服务器地址,隐藏了真实服务器的IP地址
    负载均衡:单个服务器解决不了,我们增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中到单个服务器上的
            情况改为请求分发到多个服务器上,将负载分发到不同的服务器,也就是我们所说的负载均衡
    动静分离:为了加快网站的解析速度,可以把动态页面和静态页面由不用的服务器来解析,加快解析速度,降低原来单个服务器的压力

Nginx常用命令:
    启动    ./nginx
    停止    nginx -s stop  或 nginx -s quit
    重启    nginx -s reload 或 service nginx reload
    重新加载指定配置文件    nginx -c /usr/local/nginx/config/nginx.config
    查看    nginx 版本  nginx -v

Nginx报500,502,503,504有什么区别?
    500:Internal server error 内部服务错误,比如脚本错误,编程语言语法错误
    502:bad gateway错误 网管错误。比如服务器当前连接太多,相应太慢,页面素材太多,带宽慢
    503:service tempopraily unavaliable 服务不可用,web服务器不能处理HTTP请求
    504: Gateway timeout 网关超时,程序执行时间过长导致响应超时,例如程序需要执行20秒,而nginx最大响应等待时间为10秒,这样就会出现超时。

mysql的几种字段类型:
1:整数类型:
1:tinyint smallint mediumint int bigint
2:浮点数和定点数类型:
1:float double decimal(m,d), dec
3:日期/时间类型:
1:year time date datetime timstamp
4:字符串类型:
1:char varchar tinytext text mediumtext longtext enum set
5:二进制类型:
1:bit binary varbinary tinyblob blob mediumblob longblob

nginx热更新:
https://blog.csdn.net/wzj_110/article/details/112639382

分布式事务最经典的七中解决方案:
https://blog.csdn.net/m0_67322837/article/details/126287932

RocketMq:
https://blog.csdn.net/qq_42877546/article/details/125425061
https://blog.csdn.net/qq_22162093/article/details/123938296
https://blog.csdn.net/qq_21561501/article/details/105684989?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-105684989-blog-123938296.pc_relevant_landingrelevant&spm=1001.2101.3001.4242.2&utm_relevant_index=4

常用设计模式:
https://blog.csdn.net/jingbin_/article/details/53166913?spm=1001.2101.3001.6650.18&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-18-53166913-blog-126282151.pc_relevant_3mothn_strategy_and_data_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-18-53166913-blog-126282151.pc_relevant_3mothn_strategy_and_data_recovery&utm_relevant_index=19

如何正确打开spring事务:
https://blog.csdn.net/zzuhkp/article/details/118520027

eureka面试题:
https://blog.csdn.net/weixin_48227718/article/details/125620401

jdk8新特性:
https://blog.csdn.net/m0_63836794/article/details/122573854?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-122573854-blog-126338618.pc_relevant_aa2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-122573854-blog-126338618.pc_relevant_aa2&utm_relevant_index=3
1:接口中默认方法和静态方法
1:默认方法:java8允许接口中包含具体实现的方法体,该方法是默认方法,他需要使用default关键字修饰
2:静态方法:java8中允许接口定义静态方法,使用static关键字修饰
public integerface DefaultMethod{
default Integer addMethod(int a,int b){
sout(“我是默认方法”);
return a+b;
}

    static void test(){
        sout("我是静态方法");
    }
}

/**
* @author cds
* @title DefaultMethodDemoImpl
* @date 2023/3/4 8:43
* @description Lambda表达式是匿名函数,可以理解为一段可以用参数传递的代码(代码像数据一样传递)。Lambda表达式需要有函数式接口的支持
* 方法引用是对特殊Lambda表达式的一种简化写法,当Lambda体中只调用一个方法,此方法满足函数式接口规范,此时可以使用::方法引用
*/
public class DefaultMethodDemoImpl implements DefaultMethodDemo {


    @Override
    public void demo() {
        System.out.println("我是个demo");
    }

    @Override
    public Integer addMethod(int a, int b) {

        /**
        * 普通数据类型
        */
        //正向引用方法引用
        Stream.of(11, 13, 15, 10, 9).sorted(Integer::compareTo).forEach(System.out::println);
        //正向引用
        Stream.of(11, 13, 15, 10, 9).sorted(Comparator.naturalOrder()).forEach(System.out::println);
        //逆向排序
        Stream.of(11, 13, 15, 10, 9).sorted(Comparator.reverseOrder()).forEach(System.out::println);

        List<DeviceType> list = new ArrayList<>();

        /**
        * 对象数据类型:1:数据完好
        */
        Collections.sort(list, Comparator.comparing(DeviceType::getId));

        /**	
        *  2:数据缺失
        * 数据缺失的含义是对象本身为空或者待比较对象属性为空,如果不进行处理,上述排序会出现空指针异常
        * 最常见的处理方式是通过流式运算中filter方法,过滤掉空指针数据,然后按照上述策略排序
        */
        List<DeviceType> listDemo = list.stream().filter(e -> e.getDeviceTypeName() != null).collect(Collectors.toList());

        /**
        *  3:字符串处理
        *  字符串排序问题,在不修改数据类型的前提下完成期望的操作
        */
        //对集合按照id排序(正序排序)
        Collections.sort(list, Comparator.comparingLong(e -> new Long(e.getId())));
        //数据类型转换排序时,使用jdk内置的api并不流畅,推荐使用commons-collections包中的排序工具类
        Collections.sort(list, ComparatorUtils.reversedComparator(Comparator.comparingLong(e -> new Long(e.getId()))));

        /**
        * 二:排序器
        * 内置的排序器可以完成大多数场景的排序需求,当排序需求更加精细化时,适时引入第三方框架时比较号的选择
        */
//        1:单列排序
        //正序
        Comparator<DeviceType> comparing = Comparator.comparing(DeviceType::getDeviceTypeName);
        //逆序
        Comparator<DeviceType> reversed = Comparator.comparing(DeviceType::getDeviceTypeName).reversed();
//        2:多列排序
        //默认多列均是正序排序
        Comparator<DeviceType> deviceTypeComparator = Comparator.comparing(DeviceType::getDeviceTypeName).thenComparing(DeviceType::getId);
        //自定义正序逆序
        Comparator<DeviceType> deviceTypeComparator1 = Comparator.comparing(DeviceType::getDeviceTypeName, Comparator.naturalOrder()).thenComparing(DeviceType::getId, Comparator.reverseOrder());
        
        return 1 + 1;
    }
}
        /**
        * 二:排序器
        * 内置的排序器可以完成大多数场景的排序需求,当排序需求更加精细化时,适时引入第三方框架时比较号的选择
        */
//        1:单列排序
        //正序
        Comparator<DeviceType> comparing = Comparator.comparing(DeviceType::getDeviceTypeName);
        //逆序
        Comparator<DeviceType> reversed = Comparator.comparing(DeviceType::getDeviceTypeName).reversed();
//        2:多列排序
        //默认多列均是正序排序
        Comparator<DeviceType> deviceTypeComparator = Comparator.comparing(DeviceType::getDeviceTypeName).thenComparing(DeviceType::getId);
        //自定义正序逆序
        Comparator<DeviceType> deviceTypeComparator1 = Comparator.comparing(DeviceType::getDeviceTypeName, Comparator.naturalOrder()).thenComparing(DeviceType::getId, Comparator.reverseOrder());

        //3:映射(map)
        Optional<DeviceType> first = list.stream().filter(e -> e.getDeviceTypeName().equalsIgnoreCase("组件")).findFirst();
        if (first.isPresent()) {
            String deviceTypeName = first.get().getDeviceTypeName();
//            return deviceTypeName;
        }

        //4:排序(sorted)
        //传统的Collectors类中的排序支持List实现类中的一部分排序,使用stream排序,能够覆盖所有的list实现类
        //按照默认字典顺序排序
        list.stream().sorted();
        //按照工资大小排序
        Stream<DeviceType> sorted = list.stream().sorted((x, y) -> StringUtils.compare(x.getId(), y.getId()));

        //将集合转换成map
        Map<String, String> map = list.stream().collect(Collectors.toMap(DeviceType::getId, DeviceType::getDeviceTypeName));

        //将集合转换成Map<String,DeviceType>
        Map<String, DeviceType> typeMap = list.stream().collect(Collectors.toMap(DeviceType::getId, m -> m));

MinIo:
https://blog.csdn.net/u011174699/article/details/124903036?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-124903036-blog-124928960.pc_relevant_aa2&spm=1001.2101.3001.4242.2&utm_relevant_index=4

RabbitMq:
https://blog.csdn.net/qq_46147786/article/details/126623905

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值