arraylist和linkedlist的区别
· 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
· 随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
· 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。
hashmap和hashtable的区别
· 存储:HashMap 允许 key 和 value 为 null,而 Hashtable 不允许。
· 线程安全:Hashtable 是线程安全的,而 HashMap 是非线程安全的。
· 推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。
接口和抽象类的区别
· 实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
· 构造函数:抽象类可以有构造函数;接口不能有。
· 实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
· 访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。
MySQL的连接方式
内连接 左连接 右连接
事务隔离级别
第一种隔离级别:Read uncommitted(读未提交)
如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据,该隔离级别可以通过“排他写锁”,但是不排斥读线程实现。这样就避免了更新丢失,却可能出现脏读,也就是说事务B读取到了事务A未提交的数据
解决了更新丢失,但还是可能会出现脏读
第二种隔离级别:Read committed(读提交)
如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据,该隔离级别避免了脏读,但是可能出现不可重复读。事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
解决了更新丢失和脏读问题
第三种隔离级别:Repeatable read(可重复读取)
可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写),这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务(包括了读写),这样避免了不可重复读和脏读,但是有时可能会出现幻读。(读取数据的事务)可以通过“共享读镜”和“排他写锁”实现。
解决了更新丢失、脏读、不可重复读、但是还会出现幻读
第四种隔离级别:Serializable(可序化)
提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读
MySQL的视图创建
CREATE VIEW <视图名> AS <SELECT语句>
SQL语句练习以及答案
create table class
(
classid int primary key,
classname varchar(20)
)
insert into class values(1,'G1T01');
insert into class values(2,'G1T02');
insert into class values(3,'G1T03');
insert into class values(4,'G1T04');
insert into class values(5,'G1T05');
insert into class values(6,'G1T06');
insert into class values(7,'G1T07');
create table student
(
studentid varchar(20) primary key,
studentname varchar(20),
studentage int,
studentsex char(10),
studentaddress varchar(50),
classid int references class(classid)
)
insert into student values('2010001','Jack',21,'男','湖北襄樊',1);
insert into student values('2010002','Scott',22,'男','湖北武汉',2);
insert into student values('2010003','Lucy',23,'女','湖北武汉',3);
insert into student values('2010004','Alan',19,'女','湖北襄樊',4);
insert into student values('2010005','Bill',20,'男','湖北襄樊',5);
insert into student values('2010006','Bob',21,'男','湖北宜昌',6);
insert into student values('2010007','Colin',22,'女','湖北襄樊',6);
insert into student values('2010008','Fred',19,'男','湖北宜昌',5);
insert into student values('2010009','Hunk',19,'男','湖北武汉',4);
insert into student values('2010010','Jim',18,'男','湖北襄樊',3);
create table computer
(
studentid varchar(20) references student(studentid),
score float
)
insert into computer values('2010001',90);
insert into computer values('2010002',80);
insert into computer values('2010003',70);
insert into computer values('2010004',60);
insert into computer values('2010005',75);
insert into computer values('2010006',85);
select * from class;
select * from computer;
select * from student;
--1查询出学生的编号,姓名,计算机成绩
select s.studentid,s.studentname,c.score from student s left join computer c on s.studentid=c.studentid;
--2查询参加过考试的学生信息
select * from student where studentid in(select studentid from computer);
select s.*,c.score from student s LEFT JOIN computer c on s.studentid=c.studentid where c.score is null;
--3查询出学生的编号、姓名、所在班级名称、计算机成绩
select s.studentid,s.studentname,c1.classname,c.score from student s left join computer c on s.studentid=c.studentid left join class c1 on s.classid=c1.classid;
--4查询出年龄大于19岁的学生编号、姓名、计算机成绩
select s.studentid,s.studentname,c.score from student s left join computer c on s.studentid=c.studentid where studentage >19;
--5查询出姓名中包含有c的学生编号、姓名、计算机成绩
select s.studentid,s.studentname,c.score from student s left join computer c on s.studentid=c.studentid where s.studentname like '%c%';
--6查询出计算机成绩大于80分的学生编号、姓名、班级名称
select s.studentid,s.studentname,c1.classname from student s left join computer c on s.studentid=c.studentid left join class c1 on s.classid=c1.classid where c.score >80;
select s.studentid,s.studentname,c.score from student s inner JOIN computer c on s.studentid=c.studentid where c.score >80
--7查询出所有学生的信息和计算机成绩信息
select * from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid ;
--8查询出每个班的学生的计算机成绩的平均分,最高分,最低分
select c1.classname 班级名称, avg(score) 平均分,max(score) 最高分,min(score) 最低分 from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid group by c1.classname;
select c1.classname, avg(IFNULL(c.score,0)),max(IFNULL(c.score,0)),MIN(IFNULL(c.score,0)) from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid GROUP BY c1.classname
--9查询显示出班级的计算机平均分大于80的班级名称、平均分信息,并按照平均分降序显示
1.select c1.classname 平均分大于80的班级, avg(score) 平均分 from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid group by c1.classname having avg(score)>80 order by avg(score) desc;
2.select * from (select c1.classname 平均分大于80的班级,avg(score) ss from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid group by c1.classname) aa where ss>80 order by ss desc;
select c1.classname, avg(IFNULL(c.score,0)) avg from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid GROUP BY c1.classname HAVING avg>=80 ORDER BY avg asc
--10查询出和Jim住在同一个地方的学生的基本信息
select *from student where studentaddress in(select studentaddress student where studentname='Jim');
select *from student where studentaddress =(select studentaddress student where studentname='Jim');
select s1.studentname,s2.studentname, s1.studentaddress,s2.studentaddress from student s1,student s2 where s1.studentaddress=s2.studentaddress and s1.studentname!=s2.studentnameand s1.studentname='jim'
select s2.studentname from student s1 INNER JOIN student s2 on s1.studentaddress=s2.studentaddress and s1.studentname='jim' and s1.studentname!=s2.studentname
--11查询出班级编号大于3的学生基本信息
select * from student s where s.classid >3;
--12查询出班级编号大于3的学生的计算机平均分信息
select avg(score) from student s left join computer c on s.studentid=c.studentid where s.classid>3;
--13查询出班级编号大于3的男生的学生信息
select * from student s where s.classid>3 and s.studentage='男';
--14查询男、女生的计算机平均成绩、最高分、最低分
select s.studentsex, avg(score) 平均分,max(score) 最高分,min(score) 最低分 from student s left join computer c on s.studentid=c.studentid group by s.studentsex='男'or'女';
select avg(c.score),max(c.score) ,min(c.score) from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid WHERE s.studentsex='男'
UNION
select avg(c.score),max(c.score) ,min(c.score) from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid WHERE s.studentsex='女'
--15将参加过考试的学生的年龄更改为20
update student s set s.studentage= 20 where s.studentid in (select studentid from computer);
update student set studentage= 20 where studentid in (select studentid from computer);
--16查询出每个班级的学生的平均分(查询的结果中包含平均分和班级名称)
select c1.classname 班级名称, avg(score) from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid group by c1.classname;
--17删除姓名包含“c”字符的学生计算机成绩
delete from computer where studentid in(select studentid from student where studentname like '%c%');
--18查询出G1T07班学生的编号、姓名、班级名称、计算机成绩
select s.studentid ,s.studentname,c1.classname,c.score from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid where c1.classname='G1T07';
--19查询出年龄在20-25之间的学生的编号、姓名、年龄、计算机成绩
select s.studentid,s.studentname,s.studentage,c.score from student s left join computer c on s.studentid=c.studentid where s.studentage between 20 and 25;
--20查询出成绩最高的学生的编号、姓名、计算机成绩、所在班级名称
select * from student where studentid=(select studentid from computer where score=(select max(score) from computer ))
select * from student where studentid in(select studentid from computer where score =(select max(score) from computer ))
/* 1. select s.studentid,s.studentname,max(score),c1.classname from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid ;
注释: error : Subquery returns more than 1 row 子查询的结果多于一行。
解决方法:在子查询的条件语句末尾加 limit 1 。 */
2.select s.studentid,s.studentname,c.score,c1.classname from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid where s.studentid=(select s.studentid from computer where c.score=(select max(score) from computer) limit 1);
select
s.studentid,s.studentname,c.score,c1.classname
from
student s
left join
class c1
on
s.classid=c1.classid
left join
computer c
on
s.studentid=c.studentid
where
c.score=(select max(score) from computer);
--21查询统计出每个班的平均分、显示平均分超过70分的信息、并按照降序显示信息
1.select c1.classname 平均分大于70的班级, avg(score) 平均分 from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid group by c1.classname having avg(score)>70 order by avg(score) desc;
注释: 临时表 加个 别名
2.select aa.ss 平均分大于70的班级 ,aa.ss 平均分 from (select c1.classname cc,avg(score) ss from student s left join class c1 on s.classid=c1.classid left join computer c on s.studentid=c.studentid group by c1.classname) aa where aa.ss>70 order by aa.ss desc;
select
s.studentid,s.studentname,c.score,c1.classname ,avg(c.score) avg
from
student s
left join
class c1
on
s.classid=c1.classid
left join
computer c
on
s.studentid=c.studentid
GROUP BY c1.classname
HAVING avg>70
ORDER BY avg desc ,c1.classname desc
--1查询出学生的编号,姓名,计算机成绩
select s.studentid,s.studentname,c.score
from student s,computer c
where s.studentid=c.studentid
select s.studentid,s.studentname,c.score
from student s
left join computer c
on s.studentid=c.studentid
--2查询参加过考试的学生信息
select s.*
from student s,computer c
where s.studentid=c.studentid
select s.*
from student s
left join computer c
on s.studentid=c.studentid
where c.score is not null
select *
from student
where studentid in(select studentid from computer)
--3查询出学生的编号、姓名、所在班级名称、计算机成绩
select s.studentid,s.studentname,c1.classname,c2.score
from student s right join class c1 on s.classid=c1.classid
left join computer c2 on s.studentid=c2.studentid
--4查询出年龄大于19岁的学生编号、姓名、计算机成绩
select s.studentid,s.studentname,c.score
from student s
left join computer c
on s.studentid=c.studentid
where s.studentage>19
--5查询出姓名中包含有c的学生编号、姓名、计算机成绩
select s.studentid,s.studentname,c.score
from student s
left join computer c
on s.studentid=c.studentid
where s.studentname like '%c%'
--6查询出计算机成绩大于80分的学生编号、姓名、班级名称
select s.studentid,s.studentname,c.score
from student s
left join computer c
on s.studentid=c.studentid
where c.score>80
--7查询出所有学生的信息和计算机成绩信息
select s.*,c.score
from student s
left join computer c
on s.studentid=c.studentid
--8查询出每个班的学生的计算机成绩的平均分,最高分,最低分
select s.classid, avg(c.score ),max(c.score ),min(c.score )
from student s
left join computer c
on s.studentid=c.studentid
group by s.classid
--9查询显示出班级的计算机平均分大于80的班级名称、平均分信息,并按照平均分降序显示
select c1.classname,avg(c2.score)
from student s right join class c1 on s.classid=c1.classid
left join computer c2 on s.studentid=c2.studentid
group by c1.classid
having avg(c2.score)>80
order by avg(c2.score) desc
--10查询出和Jim住在同一个地方的学生的基本信息
select *
from student
where studentaddress=(select studentaddress from student where studentname='jim')
select s2.* from
student s1,student s2
where s1.studentname='jim' and s1.studentaddress=s2.studentaddress
--11查询出班级编号大于3的学生基本信息
select *
from student
where classid>3
--12查询出班级编号大于3的学生的计算机平均分信息
select avg(c.score)
from student s
left join computer c
on s.studentid=c.studentid
where s.classid>3
--13查询出班级编号大于3的男生的学生信息
select *
from student
where classid>3 and studentsex='男'
--14查询男、女生的计算机平均成绩、最高分、最低分
select s.studentsex, avg(c.score) ,max(c.score),min(c.score)
from student s
left join computer c
on s.studentid=c.studentid
group by s.studentsex
--15将参加过考试的学生的年龄更改为20
update student
set studentage=20
where studentid in(select studentid from computer)
--16查询出每个班级的学生的平均分(查询的结果中包含平均分和班级名称)
select c1.classname,avg(c2.score)
from student s right join class c1 on s.classid=c1.classid
left join computer c2 on s.studentid=c2.studentid
group by c1.classid
--17删除姓名包含“c”字符的学生计算机成绩
delete from computer
where studentid in(select studentid from student where studentname like '%c%')
--18查询出G1T01班学生的编号、姓名、班级名称、计算机成绩
select s.studentid,s.studentname,c1.classname,c2.score
from student s right join class c1 on s.classid=c1.classid
left join computer c2 on s.studentid=c2.studentid
where c1.classname='G1T01'
--19查询出年龄在20-25之间的学生的编号、姓名、年龄、计算机成绩
select s.studentid,s.studentname,s.studentage,c.score
from student s
left join computer c
on s.studentid=c.studentid
where s.studentage BETWEEN 20 and 25
--20查询出成绩最高的学生的编号、姓名、计算机成绩、所在班级名称
select s.studentid,s.studentname,c2.score,c1.classname
from student s right join class c1 on s.classid=c1.classid
left join computer c2 on s.studentid=c2.studentid
where c2.score=(select max(score) from computer )
select s.studentid,s.studentname,c2.score,c1.classname
from student s right join class c1 on s.classid=c1.classid
left join computer c2 on s.studentid=c2.studentid
order by c2.score desc
limit 0,1
--21查询统计出每个班的平均分、显示平均分超过70分的信息、并按照降序显示信息
select c1.classname,avg(c2.score)
from student s right join class c1 on s.classid=c1.classid
left join computer c2 on s.studentid=c2.studentid
group by c1.classid
having avg(c2.score)>70
order by avg(c2.score) desc
索引分为几类
官方介绍索引是帮助MySQL高效获取数据的数据结构。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往是存储在磁盘上的文件中的(可能存储在单独的索引文件中,也可能和数据一起存储在数据文件中)。
我们通常所说的索引,包括聚集索引、覆盖索引、组合索引、前缀索引、唯一索引等,没有特别说明,默认都是使用B+树结构组织(多路搜索树,并不一定是二叉的)的索引。
优势:
可以提高数据检索的效率,降低数据库的IO成本,类似于书的目录。
通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗。
被索引的列会自动进行排序,包括【单列索引】和【组合索引】,只是组合索引的排序要复杂一些。
如果按照索引列的顺序进行排序,对应order by语句来说,效率就会提高很多。
劣势:
索引会占据磁盘空间
索引虽然会提高查询效率,但是会降低更新表的效率。比如每次对表进行增删改操作,MySQL不仅要保存数据,还有保存或者更新对应的索引文件。
主键索引
索引列中的值必须是唯一的,不允许有空值。
普通索引
MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值。
唯一索引
索引列中的值必须是唯一的,但是允许为空值。
全文索引
只能在文本类型CHAR,VARCHAR,TEXT类型字段上创建全文索引。字段长度比较大时,如果创建普通索引,在进行like模糊查询时效率比较低,这时可以创建全文索引。 MyISAM和InnoDB中都可以使用全文索引。
空间索引
MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型。MySQL在空间索引这方面遵循OpenGIS几何数据模型规则。
前缀索引
在文本类型如CHAR,VARCHAR,TEXT类列上创建索引时,可以指定索引列的长度,但是数值类型不能指定。
其他(按照索引列数量分类)
-
单列索引
-
组合索引
组合索引的使用,需要遵循最左前缀匹配原则(最左匹配原则)。一般情况下在条件允许的情况下使用组合索引替代多个单列索引使用。
sql优化
- 最大化利用索引;
- 尽可能避免全表扫描;
- 减少无效数据的查询
一、避免不走索引的场景
1. 尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描
优化方式:尽量在字段后面使用模糊查询
2. 尽量避免使用in 和not in,会导致引擎走全表扫描
优化方式:如果是连续数值,可以用between代替 如果是子查询,可以用exists代替
3. 尽量避免使用 or,会导致数据库引擎放弃索引进行全表扫描
优化方式:可以用union代替or
4. 尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描
优化方式:可以给字段添加默认值0,对0值进行判断
5.尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描
可以将表达式、函数操作移动到等号右侧
6. 当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描。
优化方式:用代码拼装sql时进行判断,没 where 条件就去掉 where,有where条件就加 and
7. 查询条件不能用 <> 或者 !=
使用索引列作为条件进行查询时,需要避免使用<>或者!=等判断条件。如确实业务需要,使用到不等于符号,需要在重新评估索引建立,避免在此字段上建立索引,改由查询条件中其他索引字段代替。
8. where条件仅包含复合索引非前置列
如下:复合(联合)索引包含key_part1,key_part2,key_part3三列,但SQL语句没有包含索引前置列"key_part1",按照MySQL联合索引的最左匹配原则,不会走联合索引
9. 隐式类型转换造成不使用索引
SQL语句由于索引对列类型为varchar,但给定的值为数值,涉及隐式类型转换,造成不能正确走索引
10. order by 条件要与where中条件一致,否则order by不会利用索引进行排序
二、SELECT语句其他优化
1. 避免出现select *
首先,select * 操作在任何类型数据库中都不是一个好的SQL编写习惯。
使用select * 取出全部列,会让优化器无法完成索引覆盖扫描这类优化,会影响优化器对执行计划的选择,也会增加网络带宽消耗,更会带来额外的I/O,内存和CPU消耗。
- 避免出现不确定结果的函数
特定针对主从复制这类业务场景。由于原理上从库复制的是主库执行的语句,使用如now()、rand()、sysdate()、current_user()等不确定结果的函数很容易导致主库与从库相应的数据不一致。另外不确定值的函数,产生的SQL语句无法利用query cache。
3.多表关联查询时,小表在前,大表在后。
在MySQL中,执行 from 后的表关联查询是从左往右执行的(Oracle相反),第一张表会涉及到全表扫描,所以将小表放在前面,先扫小表,扫描快效率较高,在扫描后面的大表,或许只扫描大表的前100行就符合返回条件并return了。
例如:表1有50条数据,表2有30亿条数据;如果全表扫描表2,你品,那就先去吃个饭再说吧是吧。
- 使用表的别名
当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减少哪些友列名歧义引起的语法错误。
- 用where字句替换HAVING字句
避免使用HAVING字句,因为HAVING只会在检索出所有记录之后才对结果集进行过滤,而where则是在聚合前刷选记录,如果能通过where字句限制记录的数目,那就能减少这方面的开销。HAVING中的条件一般用于聚合函数的过滤,除此之外,应该将条件写在where字句中。
where和having的区别:where后面不能使用组函数
6.调整Where字句中的连接顺序
MySQL采用从左往右,自上而下的顺序解析where子句。根据这个原理,应将过滤数据多的条件往前放,最快速度缩小结果集。
索引失效
什么时候没用
1.有or必全有索引;
2.复合索引未用左列字段;
3.like以%开头;
4.需要类型转换;
5.where中索引列有运算;
6.where中索引列使用了函数;
7.如果mysql觉得全表扫描更快时(数据少);
什么时没必要用
1.唯一性差;
2.频繁更新的字段不用(更新索引消耗);
3.where中不用的字段;
4.索引使用<>时,效果一般;
创建线程的三个方式
1)继承Thread类创建线程
2)实现Runnable接口创建线程
3)使用Callable和Future创建线程
创建线程池
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
Synchronzed和volatile区别什么时候用
作用:
- synchronized 表示只有一个线程可以获取作用对象的锁,执行代码,阻塞其他线程。
- volatile 表示变量在 CPU 的寄存器中是不确定的,必须从主存中读取。保证多线程环境下变量的可见性;禁止指令重排序。
区别:
- synchronized 可以作用于变量、方法、对象;volatile 只能作用于变量。
- synchronized 可以保证线程间的有序性(个人猜测是无法保证线程内的有序性,即线程内的代码可能被 CPU 指令重排序)、原子性和可见性;volatile 只保证了可见性和有序性,无法保证原子性。
- synchronized 线程阻塞,volatile 线程不阻塞。
- volatile 本质是告诉 jvm 当前变量在寄存器中的值是不安全的需要从内存中读取;sychronized 则是锁定当前变量,只有当前线程可以访问到该变量其他线程被阻塞。
- volatile 标记的变量不会被编译器优化;synchronized 标记的变量可以被编译器优化
Spring七个模块
核心容器: 核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文: Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP: 通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO: JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM: Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块: Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架: MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
spring实现原理
1、IOC 控制反转
概念:控制权由对象本身转向容器,由容器根据配置文件创建对象实例并实现各个对象的依赖关系。
核心:bean工厂
2、AOP 面向切面编程
1)静态代理
a、根据每个具体类分别编写代理类
b、根据一个接口编写一个代理类
2)动态代理
针对一个方面编写一个InvocationHandler,然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类。
AOP
在业务系统中,总有一些不得不处理的事情,我们
将这些重复性的代码抽取出来,放在专门的类中,
在通过spring的AOP的核心对代码段进行增强处理。
在不改变原代码的基础上进行功能增强。有五种
增强方式,前置增强,后置增强,环绕增强,引介增强。异常增强
AOP的作用: 利用AOP对业务逻辑的各个部分进行隔离,降低业务逻辑的耦合性,提高程序的可重用型和开发效率。 主要用于对同一对象层次的公用行为建模
Spring bean的生命周期
- Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
- Bean实例化后对将Bean的引入和值注入到Bean的属性中
- 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
- 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
- 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
- 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
- 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
- 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
- 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
bean的延迟加载
@lazy
单例模式
创建步骤
1、保留一个单例对象的静态实例,并初始化为nil
2、提供一个类方法让外界访问唯一的实例
3、重写allocWithZone方法,在这里创建唯一的实例,注意线程安全
4 、遵守NSCopying协议,实现copyWithZone方法
public class Singleton {
private static Singleton instance;
private Singleton() {
} public static Singleton getInstance() {
if(instance == null){
instance = new instance();
}
return instance;
}
}
// 饿汉式单例 立即加载
public class Singleton1 {
// 指向自己实例的私有静态引用,主动创建
private static Singleton1 singleton1 = new Singleton1();
// 私有的构造方法
private Singleton1(){}
// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton1 getSingleton1(){
return singleton1;
}
}
优点:
在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例
单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
提供了对唯一实例的受控访问。
由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
允许可变数目的实例。
避免对共享资源的多重占用。
缺点:
不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
单例类的职责过重,在一定程度上违背了“单一职责原则”。
滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
使用注意事项:
使用时不能用反射模式创建单例,否则会实例化一个新的对象
使用懒单例模式时注意线程安全问题
饿单例模式和懒单例模式构造方法都是私有的,因而是不能被继承的,有些单例模式可以被继承(如登记式模式)
适用场景:
单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:
需要频繁实例化然后销毁的对象。
创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
有状态的工具类对象。
频繁访问数据库或文件的对象。
以下都是单例模式的经典使用场景:
资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
控制资源的情况下,方便资源之间的互相通信。如线程池等。
spring mvc 执行流程
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
mybatis与mybatisplus的区别,对于开发人员来说用着具体方便在哪里
MyBatis的优缺点:
1.sql语句与代码分离,存放于xml配置文件中:
优点:便于维护管理,不用在java代码中找这些语句;
缺点: JDBC方式可以用用打断点的方式调试,但是Mybatis不能,需要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。
2.用逻辑标签控制动态SQL的拼接:
优点:用标签代替编写逻辑代码;
缺点:拼接复杂SQL语句时,没有代码灵活,拼写比较复杂。不要使用变通的手段来应对这种复杂的语句。
3.查询的结果集与java对象自动映射:
优点:保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。
缺点:对开发人员所写的SQL依赖很强。
4.编写原声SQL:
优点:接近JDBC,比较灵活。
缺点:对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如mysql数据库编程Oracle数据库,部分的sql语句需要调整。
2.什么是MyBatis-Plus
Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。
MyBatis-Plus的存在解决了我们使用Mybatis时,每当要写一个业务逻辑的时候都要在dao层写一个方法,再对应一个SQL
总结:MP的宗旨是简化开发,但是它在提供方便的同时却容易造成代码层次混乱,我们可能会把大量数据逻辑写到service层甚至contoller层中,使代码难以阅读。在使用MP时一定要做分析,不要将所有数据操作都交给MP去实现。毕竟MP只是mybatis的增强工具,它并没有侵入mybatis的原生功能,在使用MP的增强功能的同时,原生mybatis的功能依然是可以正常使用的。
JVM内存结构
JVM构成
Java源代码编译成Java Class文件后通过类加载器ClassLoader加载到JVM中
类存放在方法区中
类创建的对象存放在堆中
堆中对象的调用方法时会使用到虚拟机栈,本地方法栈,程序计数器
方法执行时每行代码由解释器逐行执行
热点代码由JIT编译器即时编译
垃圾回收机制回收堆中资源
和操作系统打交道需要调用本地方法接口
JVM原理
(1)jvm是java的核心和基础,在java编译器和os平台之间的虚拟处理器,可在上面执行字节码程序。
(2)java编译器只要面向jvm,生成jvm能理解的字节码文件。java源文件经编译成字节码程序,通过jvm将每条指令翻译成不同的机器码,通过特定平台运行
JVM执行程序的过程
1、加载.class文件
2、管理并分配内存
3、执行垃圾收集
JRE(java运行时环境)由JVM构造的java程序的运行环,也是Java程序运行的环境,但是他同时一个操作系统的一个应用程序一个进程,
因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。
JVM在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,
提供一个完整的Java运行环境,因此也就虚拟计算机。
JVM的生命周期
1、JVM实例对应了一个独立运行的java程序它是进程级别
a) 启动。启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void
main(String[] args)函数的class都可以作为JVM实例运行的起点
b) 运行。main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以表明自己创建的线程是守护线程
c) 消亡。当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出
2、JVM执行引擎实例则对应了属于用户运行程序的线程它是线程级别的
redis的使用场景以及数据类型
使用场景:秒杀、抢购、点赞、浏览量、计数器、
-
常用5种数据类型:string,list,set,zset,hash
一个字符串类型的值能存储最大容量是多少?512M
-
三种特殊数据类型:
-
geospatial:地理位置
-
hyperloglog:基础统计,统计一个集合中不重复的数据,使用位运算的方式,但是存在0.81%错误率。
-
bitmap:位图,只记录0和1。
-
什么是缓存? 缓存雪崩、缓存穿透、缓存击穿的含义以及解决方案?
数据交换的缓冲区(称作Cache),当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从内存中找。
缓存雪崩
大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
-
解决方案
可以给缓存设置过期时间时加上一个随机值时间,使得每个key的过期时间分布开来,不会集中在同一时刻失效。
缓存穿透
访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉。
-
解决方案
采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;
访问key未在DB查询到值,也将空值写进缓存,但可以设置较短过期时间。
缓存击穿
一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。
-
解决方案
在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。
Redis 数据淘汰策略有哪些?
Redis 提供 6种内存淘汰策略
- Volatile-lru:从设置了过期时间的数据集中,选择最近最少使用的数据释放。
- Allkeys-lru:从数据集中(包括设置过期时间以及未设置过期时间的数据集中),选择最近最少使用的数据释放。
- Volatile-random:从设置了过期时间的数据集中,随机选择一个数据进行释放。
- Allkeys-random:从数据集中(包括了设置过期时间以及未设置过期时间的数据集)随机选择一个数据进行入释放。
- Volatile-ttl:从设置了过期时间的数据集中,选择马上就要过期的数据进行释放。
- Noeviction:不删除任意数据(但Redis还会根据引用计数器进行释放),这时如果内存不够时,会直接返回错误。
Redis提供了哪几种持久化方式?
Redis主要提供了两种持久化机制:RDB
和AOF
:
-
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
-
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
怎么理解 Redis 事务?
redis对事务的支持目前还比较简单。redis只能保证一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令。 由于redis是单线程来处理所有client的请求的所以做到这点是很容易的。
redis没有回滚的概念,已经执行的动作不能undo
。当事务在执行EXEC命令之前出现错误,则redis会清空事务队列,放弃执行事务。在EXEC之后redis批量执行命令时产生的错误会被忽略,其他命令继续执行(这是全部执行的真正含义)。在执行的过程中,redis命令只会因为错误的语法而失败,因此,事务无罪。
Redis如何做内存优化?
尽可能使用散列表
(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小, 所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用 户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的 所有信息存储到一张散列表里面。
什么是单点登录?
单点登录(Single Sign On),简称为SSO
,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
简单来说,单点登录就是在多个系统中,用户只需一次登录,各个系统即可感知该用户已经登录。
原理: SSO系统生成一个token
,并将用户信息存到Redis中,并设置过期时间。
其他系统请求SSO系统进行登录,得到SSO返回的token,写到Cookie中
每次请求时,Cookie都会带上,拦截器得到token,判断是否已经登录。
springboot怎么简化配置的
主要是@EnableAutoConfiguration这个注解起的作用,这个注解是间接隐藏在springboot的启动类注解@SpringBootApplication中。
通过这个注解,SpringApplication.run(…)的内部就会执行selectImports()方法,寻找 META-INF/spring.factories文件,读取里面的文件配置,将事先已经写好的自动配置类有选择地加载到Spring容器中,并且能按照约定的写法在application.properties中配置参数或开关。
springcloud的五大组件
核心组件:**`Eureka`,`Ribbon`,`Feign`,`Hystrix`,`Zuul`**。
`Eureka`:提供服务注册功能。
`Ribbon`:提供负载均衡功能。
`Feign`:提供远程调用功能。
`Hystrix`:提供线程熔断功能。
`Zuul`:提供统一网关功能。
Dubbo是什么?和SpringCloud有什么区别?
Dubbo也是一种微服务框架,和SpringCloud一样。不过它是使用ZooKeeper
作为服务注册中心,通过RPC
服务调用方式进行远程调用。
SpringCloud使用Eureka
来支持服务注册,服务调用方式为REST API
。同时还集成了各类其他的类似于balabala…的组件。
Linux命令
lsof -i:端口号 查看端口号
tail -f filename 查看日志
ps -aux 查看所有的进程(不是动态的)
top 查看所有的进程(是动态的)
kill id 杀死进程