Java面试技能
2020-12-22 15:06:59 0 举报
AI智能生成
21届毕业拿到7-8offer,包括华为、京东、美团。熟悉这些知识即可
作者其他创作
大纲/内容
1、mysql
分页查询
select * from database limit 0,5
where条件子句
is not null
-- 除了1000号学生之外的同学成绩
SELECT `StduentNo`,`StudentResult` FROM result
WHERE NOT StudentNo = 1000
SELECT `StduentNo`,`StudentResult` FROM result
WHERE NOT StudentNo = 1000
between and
-- 查询考试成绩在95分到100分之间
SELECT `StduentNo`,`StudentResult` FROM result
WHERE StudentResult >=95 AND StudentResult<=100
-- 模糊查询(区间)
SELECT `StduentNo`,`StudentResult` FROM result
WHERE StudentResult BETWEEN 95 AND 100
SELECT `StduentNo`,`StudentResult` FROM result
WHERE StudentResult >=95 AND StudentResult<=100
-- 模糊查询(区间)
SELECT `StduentNo`,`StudentResult` FROM result
WHERE StudentResult BETWEEN 95 AND 100
like
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '刘%';
-- 查询姓刘的同学,名字后只有一个字
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '刘_';
-- 查询姓刘的同学,名字后只有两个字
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '刘__';
-- 查询名字中间有嘉字的同学 %嘉%
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '%嘉%';
WHERE StudentName LIKE '刘%';
-- 查询姓刘的同学,名字后只有一个字
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '刘_';
-- 查询姓刘的同学,名字后只有两个字
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '刘__';
-- 查询名字中间有嘉字的同学 %嘉%
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentName LIKE '%嘉%';
in
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE StudentNo IN (1001,1002,1003);
-- 查询在北京的学生
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `Address` IN('安徽','河南洛阳');
WHERE StudentNo IN (1001,1002,1003);
-- 查询在北京的学生
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `Address` IN('安徽','河南洛阳');
join连表查询
-- JION(表) ON (判断的条件)连接查询
-- where 等值查询
SELECT studentNo,studentName,SubjectNo,StudentResult
FROM student AS s
INNER JOIN result AS r
WHERE s.studentNo=r.studentNo
--Right Join
SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM student AS s
RIGHT JOIN result AS r
ON s.studentNo = r.studentNo
--LEFT Join
SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM student AS s
LEFT JOIN result AS r
ON s.studentNo = r.studentNo
-- where 等值查询
SELECT studentNo,studentName,SubjectNo,StudentResult
FROM student AS s
INNER JOIN result AS r
WHERE s.studentNo=r.studentNo
--Right Join
SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM student AS s
RIGHT JOIN result AS r
ON s.studentNo = r.studentNo
--LEFT Join
SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM student AS s
LEFT JOIN result AS r
ON s.studentNo = r.studentNo
操作 描述
Inner join 如果表中至少有一个匹配,就返回行
left join 即使左表中没有匹配,也会从左表中返回所有的值
right jion 即使右表中没有匹配,也会从右表中返回所有的值
Inner join 如果表中至少有一个匹配,就返回行
left join 即使左表中没有匹配,也会从左表中返回所有的值
right jion 即使右表中没有匹配,也会从右表中返回所有的值
自链接
一张表拆成两张表
分页和排序
分页
缓解数据库的压力,给人更好的体验
limit
-- 分页,每页显示五条数据
-- 语法: limit 当前页,页面的大小
-- limit 0,5 1-5
-- limit 1,5 1-5
-- limit 6,5
-- 语法: limit 当前页,页面的大小
-- limit 0,5 1-5
-- limit 1,5 1-5
-- limit 6,5
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM student s
INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
INNER JOIN `subject` sub
ON r.`subjectNo`=sub.`subjectNo`
WHERE subjectName='数据结构-1'
ORDER BY StudentResult ASC
LIMIT 0,5
-- 第一页 limit 0,5
-- 第二页 limit 5,5
-- 第三页 limit 10,5
-- 第N页 limit 5*(n-1),5
FROM student s
INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
INNER JOIN `subject` sub
ON r.`subjectNo`=sub.`subjectNo`
WHERE subjectName='数据结构-1'
ORDER BY StudentResult ASC
LIMIT 0,5
-- 第一页 limit 0,5
-- 第二页 limit 5,5
-- 第三页 limit 10,5
-- 第N页 limit 5*(n-1),5
语法 limit(查询起始下标,pagesize)
排序
order by
asc : 升序
desc : 降序
-- 排序: 升序ASC 降序 DESC
SELECT xx
FROM xx
JOIN xx
WHERE xx
ORDER BY xx
ASC || DESC
SELECT xx
FROM xx
JOIN xx
WHERE xx
ORDER BY xx
ASC || DESC
子查询
-- 方式二:使用子查询(由里及外)
SELECT `StudentNo`,r.`SubjectName`,`StudentResult`
FROM `result`
WHERE StudentNo=(
SELECT SubjectNo FROM `subject`
WHERE SubjectName = '数据库结构-1'
)
ORDER BY StudentResult DESC
SELECT `StudentNo`,r.`SubjectName`,`StudentResult`
FROM `result`
WHERE StudentNo=(
SELECT SubjectNo FROM `subject`
WHERE SubjectName = '数据库结构-1'
)
ORDER BY StudentResult DESC
-- 在这个基础上 增加一个科目 ,高等数学-2
SELECT DISTINCT s.`StudentNo`,`StudentName`
FROM student s
INNER JOIN result r
ON r.StudentNo = s.StudentNo
WHERE StudentResult>=80 AND `SubjectNo`=(
SELECT Subject FROM `subject`
WHERE SubjectName='高等数学-2'
)
-- 查询课程为 高等数学-2 且分数不小于80分的同学的学号和姓名
SELECT s.`StudentNo`,`StudentName`
FROM student s
INNER JOIN result r
ON s.StudentNo = r.StudentNo
INNER JOIN `subject` sub
ON r.`SubjectName`='高等数学-2'
WHERE `SubjectaName`='高等数学-2' AND StudentResult >=80
-- 再改造 (由里即外)
SELECT `StudentNo`,`StudentName` FROM student
WHERE StudentNo IN(
SELECT StudentNo result WHERE StudentResult >80 AND SubjectNo =(
SELECT SubjectNo FROM `subject` WHERE `SubjectaName`='高等数学-2'
)
)
SELECT DISTINCT s.`StudentNo`,`StudentName`
FROM student s
INNER JOIN result r
ON r.StudentNo = s.StudentNo
WHERE StudentResult>=80 AND `SubjectNo`=(
SELECT Subject FROM `subject`
WHERE SubjectName='高等数学-2'
)
-- 查询课程为 高等数学-2 且分数不小于80分的同学的学号和姓名
SELECT s.`StudentNo`,`StudentName`
FROM student s
INNER JOIN result r
ON s.StudentNo = r.StudentNo
INNER JOIN `subject` sub
ON r.`SubjectName`='高等数学-2'
WHERE `SubjectaName`='高等数学-2' AND StudentResult >=80
-- 再改造 (由里即外)
SELECT `StudentNo`,`StudentName` FROM student
WHERE StudentNo IN(
SELECT StudentNo result WHERE StudentResult >80 AND SubjectNo =(
SELECT SubjectNo FROM `subject` WHERE `SubjectaName`='高等数学-2'
)
)
分组
group by
-- 查询不同课程的平均分,最高分,最低分,平均分大于80
-- 核心:(根据不同的课程分组)
SELECT `SubjectName`,AVG(StudentResult),MAX(StudentResult)
FROM result r
INNER JOIN `Subject` sub
ON r.SubjectNo=sub.SubjectNo
GROUP BY r.SubjectNo -- 通过什么字段来分组
HAVING AVG(StudentResult)>80
-- 核心:(根据不同的课程分组)
SELECT `SubjectName`,AVG(StudentResult),MAX(StudentResult)
FROM result r
INNER JOIN `Subject` sub
ON r.SubjectNo=sub.SubjectNo
GROUP BY r.SubjectNo -- 通过什么字段来分组
HAVING AVG(StudentResult)>80
mysql函数
数学运算
SELECT ABS(-8) -- 绝对值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 返回0-1随机数
SELECT SIGN(-10) -- 判断一个数的符号 0-0 负数返回-1 正数返回1
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 返回0-1随机数
SELECT SIGN(-10) -- 判断一个数的符号 0-0 负数返回-1 正数返回1
字符串函数
SELECT CHAR_LENGTH('2323232') -- 返回字符串长度
SELECT CONCAT('我','233') -- 拼接字符串
SELECT INSERT('java',1,2,'cccc') -- 从某个位置开始替换某个长度
SELECT UPPER('abc')
SELECT LOWER('ABC')
SELECT REPLACE('坚持很大可能成功','坚持','努力')
SELECT CONCAT('我','233') -- 拼接字符串
SELECT INSERT('java',1,2,'cccc') -- 从某个位置开始替换某个长度
SELECT UPPER('abc')
SELECT LOWER('ABC')
SELECT REPLACE('坚持很大可能成功','坚持','努力')
-- 查询姓 周 的同学 ,改成邹
SELECT REPLACE(studentname,'周','邹') FROM student
WHERE studentname LIKE '周%'
SELECT REPLACE(studentname,'周','邹') FROM student
WHERE studentname LIKE '周%'
-- 时间跟日期函数(记住)
SELECT CURRENT_DATE() -- 获取当前日期
SELECT CURDATE() -- 获取当前日期
SELECT NOW() -- 获取当前日期
SELECT LOCATIME() -- 本地时间
SELECT SYSDATE() -- 系统时间
SELECT CURRENT_DATE() -- 获取当前日期
SELECT CURDATE() -- 获取当前日期
SELECT NOW() -- 获取当前日期
SELECT LOCATIME() -- 本地时间
SELECT SYSDATE() -- 系统时间
-- 系统
SELECT SYSTEM_USER()
SELECT USER()
SELECT VERSION()
SELECT SYSTEM_USER()
SELECT USER()
SELECT VERSION()
聚合函数(常用)
函数名称 描述
COUNT() 计数
SUM() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值
COUNT() 计数
SUM() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值
数据库加密
5.3 数据库级别MD5加密(拓展)
什么是MD5
主要增强算法复杂度不可逆性。
MD5不可逆,具体的MD5是一样的
MD5破解原理,背后有一个字典,MD5加密后的值,加密前的值
CREATE TABLE `testmd5`(
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=UTF8
-- 明文密码
INSERT INTO testmd5 VALUES(1,'张三','123456'),(2,'李四','123456'),(3,'王五','123456')
-- 加密
UPDATE testmd5 SET pwd=MD5(pwd) WHERE id =1
UPDATE testmd5 SET pwd=MD5(pwd) WHERE id !=1 -- 加密全部
-- 插入时加密
INSERT INTO testmd5 VALUES(4,'小明',MD5('123456'))
INSERT INTO testmd5 VALUES(5,'红',MD5('123456'))
-- 如何校验,将用户传递过来的密码,进行MD5加密,然后对比加密后的值
SELECT * FROM testmd5 WHERE `name`='红' AND pwd=MD5('123456')
什么是MD5
主要增强算法复杂度不可逆性。
MD5不可逆,具体的MD5是一样的
MD5破解原理,背后有一个字典,MD5加密后的值,加密前的值
CREATE TABLE `testmd5`(
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=UTF8
-- 明文密码
INSERT INTO testmd5 VALUES(1,'张三','123456'),(2,'李四','123456'),(3,'王五','123456')
-- 加密
UPDATE testmd5 SET pwd=MD5(pwd) WHERE id =1
UPDATE testmd5 SET pwd=MD5(pwd) WHERE id !=1 -- 加密全部
-- 插入时加密
INSERT INTO testmd5 VALUES(4,'小明',MD5('123456'))
INSERT INTO testmd5 VALUES(5,'红',MD5('123456'))
-- 如何校验,将用户传递过来的密码,进行MD5加密,然后对比加密后的值
SELECT * FROM testmd5 WHERE `name`='红' AND pwd=MD5('123456')
事务
要么都成功,要么都失败
事务的原则
ACID
原子性
Atomicity: 要么都成功,要么都失败
一致性
Consistency: 事务前后的完整性要保持一致,200以后变成80+120
持久性
Durability:事务一旦提交,不可逆转,被永久持续到数据库中
隔离性
I :事务产生多并发情况下,互不干扰。
隔离性会产生很多问题
脏读: 一个事务读取了另外一个事务未提交的数据
不可重复读: 在一个事务内,多次读取同一行的数据时,读取到的结果不相同
幻读:一个事务内,读取到了,别的事务插入的数据,导致结果不一样,多了一行
-- mysql 自动开启事务提交
SET autocommit=0 -- 关闭
SET autocommit=1 -- 开启(默认的)
-- 手动处理事务
SET autocommit =0 -- 关闭自动提交
-- 事务开启
START TRANSACTION -- 标记一个事务的开始,从这个之后的SQP都在同一个事务内
INSERT XX
INSERT XX
-- 提交 : 持久化(成功)
COMMIT
-- 回滚: 回到原来的样子(失败)
ROLLBACK
-- 事务结束
SET autocommit = 1 -- 开启自动提交
-- 了解
SAVEPOINT 保存点名称 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点 -- 删除保存点
SET autocommit=0 -- 关闭
SET autocommit=1 -- 开启(默认的)
-- 手动处理事务
SET autocommit =0 -- 关闭自动提交
-- 事务开启
START TRANSACTION -- 标记一个事务的开始,从这个之后的SQP都在同一个事务内
INSERT XX
INSERT XX
-- 提交 : 持久化(成功)
COMMIT
-- 回滚: 回到原来的样子(失败)
ROLLBACK
-- 事务结束
SET autocommit = 1 -- 开启自动提交
-- 了解
SAVEPOINT 保存点名称 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点 -- 删除保存点
实例
模拟场景
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
USE shop
CREATE TABLE `account`(
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO account(`name`,`money`)
VALUES('A',2000),('B',10000)
-- 模拟转账:事务
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION -- 开启事务(一组事务)
UPDATE account SET money = money-500 WHERE `name` = 'A' -- A 转账给B
UPDATE account SET money = money+500 WHERE `name` = 'B' -- B 收到钱
COMMIT ; -- 提交事务
ROLLBACK ; -- 回滚
SET autocommit=1 -- 恢复默认值
索引
主键索引只能有一个,唯一索引有多个
索引分类
1.主键索引
primary key : 唯一的标识,只能有一列作为主键,主键不可重复
2.唯一索引
unique key :
避免重复的列出现,唯一索引可以重复,多个列都可以标识唯一索引
3.常规索引
KEY/INDEX :
默认的,index,key关键字来设置
4.全文索引
fulltext
在特点的数据库引擎下才有,MyISAM
快速定位数据
快速定位数据
5.测试索引
索引的使用
-- 1.在创建表的时候给字段增加索引
-- 2.创建完毕后,增加索引
-- 1.在创建表的时候给字段增加索引
-- 2.创建完毕后,增加索引
-- 显示所有的索引信息
SHOW INDEX FROM 表
-- 增加一个索引
ALTER TABLE 表 ADD FULLTEXT INDEX 索引名(字段名)
-- EXPLAIN 分析sql执行状况
EXPLAIN SELECT * FROM student -- 非全文索引
SHOW INDEX FROM 表
-- 增加一个索引
ALTER TABLE 表 ADD FULLTEXT INDEX 索引名(字段名)
-- EXPLAIN 分析sql执行状况
EXPLAIN SELECT * FROM student -- 非全文索引
索引在小数据的时候,用处不大,但是在大数据的时候,区别十分明显
索引原则
索引不是越多越好
不要对经常变动的数据加索引
小数据量的表不需要加索引
索引一般加在常用来查询的字段上
索引不是越多越好
不要对经常变动的数据加索引
小数据量的表不需要加索引
索引一般加在常用来查询的字段上
索引的数据结构
Hash 类型的索引
Btree: 默认innodb 的数据结构
阅读: http://blog.codinglabs.org/articles/theory-of-mysql-index.html
规范数据库设计
当数据库比较复杂的时候,我们就需要设计了
糟糕的数据库设计:
数据冗余,浪费空间
数据库插入和删除都会麻烦,异常【屏蔽使用物理外键】
程序的性能差
良好的数据库设计:
节省内存空间
保证数据库的完整性
方便我们开发系统
软件开发中,关于数据库的设计
分析需求:分析业务和需要处理的数据库的需求
概要设计:设计关系图 E-R图
设计数据库的步骤(个人博客)
收集信息,分析需求
用户表(用户登录注销,用户的个人信息,写博客,创建分类)
分类表(文章分类,谁创建的)
文章表(文章的信息)
友链表(友链信息)
自定义表(系统信息,某个关键的字,或者某些主字段)
说说表(发表心情…id ,content ,time)
标识实体(把需求落地到每个字段)
标识实体之间的关系
写博客 user–>blog
创建分类 user–>category
关注 user–>user
友链–>links
评论 user–>user
糟糕的数据库设计:
数据冗余,浪费空间
数据库插入和删除都会麻烦,异常【屏蔽使用物理外键】
程序的性能差
良好的数据库设计:
节省内存空间
保证数据库的完整性
方便我们开发系统
软件开发中,关于数据库的设计
分析需求:分析业务和需要处理的数据库的需求
概要设计:设计关系图 E-R图
设计数据库的步骤(个人博客)
收集信息,分析需求
用户表(用户登录注销,用户的个人信息,写博客,创建分类)
分类表(文章分类,谁创建的)
文章表(文章的信息)
友链表(友链信息)
自定义表(系统信息,某个关键的字,或者某些主字段)
说说表(发表心情…id ,content ,time)
标识实体(把需求落地到每个字段)
标识实体之间的关系
写博客 user–>blog
创建分类 user–>category
关注 user–>user
友链–>links
评论 user–>user
三大范式
第一范式
1NF:原子性:保证每一列不可再分
第二范式
2NF : 前提:满足第一范式
每张表只描述一件事情
每张表只描述一件事情
第三范式
3NF:前提:满足第一范式和第二范式
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
(规范数据库的设计)
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
(规范数据库的设计)
为什么需要数据规范化?
信息重复
更新异常
插入异常
删除异常
无法正常显示异常
删除异常
丢失有效的信息
信息重复
更新异常
插入异常
删除异常
无法正常显示异常
删除异常
丢失有效的信息
规范性和性能的问题
关联查询的表,不得超过三张表
考虑商业化的需求和目标(成本和用户体验) 数据库的性能更加重要
再规范性能的问题的时候,需要适当的考虑一下,规范性
故意给某些表加一些冗余的字段(从多表,变成单表)
故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
关联查询的表,不得超过三张表
考虑商业化的需求和目标(成本和用户体验) 数据库的性能更加重要
再规范性能的问题的时候,需要适当的考虑一下,规范性
故意给某些表加一些冗余的字段(从多表,变成单表)
故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
JDBC(重点)
数据库驱动
驱动:声卡,显卡,数据库
JDBC
SUN 公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,JDBC
这些规范的实现由具体的厂商去做
对于开发人员来说,我们只需要掌握JDBC的接口操作即可
这些规范的实现由具体的厂商去做
对于开发人员来说,我们只需要掌握JDBC的接口操作即可
java.sql
javax.sql
还需要导入数据库驱动包
javax.sql
还需要导入数据库驱动包
锁
性能
乐观
悲观
操作类型
读锁(悲观,共享),同一数据允许多个操作同时进行读,
写锁(悲观,排他),写操作没有完成之前,不允许其他写锁和读锁
颗粒度
表锁
锁整张表,开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲
突的概率最高,并发度最低;
突的概率最高,并发度最低;
加锁:lock table 表名称 read(write),表名称2 read(write);
查看锁:show open tables;
解锁:unlock tables;
读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。
行锁
每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁
冲突的概率最低,并发度最高。
冲突的概率最低,并发度最高。
支持事务
原子性(Atomicity) :事务是一个原子操作单元,其对数据的修改,要么全都执
行,要么全都不执行。
一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态。这意
味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束
时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并
发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是
不可见的,反之亦然。
持久性(Durable) :事务完成之后,它对于数据的修改是永久性的,即使出现系
统故障也能够保持。
行,要么全都不执行。
一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态。这意
味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束
时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并
发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是
不可见的,反之亦然。
持久性(Durable) :事务完成之后,它对于数据的修改是永久性的,即使出现系
统故障也能够保持。
并发事务处理带来的问题
更新丢失
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每
个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其
他事务所做的更新
个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其
他事务所做的更新
脏读
事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基
础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求
础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求
不可重读
事务A读取到了事务B已经提交的修改数据,不符合隔离性
幻读
事务A读取到了事务B提交的新增数据,不符合隔离性
事务隔离级别
读未提交
可能出现
脏读
脏读
可能出现不可重复读
可能出现幻读
读已提交
不能出现脏读
可能出现不可重复读
可能出现幻读
可重复读
不能出现脏读
不能出现不可重复读
可能出现幻读
可串行化
都不能出现
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔
离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。
同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用
对“不可重复读"和“幻读”并不敏感,可能更关心数据并发访问的能力。
常看当前数据库的事务隔离级别: show variables like 'tx_isolation';
设置事务隔离级别:set tx_isolation='REPEATABLE-READ';
离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。
同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用
对“不可重复读"和“幻读”并不敏感,可能更关心数据并发访问的能力。
常看当前数据库的事务隔离级别: show variables like 'tx_isolation';
设置事务隔离级别:set tx_isolation='REPEATABLE-READ';
优化
尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
合理设计索引,尽量缩小锁的范围
尽可能减少检索条件范围,避免间隙锁
尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql
尽量放在事务最后执行
尽可能低级别事务隔离
合理设计索引,尽量缩小锁的范围
尽可能减少检索条件范围,避免间隙锁
尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql
尽量放在事务最后执行
尽可能低级别事务隔离
分库分表
垂直拆分
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的数据
库上面,这样也就将数据或者说压力分担到不同的库上面
库上面,这样也就将数据或者说压力分担到不同的库上面
优点
1拆分后业务清晰,拆分规则明确
2. 系统之间整合或扩展容易。
3. 数据维护简单。
缺点
1. 部分业务表无法join,只能通过接口方式解决,提高了系统复杂度。
2. 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高。
3. 事务处理复杂。
水平拆分
垂直拆分后遇到单机瓶颈,可以使用水平拆分。相对于垂直拆分的区别是:垂直拆分是把不同的表拆到不同的数据
库中,而水平拆分是把同一个表拆到不同的数据库中。
相对于垂直拆分,水平拆分不是将表的数据做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中
包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中 的某些行切分到
一个数据库,而另外的某些行又切分到其他的数据库中,主要有分表,分库两种模式
库中,而水平拆分是把同一个表拆到不同的数据库中。
相对于垂直拆分,水平拆分不是将表的数据做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中
包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中 的某些行切分到
一个数据库,而另外的某些行又切分到其他的数据库中,主要有分表,分库两种模式
优点
1. 不存在单库大数据,高并发的性能瓶颈。
2. 对应用透明,应用端改造较少。
3. 按照合理拆分规则拆分,join操作基本避免跨库。
4. 提高了系统的稳定性跟负载能力。
缺点
1. 拆分规则难以抽象。
2. 分片事务一致性难以解决。
3. 数据多次扩展难度跟维护量极大。
4. 跨库join性能较差。
存储引擎
MYISAM
数据文件和索引文件分开(非聚集)frm+MYD+MYI
不支持事务,不支持行级锁
innodb
表数据文件就是按B+tree组织的索引结构文件(聚集),frm(表结构)+ibd
支持事务
包含了完整的数据记录
主键索引包含数据,非主键索引不包含数据,只包含主键值,(基于数据一致性与节省空间考虑)
支持事务(TRANSACTION)
支持行级锁
支持行级锁
优化
MySQL支持两种方式的排序filesort和index,Using index是指MySQL扫描索引本身完成排序。index
效率高,filesort效率低。
效率高,filesort效率低。
、order by满足两种情况会使用Using index。
1) order by语句使用索引最左前列。
2) 使用where子句与order by子句条件列组合满足索引最左前列。
1) order by语句使用索引最左前列。
2) 使用where子句与order by子句条件列组合满足索引最左前列。
3、尽量在索引列上完成排序,遵循索引建立(索引创建的顺序)时的最左前缀法则。
、如果order by的条件不在索引列上,就会产生Using filesort。
单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;
双路排序:是首先根据相应的条件取出相应的排序字段和可以直接定位行
数据的行 ID,然后在 sort buffer 中进行排序,排序完后需要再次取回其它需要的字段
数据的行 ID,然后在 sort buffer 中进行排序,排序完后需要再次取回其它需要的字段
能用覆盖索引尽量用覆盖索引
group by与order by很类似,其实质是先排序后分组,遵照索引创建顺序的最左前缀法则。对于group
by的优化如果不需要排序的可以加上order by null禁止排序。注意,where高于having,能写在where中
的限定条件就不要去having限定了
by的优化如果不需要排序的可以加上order by null禁止排序。注意,where高于having,能写在where中
的限定条件就不要去having限定了
2、java基础
入门
特点
简单
面向对象
跨平台
安全
多线程
八大基本类型
整形
byte
short
int
long
浮点型
float
double
字符型
char
布尔型
boolean
作用域和权限
private:只能本类使用
默认(default ):本类和子类可以使用
protected:本类,子类,同包
public:都可以使用
运算符
==和equals
算数运算符
关系运算符
位运算符
逻辑运算符
赋值运算符
条件运算符(三元运算符)
循环结构
do..while
while
for
普通for循环
增强for循环
break
continue
条件语句
if
if..else
if..else if..else
switch case
数组
定义
一维数组
数组类型[] 数组名 = [数据1,数据2]
数组类型[] 数组名 = new 数组类型[数组大小]
多维数组
数组类型[][] 数组名 = new 数组类型[数组大小][数组大小]
优缺点
优点
查询效率比较高
可以容纳基本类型
缺点
数组的长度是固定的,不能改变
数组存储的类型必须是设置的存储类型
删除和插入比较慢,每次删除和插入会从新排序
方法(函数)
定义
优点
使程序变得简短而清晰
有利于程序维护
可以提高程序开发的效率
提高了代码的重用性
排序
插入排序
直接插入排序
希尔排序
选择排序
简单选择排序
堆排序
交换排序
冒泡排序
快速排序
归并排序
基数排序
数据结构
队列
栈
链表
单链
双链
循环链表
块级链表
树
二叉树
面向对象
类装载器
static修饰
方法
变量
代码块
重载(Overload)
封装
好处
良好的封装能够减少耦合
类内部的结构可以自由修改
可以对成员变量进行更精确的控制
隐藏信息,实现细节
例子
继承
特性
子类拥有父类非 private 的属性、方法
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展
子类可以用自己的方式实现父类的方法
Java 的继承是单继承,但是可以多重继承
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)
关键字
extends(继承)
implements(实现)
构造方法
注意
方法名和类名要一致
无返回值修饰符
不能被直接调用
由 new 关键字自动调用
可以使用return关键字(结束方法体)
不能用static修饰
可以重载
不可以被继承
重写(Override)
规则
多态
重载式多态
重写式多态
向上转型
向下转行
抽象
定义
如果一个类包含抽象方法,那么该类必须是抽象类。
任何子类必须重写父类的抽象方法,或者声明自身为抽象类
规定
抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象
抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能
构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法
抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类
接口(Interface)
接口与类
相同点
一个接口可以有多个方法
接口文件保存在 .java 结尾的文件中,文件名使用接口名
接口的字节码文件保存在 .class 结尾的文件中
接口相应的字节码文件必须在与包名称相匹配的目录结构中
区别
接口不能用于实例化对象
接口没有构造方法
接口中所有的方法必须是抽象方法
接口不能包含成员变量,除了 static 和 final 变量
接口不是被类继承了,而是要被类实现
接口支持多继承
接口和抽象类的区别
抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行
抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的
接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法
一个类只能继承一个抽象类,而一个类却可以实现多个接口
特性
接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字
接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字
接口中的方法都是公有的
final修饰
类
方法
变量
jvm
类装载器:将java文件加载成.class文件
字节码执行引擎
内存模型
线程共用
堆
方法区(元空间)
线程独有
栈
栈帧
局部变量表
操作数栈
动态链接
方法出口
程序计数器
本地方法栈
api
java.lang
exception
异常处理
try..catch
finally
throws
throw
thread
构造方法
Thread()
Thread(Runnable target)
Thread(Runnable target, String name)
Thread(String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, String name)
方法
sleep(long millis)
start()
toString()
getName()
getPriority()
interrupted()
java.util
date
构造方法
Date()
Date(long date)
方法
after(Date when)
before(Date when)
getTime()
setTime(long time)
Collection
子类
List
ArrayList
构造器
public ArrayList()
public ArrayList(ICollection)
public ArrayList(int)
LinkedList
构造器
LinkedList()
LinkedList(Collection<? extends E> c)
Set
HashSet
构造器
HashSet()
HashSet(Collection<? extends E> c)
HashSet(int initialCapacity)
HashSet(int initialCapacity, float loadFactor)
TreeSet
特点
使用方式
自然排序(Comparable)
比较器排序(Comparator)
区别
构造器
TreeSet()
TreeSet(Collection<? extends E> c)
TreeSet(Comparator<? super E> comparator)
TreeSet(SortedSet<E> s)
Map
Map接口和Collection接口的不同
功能
添加功能
删除功能
判断功能
获取功能
长度功能
子类
HashMap
构造器
HashMap()
HashMap(int capacity)
HashMap(int capacity, float loadFactor)
HashMap(Map<? extends K, ? extends V> map)
TreeMap
构造器
TreeMap()
TreeMap(Map<? extends K, ? extends V> copyFrom)
TreeMap(Comparator<? super K> comparator)
TreeMap(SortedMap<K, ? extends V> copyFrom)
java.util.concurrent
java.io
类
File
构造器
File(File parent, String child)
File(String pathname)
File(String parent, String child)
File(URI uri)
方法
mkdir()
OutputStream
构造器
OutputStream()
方法
close()
flush()
write(byte[] b)
write(byte[] b, int off, int len)
write(int b)
InputStream
构造器
InputStream()
方法
close()
mark(int readlimit)
read()
read(byte[] b)
reset()
Writer
构造器
Writer()
Writer(Object lock)
方法
append(char c)
flush()
write(char[] cbuf)
write(int c)
close()
Reader
构造器
Reader()
Reader(Object lock)
方法
close()
mark(int readAheadLimit)
read()
read(char[] cbuf)
read(CharBuffer target)
ready()
reset()
接口
Serializable
java.math
java.nio
泛型
方法
例子
类
例子
类型通配符
内部类
成员内部类
局部内部类
匿名内部类
静态内部类
反射
用途
反射相关类
3、jvm
运行时数据区域
程序计数器PCR
1.较小的内存
2.当前线程执行的字节码行号指示器
3.字节码指示器:通过改变这个计数器的值来选取下一条需要执行的指令
4.线程私有
5.如果执行的是java方法,则记录的是字节码指令的地址,如果是Native方法,计数器值为空
6.不会内存溢出
java虚拟机栈
1.线程私有
2.生命周期和线程相同
3.每个方法创建栈帧
1.局部变量表
A.存放编译器可知的各种基本数据类型,对象引用
B.64位的long,dubbo占用两个Slot
C.所需的内存在编译器就确定
2.操作数栈
3.动态连接
4.返回地址
5.异常情况
A:线程请求的栈深度大于虚拟机允许的深度
B:栈拓展内存不够用,内存溢出
本地方法栈
1.线程私有
2.执行的是native方法
3.异常情况和虚拟机栈相同
Java 堆
1.jvm中内存最大的一块
2.线程共享
3.存放对象实例
4.垃圾回收的主要区域
5.新生代
1.Eden
2.From Survivor
3.To Survivor
6.老年代
7.多个线程私有的分配缓存区TLAB
8.物理上不连续的内存空间
9.异常:内存溢出
(永久代)方法区
1.线程共享
2.存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码
3.运行时常量池(存储编译器生成的字面量和符号引用)
直接内存
NIO中使用这块内存居多
非堆内存受总内存大小限制
对象的创建
1.new 指令创建对象
A:检查这个指令的参数能否在常量池中找到类的符号引用
B:检查这个符号引用是否已经被加载,解析,初始化过
C:没有的话先进行类加载过程
D:类加载完成后,分配内存
2.分配内存方式
A:指针碰撞
假设内存规整,指针一边是空闲空间一边是被分配空间,通过指针移动表示使用了多少内存
B:空闲列表
C:两种方式取决于垃圾收集器类型,带有压缩整理的垃圾收集器可以使用指针碰撞
D:并发情况下线程不安全
同步
按照线程划分在不同的空间TLAB
E:内存分配好的话将内存空间初始化为0,然后将hashCode,分代年龄等信息保存在对象头
3.对象的内存布局
A:对象头
第一部分存储hashCode,分代年龄,锁信息等数据(MarkWord)
第二部分类型指针(通过这个指针确定是哪个类的实例)
数组的话还存储数据的长度
B:实例数据
类的字段信息,包括父类的字段信息等
存储顺序受分配策略的影响:相同宽度的字段总是被分配到一起
父类中的字段信息在子类之前
C:对齐填充
虚拟机要求对象大小是8字节的整数倍
如果对象大小不是8字节的整数倍的话,需要通过占位符补全
4.对象的访问定位
句柄访问 详看对象访问句柄图 优点:对象移动reference不用修改,句柄池更新即可
直接指针访问 详细看对象指针图 优点:速度块
假设内粗不规整,占用内存后的对象会记录在一张列表上
内存分配策略
年轻代
对象主要分配在新生代的Eden区域
启动本地线程分配缓存的话,则优先在TLAB上分配
优先将对象分配在新生代上,Eden区域内存不够时发送Minor GC
老年代
大对象直接进入老年代
可以配置参数指定大于多大对象直接进入老年代,防止年轻代内存复制频繁
长期存活的对象进入老年代
1.虚拟机给对象添加年龄计数器
2.动态年龄判断
3.空间分配担保
常用的工具
jps 显示指定系统内所有的虚拟机进程
jstat 监视虚拟机各种运行状态的信息
jinfo 实时查看,调整虚拟机参数
jmap 生成堆转储快照
jhat 虚拟机堆转储快照分析工具
jstack 生成虚拟机当前时刻的线程快照
类文件结构
class文件是一组以8字节为基础单位的二进制流
由无符号数和表构成
实战
Java 堆溢出
虚拟机栈溢出
本地方法栈溢出
方法区溢出
常量池溢出
本机直接内存溢出
垃圾回收
对象回收的判断
1.引用计数算法
给对象添加一个引用计数器,
每一个地方引用它,计数器值就加1,
对象引用失效的时候,计数器就减1.
计数器值为0的时候,此对象为垃圾
优点:判定效率高
缺点:对象间循环依赖,此算法
无法正确判断是否为垃圾对象
主流虚拟机没有这种算法
2.可达性分析算法
GC Roots"的对象作为起始点
从这些节点开始向下搜索,
搜索所走过的路径称为引用链(Reference Chain)
当一个对象到GC Roots没有任何引用链相连时,
则证明此对象是不可达的
作为GC Roots对象
栈帧中本地变量表中引用的对象
方法区类静态属性引用的对象
方法区中常量引用的对象
方法栈JNI引用的对象
强引用 Object obj = new Object
软引用 有用非必须
弱引用 非必须
虚引用 最弱的引用
不可达对象是否死亡判断
第一次标记 是否执行finalize
第二次标记 finalize方法是否可以和Gc root重新建立关系
枚举根节点
安全点
安全区域
方法区回收
垃圾回收效率较低
回收内容
废弃常量
无用类
1.该类所有实例都被回收
2.加载该类的ClassLoader被回收
3.该类对应的class对象没有被引用,无法在任何地方反射访问该类方法
垃圾收集算法
标记清除算法(最基础算法)
1.首先标记出所有需要回收的对象
2.在标记完成后统一回收掉所有被标记的对象
缺点1:标记和清除过程的效率都不高
缺点2:产生大量不连续的内存碎片
复制算法
1.内存按容量划分为大小相等的两块
2.一块内存用完了,将存活着的对象复制到另外一块
3.将都是垃圾对象的那块清空内存
缺点1:在对象存活率较高时,复制操作次数多,效率降低
缺点2:內存缩小了一半;需要額外空间做分配担保(老年代)
标记整理算法
1.标记步骤和标记清除算法相同
2.标记完后垃圾对象移动到一端,然后在清理掉
分代收集算法
新生代
复制算法
老年代
标记-清理或者标记-整理
垃圾收集器
Serial(最基本的收集器)
单线程
垃圾收集的时候,暂停所有线程
优点简单高效,缺点停顿时间长
年轻代-复制算法,老年代-标记整理算法
ParNew收集器
Serial的多线程版本
Parallel Scavenge收集器
新生代收集器
复制算法
吞吐量较高
多线程
Serial Old收集器
Serial的老年代版本
Parallel Old收集器
Parallel的老年代版本
CMS收集器
回收停顿时间短
多线程
标记-清除
1.初始标记
2.并发标记
3.重新标记
4.并发清除
G1收集器
并行并发
分代收集
空间整合
可预测停顿
GC日志
GC日志最前面时间是虚拟机启动以来经过的秒数
【GC 【Full GC 垃圾收集的停顿类型
类加载机制
什么是类的加载机制
类加载的生命周期
加载
1.通过类的全限定名称获取此类的二进制流
2.将这个二进制字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.内存中生成一个java.lang.class对象,作为方法区这个类中各种数据的访问入口
4.可以从ZIP包,网络,动态代理,其他文件比如JSP,数据库等方式
5.加载和连接是交叉进行的
连接
验证
确保Class文件的字节流中包含的信息符合当前虚拟机要求
文件格式验证
元数据验证
字节码验证
符号引用验证
准备
为类变量分配内存并设置类变量初始值
解析
1.类或接口的解析
2.字段解析
3.类方法解析
4.接口方法解析
初始化
执行构造器 <clinit>
收集类中所有类变量的赋值动作和静态语句块中的合并语句
子类的clinit()执行之前,父类clinit()一定执行完成
<clinit>不是必须的,类或者接口中没有对类变量赋值,编译器就可以不生成这个方法
不会执行父接口的(),除非要使用父接口中定义的变量
多线程环境下可以正常加锁,同步,只有一个会去执行,其余挂起,如果有一个线程耗时,那么造成多个线程阻塞
使用
卸载
类加载器
双亲委派模型
启动类加载器(虚拟机中的一部分)
将虚拟机识别的类库加载到内存
其他的类加载器(独立于虚拟机外部)
扩展类加载器
应用程序类加载器
负责加载ClassPath上指定的类库
自定义类加载器
工作过程
虚拟机字节码执行引擎
运行时栈帧结构
局部变量表
操作数栈
动态连接
方法返回地址
分派
静态分派
4、juc
1、JUC是什么
java.util.concurrent在并发编程中使用的工具类
进程/线程回顾
进程、线程是什么
进程、线程的例子
线程状态
wait和sleep的区别
什么是并发?什么是并行
2、锁
synchronized
多线程编程模板
线程、操作。资源类
高内聚、低耦合
实现步骤
1、创建资源类
2、资源类里面创建同步方法、同步代码块
Lock
lock是什么?
Lock接口的实现
使用
与synchronized的区别
创建线程的方法
(实现Runnable)
(实现Runnable)
新建类实现runnable接口
lambda表达式
匿名内部类
3、Java8与Lambda表达式
lambda表达式?
是什么?
要求
写法
函数式接口
接口中也可以有实现方法
4、线程间通信
5、多线程锁
6、集合不安全
7、callable接口
0 条评论
下一页