前言
- 大家好,这里是IT学习日记,相信大家对今年IT的行情应该也有所了解了,从大厂到小厂,各种裁员消息。公司裁员我们无法决定,我们能做的就是不断提升自己,提前准备。
- 本系列文章主要分享了之前博主真实面试中遇到的一些问题,希望能够帮助准备就业或者跳槽的朋友。
JAVA基础知识
一: 高并发情况下如何保证全局唯一ID的生成
1、为何需要生成唯一ID
随着业务量逐渐复杂,数量不断增大,项目不断分解拆分为分布式,很多业务场景需要有唯一标识字段来标识对应的数据,如美团、淘宝生成的订单,此时,分布式的唯一ID必不可缺。
2、全局唯一ID必要要求
唯一性: 能够在分布式情况下唯一表示一个数据
趋势递增: 有序性可以有利于快速定位到数据,而且很多数据库底层索引是通过Btree实现,有序的数据能够保证写入的性能。
安全性: 生成全局唯一ID的规则不能过于简单,防止恶意破坏者根据已知ID推算出其他ID,用于恶意使用。
3、全局唯一ID系统生成可用性要求
高可用: 在高并发情况下,唯一ID生成的成功率要大于99%,保证可用。
高效率: 在高并发情况下,生成唯一ID的延迟不能太大。
4、生成全局唯一ID方式
1、UUID方式: 32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的36个字符,示例:110e8400-e29b-41d4-a716-446655440011。
2、基于Redis方式: 通过INCR或者INCRBY命令来实现,以为Redis执行时单线程,天然保证了原子性。
3、snowflake(雪花算法) :Twitter的分布式自增ID算法snowflake,Twitter的分布式自增ID算法snowflake,且生成的ID是根据时间有序的,SnowFlake 算法生成id的结果是一个64bit大小的整数, 为一个Long型(转换成字符串后长度最多19),分布式系统内不会产生ID碰撞(由datacenter和Iworkerld作区分)并且效率较高(图来源网络,侵删)
二: 为什么不推荐使用UUID作为数据表主键
1、Mysql官方建议主键字段长度越短越好,UUID生成的全局ID长度为36个字符,不符合这一推荐,官方描述如下:
代码语言:javascript复制All indexes other than the clustered index are known as secondary
indexes. In InnoDB, each record in a secondary index contains the
primary key columns for the row, as well as the columns specified for
the secondary index. InnoDB uses this primary key value to search for
the row in the clustered index.*** If the primary key is long, the
secondary indexes use more space, so it is advantageous to have a
short primary key
2、Mysql 中索引的底层是B 树实现,但是UUID生成的全局ID是无序的,这样就要求每次插入数据都需要对索引进行重新的排序,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面,大大降低了写入数据的效率。
3、InnoDB引擎使用聚集索引,数据记录本身被存于主索引(一颗B Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,这样查找时效率也更加高,因为范围查找是最常见的业务场景之一。
三: 创建类的有哪些方式
1、使用new关键创建
2、通过反射创建
3、通过反序列化创建
4、通过clone(克隆)方法创建
四: 如何看一个网络通不通
方式一: ping ip地址/域名
方式二: ssh ip地址 -p 端口号 -v
方式三: telnet ip地址 端口号
五: 网络通了进程也运行着 但是访问不到可能是什么原因
1、防火墙限制
2、端口未开放
3、主机被加入了黑名单
六: 从前后台描述下你如何将一个数据插入到数据库中
回答思路:
这种的题目主要是考察你是否对开发的流程掌握,可以直接使用创建账号案例来举例即可。
案例:
用创建账号为例子,前端将用户填写在表单的数据转换成json,然后通过ajax指定请求地址,发起请求,后端在control层接受前台传递的参数,转发到Service层,在Service做参数校验,不符合则直接返回错误提示,符合则将数据封装成对应的实体,传递到Dao层,Dao调用对应的持久层框架API,将数据存储到数据库中。
七: 你们的事务是放在那里,怎么使用
回答思路:
考官主要考察你实际项目中是否有接触过事务,使用事务之前是否了解事务的相关知识,所以,只需要往这两个方向回答就可以,最好可以举例一些特殊的情况,如使用声明式事务失效等
使用场景:
1、有多个对数据库操作的业务中
2、且这多个操作需要保证原子性,要么所有业务都成功,要么所有业务都失败。
使用方式:
1、声明式事务: 使用Transactional注解,特点,侵入性小,使用简单
2、编程式事务:
特点:
侵入性强,但是可用控制的颗粒度更小,适用的场景更多如多线程场景下
使用方式代码如下:
代码语言:javascript复制@Autowired
DataSourceTransactionManager dataSourceTransactionManager;
@Autowired
TransactionDefinition transactionDefinition;
//手动开启事务
transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
//手动提交事务
dataSourceTransactionManager.commit(transactionStatus);
//手动回滚
dataSourceTransactionManager.rollback(transactionStatus);
八: Transactional注解失效的场景有哪些
Transactional 可以作用在接口、类、类方法。
作用于类:当把@Transactional 注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息。
作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。
作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效
失效场景:
1、如果Transactional注解应用在非public 修饰的方法上,Transactional将会失效。
2、Transactional 注解属性 propagation 设置错误这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
3、rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。
4、同一个类中方法调用,导致@Transactional失效。因为Transactional是基于AOP实现的,它的功能实际上是生成的代理对象去实现,所以,同一个类中的方法调用,实际上默认是this,即当前类调用,不是生成的代理类调用,所以无效
5、手动使用了try...catch捕获异常,此时也不会生效
6、数据库引擎不支持事务。事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了。
7、类没有被 Spring 管理,此时即使方法添加了Transactional也无法生效
8、多数据源时,数据源没有配置事务管理器也不会生效。
Spring Boot本身并不管理事务,只是提供了 PlatformTransactionManager 接口来供持久层实现来达到事务的管理,Spring Boot 默认使用JDBC来控制事务。 如果是多数据源的话,需要对每个数据源配置事务管理器,步骤如下(图来源网络,侵删):
九: 集中式和分布式的特点
集中式:
就是一个项目就是一个独立的应用,这个项目中包含了各个子模块,比如,邮件功能、文件上传功能等等。最多也就是多部署几个服务器,前面挡上负载均衡来平衡系统负载。
缺点:不易拓展、更新一个功能就需要重新部署整个项目。 一个子模块出问题就可能影响整个系统的。
优点:对于开发、测试、运维会比较方便,不用考虑复杂的分布式环境。
分布式:
也就是 若干个 独立功能的计算机的组合,通常做法就是针对一个系统,将系统中的各个业务模块分离开来分别部署到不同的计算机上,来配合工作使系统正常运转的一种系统部署方式,如果某个业务模块负载较高那么就增 加服务器并挡上负载均衡来缓解压力,但多个服务器仍然是只提供一个业务模块的功能。 但是对于用户是感觉不到的。
缺点: 对于开发、测试、运维 要考虑复杂的分布式环境,比如分布式事务、分布式锁等。
优点: 项目的各功能模块独立分开,一个模块更新不影响其他模块。
十: 静态代码块、构造代码块和构造函数的区别
静态代码块:用于给类初始化,类加载时就会被加载执行,只加载一次。
构造代码块:用于给对象初始化的。只要建立对象该部分就会被执行,且优先于构造函数。
构造函数: 给对应对象初始化的,建立对象时,选择相应的构造函数初始化对象。
创建对象时,三者被加载执行顺序:静态代码块--->构造代码块--->构造函数
小结
不积跬步,无以至千里;不积小流,无以成江海。今天播种努力的种子,总会有一天发芽!