java面试题

redis

redis使用场景?

string、list(队列)、hash(hmset)、set(统计网站访问ip)、zset(top10)
缓存、服务无状态化、锁(redison)
及时性、数据一致性要求不高的数据、访问量大更新频率低的

redis单线程还是多线程?

无论什么版本,工作线程只有一个。
6.X版本出现了IO多线程(redis性能瓶颈在网络请求、所以使用多线程处理io 如:用户空间内、内核空间以及网卡的输入输出,单线程处理数据的计算)

遇到过缓存穿透吗?

当key不存在时,直接查db
解决:
1.value为null的key也放入缓存,设置一个过期时间
2.使用布隆过滤器

遇到过缓存击穿吗?

对一个热点key,非常热,key过期后会有大量请求直接落到db
解决:1.查缓存没有
2.1获取到锁:查db
2.2未获取到锁:sleep一会,回到步骤1
3.更新db到缓存
4.解锁
sleep是blocking状态,不会抢占cpu时间,做好线程池管理就行了

如何避免缓存雪崩?

当key过期时间一样时 所有的key统一过期
解决:过期时间使用随机值

缓存回收策略?

1.后台在轮询的时候,分段删除过期key
2.请求的时候判断已过期的
3.内存空间不足的情况下
4.lru ttl random lfu

如何进行缓存预热?

提前把数据存入redis,你知道哪些是热数据吗?
不知道哪些是热数据情况下,结合缓存击穿策略来回答

数据库与缓存不一致?

1.canal+binlog+rocketmq顺序消费+重试+时间版本号

redis主从不一致问题?

1.redis默认弱一致的,异步同步
2.锁不能用主从,可以用单实例、分片集群 ==> redisson
3.wait 2 0同步复制完返回,不推荐

redis持久化原理

RDB AOF(默认1秒fsync一个pageCache)
开启AOF是可以通过执行日志得到全部内存数据的方式
aof文件体积会变大、重复无效命令,重写所有的kv生成命令到aof
4.X版本,重写不再生成kv命令(性能原因),改为把rdb文件放到aof文件的头部,再追加日志

redis扛不住了,万级流量达到DB上

回答缓存穿透

为什么使用setnX?

原子性的,不存在则完成创建

分布式锁?

lua脚本单线程+ set NX EX命令 不存在则设置 +过期时间
NX EX要在同一个原子内执行避免死锁
redisson 分布式锁,读写锁、countdownLatch 、 semaphore等
如果未设置过期时间、线程未结束可以自动续期、默认30秒

redis存储

1.redis实例哈希槽slots ,有利于数据迁移
2.一致性hash算法,有利于负载防止hash倾斜,且添加移除节点只有影响下一个node节点的查询
https://zhuanlan.zhihu.com/p/179266232


jvm模型?

在这里插入图片描述

— 线程独享区—

  • 每个线程都有自己的栈,栈中的数据都是以栈帧(一个方法)的格式存在。
  • 在这个线程上正在执行的每一个方法都各自对应一个栈帧
  • 栈帧是一个内存区块,是一个数据集维系着方法执行过程中的各种数据信息

程序计数器

  • 是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

本地方法栈

(Native MethodStacks):

  • 与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。

— 共享区—

方法区

存放class文件、常量

存放共享对象、大对象
默认新生代空间的分配:Eden : Fron : To = 8 : 1 : 1
新生带,默认15Minor GC ->老年代 Full GC
* 垃圾回收算法
根搜索算法、标记清除(易产生磁盘碎片)、复制算法、标记整理算法(被引用对象左端移动)
对于新生代内存的回收(Minor GC)主要采用复制算法。而对于老年代的回收(Major GC),大多采用标记-整理算法。
CMS收集器在Minor GC时会暂停所有的应用线程,并以多线程的方式进行垃圾回收
* 垃圾收集器
CMS才要采用多线程标记清除算法、后会产生大量的内存碎片,当有不足以提供整块连续的空间给新对象/晋升为老年代对象时又会触发FullGC。且在1.9后将其废除
G1从整体上来看是基于‘标记-整理’算法实现,从局部(相关的两块Region)上来看是基于‘复制’算法实现,这两种算法都不会产生内存空间碎片。
可以并行回收各个region空间,不停止应用线程
并行:两个cpu分别执行两个任务
并发:两个cpu执行3+任务

执行引擎

解释执行字节码指令、优化热点字节码为指令、垃圾回收

  • 解释器
  • JIT即时编译
  • GC

类加载器

一、类加载流程

  • 加载–>连接(验证–>准备–>解析)–>初始化。
  • 1.加载
    这个过程主要是通过类的全限定名,例如 java.lang.String 这样带上包路径的类名,获取到字节码文件;然后将这个字节码文件代表的静态存储结构(可简单理解为对象创建的模板)存在方法区,并在堆中生成一个代表此类的 Class 类型的对象,作为访问方法区中“模板”的入口,往后创建对象的时候就按照这个模板创建。举个例子,有时候通过反射创建对象,像当初学 JDBC 时会通过 Class.getName(“com.mysql.jdbc.Driver.class”).newInstance() 创建对象,通过 Class 和相应的全限定类名获取到方法区中的“模板”然后创建对象。
    在这里插入图片描述
  • 2、验证
    验证过程主要确保被加载的类的正确性。首先要先验证文件格式是否规范,如果只是通过 .class 后缀来辨别,那随便把后缀名改一下就可以跑程序了,那岂不是很容易出事。
  • 3、准备与初始化
    这个阶段主要是给类变量(静态变量)分配方法区的内存并初始化类对象,放入方法区

二、类加载器分类

在这里插入图片描述
启动类加载器是由C/C++写的,主要负责加载 jre\lib 目录下的类;扩展类加载器主要负责加载 jre\lib\ext 目录下的类;而应用程序类加载器主要负责加载我们自己编写的类;当然还能自己写类加载器,即自定义加载器。程序主要由前面三个类加载器相互配合加载的。

三、类加载时机

创建类的实例,也就是new一个对象
访问某个类或接口的静态变量,或者对该静态变量赋值
调用类的静态方法
反射(Class.forName(“com.lyj.load”))
初始化一个类的子类(会首先初始化子类的父类)
JVM启动时标明的启动类,即文件名和类名相同的那个类

jvm 对象内存分配

栈上分配-> tlab分配->eden区分配->老年代
  栈上分配:
	-XX:+DoEscapeAnalysis 是开启逃逸分析 默认就是打开的
	对象的作用域都不会逃逸出方法外,将对象分配在方法栈中
	好处: 方法执行完后销毁,不需要垃圾回收器介入,从而提高系统的性能。
	局限性: 栈空间小,对于大对象无法实现栈上分配。
	基础:栈上分配依赖于逃逸分析和标量替换。
 tlab分配:thread local buffer
 对象的作用域都不会逃逸当前线程,将对象分配在线程独享区域

mysql

ACID

原子性:undo log,历史版本数据回滚
一致性
隔离性:锁+mvcc(多版本并发控制,undlog记录版本线性表+readView)
持久性: redo log

undo log?
数据库每条记录都有三个隐藏字段,隐藏主键(当没有主键时)、最新事务id、回滚的undolog记录id(当前记录最新的undolog日志中的记录)、当update、delete操作时,会先将当前记录复制到undolog日志中,修改主表当前记录回滚id,如果失败则回滚当前记录
readview?
trx_ids: 当前活跃事务集合 1,2,3
up_trx_id 1 当前活跃事务最新值
low_trx_id 4 下一个活跃事务
data_trx_id: 被select记录的最新trx_id
creator_trx_id 当前事务id
creator_trx_id = data_trx_id 当前记录可见
if data_trx_id>= low_trx_id 表示当前readview被创建后记录被修改,当前记录在快照中不可见,去unlog中取其他版本,继续比较
if data_trx_id< up_trx_id 表明生产当前readview时,当前的数据以及被提交,所以可见
if data_trx_id in trx_ids true: 当前版本不可见,false:当前版本可见

读已提交:每次select * from的时候会创建一个当前获取事务视图表,判断当前记录对应的trxId是否在视图表内,在表示当前记录还未提交,取当前记录前一条undolog版本,重复判断
可重复度: 同一个事务第一次select * from的时候创建一个当前当前视图表,判断当前记录是否在视图表内,在表示当前记录还未提交,取当前记录前一条undolog版本,重复判断,直到找到不在当前redview中的记录

隔离级别

读未提交:不加锁,事务A能读取到其他事务未提交的数据,直接读取主表数据,易脏读
读已提交:oracle默认,事务A只能读取其他事务已提交的数据,同一个事物不可重复读
可重复读:mysql默认,事物A重复读取相同记录得到的结果相同,即使其他事务已提交,可重复读只对update有效,add无效所以会产生幻读

sql类型优化

数据类型:
varchar:变长类型、适合存储长度不固定的列
char: 定长:适合存储长度固定,检索效率高

explain

在这里插入图片描述
sql执行顺序根据id 倒序执行,如果id相同,之上而下执行
select_type属性下有好几种类型:

SIMPLLE:简单查询,该查询不包含 UNION 或子查询
PRIMARY:如果查询包含UNION 或子查询,则最外层的查询被标识为PRIMARY
UNION:表示此查询是 UNION 中的第二个或者随后的查询
DEPENDENT:UNION 满足 UNION 中的第二个或者随后的查询,其次取决于外面的查询
UNION RESULT:UNION 的结果
SUBQUERY:子查询中的第一个select语句(该子查询不在from子句中)
DEPENDENT SUBQUERY:子查询中的 第一个 select,同时取决于外面的查询
DERIVED:包含在from子句中子查询(也称为派生表)
UNCACHEABLE SUBQUERY:满足是子查询中的第一个 select 语句,同时意味着 select 中的某些特性阻止结果被缓存于一个 Item_cache 中
UNCACHEABLE UNION:满足此查询是 UNION 中的第二个或者随后的查询,同时意味着 select 中的某些特性阻止结果被缓存于一个 Item_cache 中
类型有点多啊,我加粗的是最常见的,起码要看得懂加粗的部分。

type
该列称为关联类型或者访问类型,它指明了MySQL决定如何查找表中符合条件的行,同时是我们判断查询是否高效的重要依据。
以下为常见的取值

ALL:全表扫描,这个类型是性能最差的查询之一。通常来说,我们的查询不应该出现 ALL 类型,因为这样的查询,在数据量最大的情况下,对数据库的性能是巨大的灾难。
index:全索引扫描,和 ALL 类型类似,只不过 ALL 类型是全表扫描,而 index 类型是扫描全部的索引,主要优点是避免了排序,但是开销仍然非常大。如果在 Extra 列看到 Using index,说明正在使用覆盖索引,只扫描索引的数据,它比按索引次序全表扫描的开销要少很多。
range:范围扫描,就是一个有限制的索引扫描,它开始于索引里的某一点,返回匹配这个值域的行。这个类型通常出现在 =、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN、IN() 的操作中,key 列显示使用了哪个索引,当 type 为该值时,则输出的 ref 列为 NULL,并且 key_len 列是此次查询中使用到的索引最长的那个。
ref:一种索引访问,也称索引查找,它返回所有匹配某个单个值的行。此类型通常出现在多表的 join 查询, 针对于非唯一或非主键索引, 或者是使用了最左前缀规则索引的查询。
eq_ref:使用这种索引查找,最多只返回一条符合条件的记录。在使用唯一性索引或主键查找时会出现该值,非常高效。
const、system:该表至多有一个匹配行,在查询开始时读取,或者该表是系统表,只有一行匹配。其中 const 用于在和 primary key 或 unique 索引中有固定值比较的情形。
NULL:在执行阶段不需要访问表。

索引优化

myisam(数据索引分开存放)、innodb(数据索引在同一个文件) :索引: b+tree
innodb 主键索引(聚族索引): 叶子节点存放data
innodb 普通索引:叶子节点存放主键,查询需要回表
为什么非叶子节点不存放数据?
防止数据查找时读取磁盘块文件过大,浪费内存
在这里插入图片描述
sql优化
Sql的分类
DDL:create drop alter;表结构更改
DML:insert delete update;表记录数据
DQL select 查询
DCL :commit rollback;事务流程控制

create DATABASE databaseName 创建库
drop DATABASE databaseName 删除库 表和数据不能恢复
drop table if exists tablename1 ,tbalename2… 删除表
navicat给列指定外键时要先给这个列创建索引才能创建外键,删除外键时要先删除索引再删除外键 否则报错

数据类型 unisigned 无符号
整数
tinyint 1个字节 -128到127/0到255
int 4个字节 -21亿 到21亿/0到42亿
bigint 8个字节

int(5)  
5表示显示5位数字宽度 与数据类型取值范围无关
如果插入数据小于5位由空格填充 大于5位只要值<int最大值也可以插入而且能够显示出来
如果不指定宽度则默认宽度为数据类型的最大宽度 如tinyint默认tinyint(4) int默认int(11)..其中一位是符号\
因此根据实际需要设置字段宽度 有利于查询效率节省空间

浮点型和定点型
float 单精度 4个字节
duoble 双精度 8字节
decimal(m,n) 定点型 m其范围为1~65 M 的默认值是10 m+2个字节 精度要求高的可以用
当数值在其取值范围之内,小数位多了,则直接截断小数位。
若数值在其取值范围之外,则用最大(小)值对其填充
float(m,n) m表示总宽度 n表示小数宽度

日期
year YYYY
date YYYY-MM-DD
time HH:MM:SS
datetime YYYY-MM-DD HH:MM:SS
timestamp YYYY-MM-DD HH:MM:SS

函数
数学函数
ABS(-32) =32
floor(1.1) =1 返回不大于x的最大整数
ceiling(1.1) =2 返回不小于x的最小整数
ROUND(1.5)=2 四舍五入
±*%/…

字符串函数
length('string')=6             返回字符串长度
concat('my','s','ql') =mysql   字符串拼接
INSERT(‘whtas', 2, 3, ‘is')=wiss 替换下标范围
REPLACE('www', 'w', 'W')=WWW    替换指定字符串
instr('foobarbar', 'bar')=4    获取字符串位置
	locate('bar', 'foobarbar')=4:    获取字符串位置
LEFT('foobarbar', 5)=fooba:   从左边截取n个长度
RIGHT('foobarbar', 4)=rbar:	  从右边截取n个长度
TRIM(' bar ')=bar             删除前后空格
	LTRIM(' barbar')=barbar
	RTRIM(‘barbar ’)=barbar
REVERSE('abc')=cba			  反转


日期和时间函数 
dayofweek(date):星期索引(1=星期天,2=星期一, …7=星期六)
dayofmonth(date):返回date的月份中的日期,在1到31范围内。 
dayofyear(date):返回date在一年中的日数, 在1到366范围内。 

year(date):返回date的年份,范围在1000到9999
month(date):返回date的月份,范围1到12。 、
hour(time)返回time的小时,范围是0到23
minute(time):返回time的分钟,范围是0到59
second(time):返回time的秒数,范围是0到59

DATE_ADD(date,INTERVAL expr type) ,进行日期增加的操作,可以精确到秒 type类型可以是秒以上类型
DATE_SUB(date,INTERVAL expr type) ,进行日期减少的操作,可以精确到秒
CURDATE()  YYYY-MM-DD
CURTIME()   HH:MM:SS
NOW()		YYYY-MM-DD HH:MM:SS

流程控制函数
SELECT CASE 11 WHEN 1 THEN 'one'
	WHEN 2 THEN 'two' ELSE 'more' END
IF(1>2,2,3);

加密函数
PASSWORD(str)
MD5(str)
ENCODE(str,pswd_str)函数可以使用字符串pswd_str来加密字符串str。加密的结果是一个二进制数,必须使用BLOB类型的字段来保存它
DECODE(crypt_str,pswd_str)函数可以使用字符串pswd_str来为crypt_str解密
INET_ATON(IP)函数可以将IP地址转换为数字表示;INET_NTOA(n)函数可以将数字n转换成IP的形式。其中,INET_ATON(IP)函数中IP值需要加上引号。这两个函数互为反函数。

聚合函数
AVG([distinct] expr)	求平均值
COUNT({*|[distinct] } expr) 	统计行的数量
MAX([distinct] expr)  求最大值
MIN([distinct] expr) 	求最小值
SUM([distinct] expr) 	求累加和
group_concat(一组中的某一列所有值)

select [聚合函数] 字段名 from 表名
    [where 查询条件]
    [group by 字段名]
    [having 过滤条件]

合并查询
	UNION  ALL  不去重合并
		SELECT * FROM student 
		UNION ALL
		SELECT *FROM student;
	UNION  去重合并

连接查询 
	内连接  取满足条件的数据
	SELECT * FROM student JOIN course ON student.sID = course.gID;
	SELECT * FROM student,student_info WHERE student.sID=student_info.sID;
	左连接  左面全部列出
	SELECT * FROM student LEFT JOIN course ON student.sID = course.gID
	右连接 右边全部列出
	SELECT * FROM student RIGHT JOIN course ON student.sID = course.gID;
	
	MySQL的子查询  ANY、SOME、ALL、IN、EXISTS  (要建立临死表效率低)
	SELECT * FROM student WHERE sID > ANY(SELECT gID FROM course);	

存储过程
create procedure 存储过程名(参数) 用call 存储过程名 返回值定义在参数里
create function 存储函数名(参数) 可以有返回值 用select 存储函数名 from tablename 其实就是自定义函数

select * from mysql.proc where db= 'dbname';  查看dbname中的存储过程和自定义函数
SHOW CREATE [function|procedure] dbname.proName ;   查看名为proName的储存过程函数的详细信息 包含sql 

mysql优化
1表的设计合理化 三范式
2mysql索引 普通索引 主键索引 唯一索引unique 全文索引
3分表技术 水平垂直
5存储过程
8定时清理不需要的数据
9sql语句优化

三范式
字段具有原子性 不可再分解 (自然而然遵循了)
表中的记录是唯一的 不能出现完全相同的一条记录 通常设计一个没有业务的主键实现
对字段的冗余性约束 要求字段没有冗余
但是没有冗余的设计未必是最好的 有时为了提高运行效率 就必须反三范式增加冗余字段

sql语句本身优化
如何从一个大项目中快速定位查询速度慢的sql(慢查询定位)
列出mysql状态信息
show statue [session|global] 默认为session
like
‘uptime’ 查看mysql运行了多久
‘com_select’ 查看当前回话一共进行了多少次查询 加global从mysql开启算起
‘com_insert’
‘com_delete’
‘com_update’
‘connections’ 连接数
‘slow_queries’ 显示慢查询次数
默认情况下mysql认为10秒是慢查询
*修改mysql的慢查询时间
show VARIABLES like ‘long_query_time’
set long_query_time =1 设置为1秒 重启后重新设置
如何把慢查询的sql语句记录到日志中去?
在默认的情况下mysql不会记录慢查询,需要在启动mysql的时候 指定记录慢查询
my.ini配置slow_query_log=1 重启mysql
show variables like ‘%slow_query_log%’; 查看是否开启和log日志位置默认在data中
此时超过1秒的sql语句就会被记录到慢查询日志中
优化
相同的查询mysql会把结果缓存起来 下次查询就快了
四种索引
1主键索引 primary key 主键索引用上主键上 不可为null
4唯一索引 unique 字段可不重复但是可以有多个null
2普通索引 Normal 先创建表再创建普通索引
3全文索引 fulltext 大文本索引 只能对myisam生效
5复合索引 索引名字相同 作用在多列上 where中左边列在条件中才使用索引
创建索引
create index 索引名 索引类型 t1(id)
查询索引
desc t1 缺点不能显示索引名
show index from t1;

为什么常见索引后查询速度就会变快?
在不创建索引时select做全表扫描
索引算法btree二叉树算法:见图片文件
缩小查询对比次数 dql变快
但是对dml变慢 磁盘占用

索引的错误使用方法?
like “%text%”
分析sql: EXPLAIN select * from aaa where name LIKE “%萨德%” 查看是否使用索引
详解看图片

什么时候不会使用索引?
like查询 %在前面 不会使用索引
如果前面非要使用% 只能使用全文索引—>sphinx方式查询
or 中所有的字段都必须建立索引 复合索引后面的字段存在or中也不行 不然不会使用索引
尽量避免使用or
'‘或者"" 如果字段是字符串 查询必须用’'或者""包起来否者不使用索引
有一种情况 如果全表扫描比使用索引还快则不使用索引
在那些列上适合添加索引?
在较为频繁作为查询条件的字段应该创建索引
唯一性太差的字段不适合创建索引 比如性别
更新非常频繁的字段不适合创建索引
不会出现在where子句中字段不应该创建索引

如何查询索引使用情况
show status like “handler_read%”
handler_read_key 值越高越好 使用到索引的次数
handler_read_rnd_key 越低越好 未使用到索引次数

存储引擎选择?
myisam 如果表对事务要求不高
innodb 对事务要求高 比如订单 账户 表
Memory 基于内存的 数据变化频繁 不需要入库
myisam和innodb区别?
myisam innodb
1 事务安全 否 是
2查询和添加速度 高 低
3支持全文索引 是 否
4锁机制 表 行
5外键 否 是

myisam表做删除数据 磁盘空间不变
optimize table t1 进行清理

表的分割
水平 海量数据肿么办?
逻辑分表 分表字段必须是主键 或 主键的一部分
key分表
partition by key(条件字段id) partitions 10;
hash分表
partition by hash(表达式/字段) partitions 数量;
range分表
根据 字段/表达式 是否满足某个范围条件进行分表设计
partition by range(year(pubdate))(
#小于1980年的为一个表…
partition hou70 values less than (1980),
partition hou80 values less than (1990),
partition hou90 values less than (2000),
partition hou00 values less than (2010)
)
list分表
根据 表达式/字段 的内容值是否在某个“列表”中进行分表设计。
partition by list(month(pubdate))(
partition spring values in (3,4,5),
partition summer values in (6,7,8),
partition autumn values in (9,10,11),
partition winter values in (12,1,2)
)
减少分表 在range/list领域会造成数据丢失
在key/hash领域不会造成数据丢失,

         物理分表       自己写逻辑
  
垂直分割  某个字段数据量很大 又不是特别重要关注的内容 就可以单独建一个表装这个字段	

写sql语句技巧?
group by 分组查询 分组后 默认会对分组结果排序 加上 order by null 就可以防止排序
尽量使用连接查询代替子查询 因为使用join mysql不会在内存中创建临时表

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。 

2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: 
	select id from t where num is null 
	可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: 
	select id from t where num=0 
3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。 

4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如: 
	select id from t where num=10 or num=20 
	可以这样查询: 
	select id from t where num=10 
	union all 
	select id from t where num=20 
	

	
6.下面的查询也将导致全表扫描: 
	select id from t where name like '%abc%' 
	若要提高效率,可以考虑全文检索。

8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: 
	select id from t where num/2=100 
	应改为: 
	select id from t where num=100*2 

9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: 
	select id from t where substring(name,1,3)='abc'--name以abc开头的id 
	应改为: 
	select id from t where name like 'abc%' 

10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 

11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。 

13.很多时候用 exists 代替 in 是一个好的选择: 
	select num from a where num in(select num from b) 
	用下面的语句替换: 
	select num from a where exists(select 1 from b where num=a.num) 
		
17.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

18.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。 

总结
	判断是否为null 	索引无效
	!=、or、in、 not in、like '%abc%' 			exists 代替 in
	不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算
	连接查询代替子查询

.数据库事务的四个特性及含义?
ACID,原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)。
原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
隔离性:隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行 相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请 求,使得在同一时间仅有一个请求用于同一数据。
持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚

drop,delete与truncate的区别
drop直接删掉表 truncate删除表中数据,再插入时自增长id又从1开始 delete删除表中数据,可以加where字句。
delete语句为DML,这个操作会被放到 rollback segment中,事务提交后才生效。
truncate、drop是DLL,操作立即生效,原数据不放到 rollback segment中,不能回滚

varchar和char 的区别:
char 表示定长,长度固定,varchar表示变长,即长度可变
如char(10),表示存储的是10个字符,无论你插入的是多少,都是10个,如果少于10个,则用空格填满。
而varchar(10),小于10个的话,则插入多少个字符就存多少个。
以上所插入的字符串超出它们的长度时,视情况来处理,如果是严格模式,则会拒绝插入并提示错误信息,如果是宽松模式,则会截取然后插入
存储的容量不同
对 char 来说,最多能存放的字符个数 255,和编码无关。
而 varchar 呢,最多能存放 65532 个字符。

int(n)中n的涵义?
INT(1) 和 INT(10)本身没有区别,但是加上(n)值后和zerofill,宽度不够前面0填充。
create table test1(id int(3) zerofill); 如12会保存为012 1234保存为1234

Innodb是行锁,那什么时候会产生行锁,什么情况下会变成表锁?
答:一般情况下,innodb只对指定的行进行锁定,其他进程还是可以对表中的其他行进行操作的,因此,这时候innodb加的就是行锁;
但是,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”。

Explain select * from emp where ename=“zrlcHd”
会产生如下信息:
select_type:表示查询的类型。
table:输出结果集的表
type:表示表的连接类型
possible_keys:表示查询时,可能使用的索引
key:表示实际使用的索引
key_len:索引字段的长度
rows:扫描出的行数(估算的行数)
Extra:执行情况的描述和说明
优化mysql配置

IO

1.阻塞Io,用户线程socket.read()时,如果没有数据线程就一直处于blokc状态等数据就绪
2.非阻塞IO socket.read(),用户线程可以写一个while true,一直做socket.read,缺点:cpu占用高
3.多路复用IO模型,一个线程管理多个socket:
Java NIO 实际上就是多路复用 IO,会有一个线程不断去轮询多个socket的状态(socket.read),只有当socket真正有读写事件时,才真
正调用实际的IO读写操作。通过selector.select()去查询每个通道是否有到达事件,如果没有事件,则一直阻塞在那里
缺点:一旦事件响应体很大,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询
4.信号驱动 IO 模型
当用户线程发起一个 IO 请求操作,会给对应的 socket 注册一个信号函数,然后用户线程会继续执行,
当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用 IO 读写操作来进行实际的 IO 请求操作
5.异步IO模型,read数据由用户线程同步读取,转为由内核异步读取,read结束后内核会给用户线程发送一个信号,告诉它 read 操作完成了

zookeeper选举:

目前有 5 台服务器,每台服务器均没有数据,它们的编号分别是 1,2,3,4,5,按编号依次启动,它们
的选择举过程如下:
1. 服务器 1 启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反
馈信息,服务器 1 的状态一直属于 Looking。
2. 服务器 2 启动,给自己投票,同时与之前启动的服务器 1 交换结果,由于服务器 2 的编号
大所以服务器 2 胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是
LOOKING。
3. 服务器 3 启动,给自己投票,同时与之前启动的服务器 1,2 交换信息,由于服务器 3 的编
号最大所以服务器 3 胜出,此时投票数正好大于半数,所以服务器 3 成为领导者,服务器
1,2 成为小弟。
4. 服务器 4 启动,给自己投票,同时与之前启动的服务器 1,2,3 交换信息,尽管服务器 4 的
编号大,但之前服务器 3 已经胜出,所以服务器 4 只能成为小弟。
5. 服务器 5 启动,后面的逻辑同服务器 4 成为小弟

java基础面试

红黑树、深拷贝浅拷贝、juc包concurrentHashMap原理

设计模式:开闭原则:对扩展开放,对不变闭合
多态:接口 泛型:mybatis
众多设计模式都是基于继承、封装、多态实现
静态、动态代理proxy(面向接口、创建新的class文件反射创建对象,效率低)、cglib(被代理对象无需实现接口、字节码转化生产代理类的子类、被代理类不能是final修饰)

java基础面试

Kafka 弄丢了消息
1.解决办法也比较粗暴,我们手动关闭自动提交 offset,每次在真正消费完消息之后之后再自己手动提交 offset 。 但是,细心的朋友一定会发现,这样会带来消息被重新消费的问题。比如你刚刚消费完消息之后,还没提交 offset,结果自己挂掉了,那么这个消息理论上就会被消费两次。

2.我们知道 Kafka 为分区(Partition)引入了多副本(Replica)机制。分区(Partition)中的多个副本之间会有一个叫做 leader 的家伙,其他副本称为 follower。我们发送的消息会被发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进行同步。生产者和消费者只与 leader 副本交互。你可以理解为其他副本只是 leader 副本的拷贝,它们的存在只是为了保证消息存储的安全性。

试想一种情况:假如 leader 副本所在的 broker 突然挂掉,那么就要从 follower 副本重新选出一个 leader ,但是 leader 的数据还有一些没有被 follower 副本的同步的话,就会造成消息丢失。

3。.设置 acks = all

解决办法就是我们设置 acks = all。acks 是 Kafka 生产者(Producer) 很重要的一个参数。

acks 的默认值即为1,代表我们的消息被leader副本接收之后就算被成功发送。当我们配置 acks = all 代表则所有副本都要接收到该消息之后该消息才算真正成功被发送。

4.设置 replication.factor >= 3

为了保证 leader 副本能有 follower 副本能同步消息,我们一般会为 topic 设置 replication.factor >= 3。这样就可以保证每个 分区(partition) 至少有 3 个副本。虽然造成了数据冗余,但是带来了数据的安全性。

5。设置 min.insync.replicas > 1

一般情况下我们还需要设置 min.insync.replicas> 1 ,这样配置代表消息至少要被写入到 2 个副本才算是被成功发送。min.insync.replicas 的默认值为 1 ,在实际生产中应尽量避免默认值 1。

但是,为了保证整个 Kafka 服务的高可用性,你需要确保 replication.factor > min.insync.replicas 。为什么呢?设想一下假如两者相等的话,只要是有一个副本挂掉,整个分区就无法正常工作了。这明显违反高可用性!一般推荐设置成 replication.factor = min.insync.replicas + 1。

6.设置 unclean.leader.election.enable = false

Kafka 0.11.0.0版本开始 unclean.leader.election.enable 参数的默认值由原来的true 改为false

我们最开始也说了我们发送的消息会被发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进行同步。多个 follower 副本之间的消息同步情况不一样,当我们配置了 unclean.leader.election.enable = false 的话,当 leader 副本发生故障时就不会从 follower 副本中和 leader 同步程度达不到要求的副本中选择出 leader ,这样降低了消息丢失的可能性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值