Java基础
Synchronized和Lock
Synchronized有三种用法,分别是
-
Synchronized修饰普通实例方法,锁是当前实例对象
-
Synchronized修饰静态方法,锁是当前类的class对象
-
Synchronized修饰代码块,锁是括号里的对象
Lock锁的使用
Lock是jdk1.5引入的一个接口,他的主要实现类有
-
ReenTrantLock():可重入锁,最常用的一种实现类
-
ReentrantReadWriteLock.ReadLock():读锁
-
ReentrantReadWriteLock.WriteLock():写锁
Synchronized和Lock的区别
- Synchronized是Java关键字,Lock是Java的一个接口
- Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁(tryLock())
- Synchronized会自动释放锁,Lock必须通过unlock()去手动释放锁
- 锁的中断机制不同,Synchronized修饰的线程,其他线程会一直等待,Lock锁的线程,其他线程可能不会一直等待
- Synchronized是重入锁,非公平锁,Lock也是可重入锁,默认是非公平锁,但是可以通过在new对象的时候,参数列表指定false,让它成为公平锁
- Synchronized适合锁少量的代码同步问题,Lock适合锁大量的同步代码
List集合怎么去重
-
利用set去重
Set set2 = new HashSet(); List newList3 = new ArrayList(); set2.addAll(list); newList3.addAll(set2); System.out.println("set和list转换去重:" + newList3);
-
遍历后判断,再添加到另一个集合中
List newList2 = new ArrayList(); for (Integer integer : list) { if(!newList2.contains(integer)){ newList2.add(integer); } }
-
双重for循环去重
for (int i = 0; i < list.size(); i++) { for (int j = 0; j < list.size();j++ ) { if (i != j && list.get(i) == list.get(j)) list.remove(j); } }
spring的事务隔离级别和传播行为
spring的事务隔离级别有五个,分别是
-
default: 表示默认使用数据库的事务隔离级别
-
read-unCommit(读未提交):表示其他事务可以看到某个事务修改了但是没有提交的数据,可能造成脏读、幻读、不可重复读
-
read-Commit(读提交):Oracle的默认隔离级别。表示其他事务不能看到某个事务未提交的数据,可以防止脏读,但是不能防止幻读和不可重复读
-
Repeatable-read(可重复读):mysql的默认隔离级别。表示当事务多次读取同一数据时,保证他的值和事务开始的内容是一样的,可以防止脏读,不可重复读,但是可能会出现幻读。
-
Serializable(序列化):这是最可靠但是花费最昂贵的事务隔离级别。可以防止脏读幻读不可重复读。
spring的传播行为有七个,分别是
- required:表示如果存在当前事务,就加入,没有就新建一个事务
- Mandatory:表示如果存在当前事务,就加入,如果没有,就抛出异常
- never:表示以非事务的方式运行,如果存在当前事务,就抛出异常
- not-support:表示以非事务的方式运行,如果存在当前事务,就将当前事务挂起
- requires-new:表示新建一个事务,如果存在当前事务,就将当前事务挂起
- supports:表示支持当前事务,如果不存在当前事务,就以非事务的方式运行
- Nested:表示如果存在当前事务,就嵌套在当前事务中运行,如果外层事务失败,会回滚内层事务,但是如果内层事务失败,则不会引起外层事务回滚。如果不存在,就新建一个事务运行
数据库优化
具体场景
-
有1000万条数据要插入到数据库中,有什么思路
首先,如果要将这么多数据插入到数据库中,如果一条一条的插的话,那么这样频繁的开关链接肯定是不行的,如果是这样的话,就可以在一条sql语句中插入多条数据这样可以减少连接次数,然后的话更改了数据的话肯定要提交事务,提交事务的话可以进行分批处理,就是不要每插入一次就提交一下事务,再者就是就是尽量有序插入,这样的话主要是为了减少以后索引的维护压力 -
数据库中有1000万条数据库,我要查询比如说a字段为10的,和年龄是10或者15的,讲一下怎么查询
首先对于查询的字段可以 添加索引,然后的话,使用了索引,就要优化自己的sql语句,不要用到or和in
可以使用union去把查询的结果并起来,这样的话就不会导致索引不可用。然后对于数据库本身的话也是可以考虑的一方面,可以通过更改数据库引擎,来寻找最优的方式。mysql默认引擎是innoDB,Oracle没有引擎的概念,oracle是将数据处理分为两大类,分别是联机事务处理和联机分析处理。
-
一次插入10条数据怎么操作?(Mybatis里面怎么操作)
可以直接通过insert语句插入,每条字段之间通过“,”隔开。在Mybatis中插入的话,可以通过
先把要插入的值放进一个lsit集合中,再使用foreach标签来循环遍历这个list集合插入。
索引为什么能提高查询效率
索引本质上是一个数据结构,在Mysql中是B+树,B+树是一种平衡树(一颗空树或者说它左右两颗子树的高度查绝对值不会超过1,并且左右两个子树都是平衡树),在不使用索引时,数据库中的记录都是存储在页中
每个数据页组成了一个双向链表,同时每个数据页中的数据又组成了一个单向链表,所以要查询数据的话,就需要遍历这些链表,因为链表的这个数据结构的特性,自然速度快不了。
当使用的索引后,因为索引底层是一颗平衡树,这个平衡树就像一个"目录",我们可以通过"目录",就能快速的定位到我们要查找的对应记录在具体的哪个页上面,然后再继续通过这个”目录“,可以快速的找到这个页上面的具体记录。(具体是通过平衡树的算法==》二分查找法)
数据库怎么查询重复数据
select * from people where id in (
select id from people group by id having count (id)>1)
session执行流程和原理?
- 用户第一次请求服务器时,服务器端会生成一个sessionid
- 服务器端将生成的sessionid返回给客户端,通过set-cookie
- 客户端收到sessionid会将它保存在cookie中,当客户端再次访问服务端时会带上这个sessionid
- 当服务端再次接收到来自客户端的请求时,会先去检查是否存在sessionid,不存在就新建一个sessionid重复1,2的流程,如果存在就去遍历服务端的session文件,找到与这个sessionid相对应的文件,文件中的键值便是sessionid,值为当前用户的一些信息
- 此后的请求都会交换这个 Session ID,进行有状态的会话。
session存储的数据存在哪里?
session.setAtturbute()是通过键值对的方式存储数据的,所以底层是存放在键值对里面的
mybatis的#{}和 有 什 么 区 别 ? 为 什 么 {}有什么区别?为什么 有什么区别?为什么{}会存在
mybatis在处理#{}时,会对sql进行预编译,将#{}替换成问号,这样可以有效防止sql注入
mybatis在处理${}时,会直接将我们输入的值进行字符串拼接,所以可能会发生sql注入
但是 既 然 会 存 在 , 那 就 肯 定 会 有 它 的 意 义 , 所 以 说 当 我 们 需 要 s q l 注 入 的 时 候 , 它 就 能 发 挥 它 的 作 用 了 。 比 如 在 我 们 使 用 m y b a t i s 查 询 数 据 时 使 用 o r d e r b y 动 态 参 数 排 序 时 就 应 该 使 用 {}既然会存在,那就肯定会有它的意义,所以说当我们需要sql注入的时候,它就能发挥它的作用了。比如在我们使用mybatis查询数据时使用order by动态参数排序时就应该使用 既然会存在,那就肯定会有它的意义,所以说当我们需要sql注入的时候,它就能发挥它的作用了。比如在我们使用mybatis查询数据时使用orderby动态参数排序时就应该使用{}。
mybatis关系映射
数据结构–链表和数组、树
数据结构分为线性结构和非线性结构
- 线性结构
- 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系
- 线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构,顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的
- 链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息
- 常见线性结构有:数组、队列、链表和栈
- 非线性结构
非线性结构包括:二维数组、多维数组、广义表、树结构、图结构
链表是以节点的形式来存储的,每个节点包含date域,next域:指向下一个节点。链表分为带头节点的链表和没有头节点的链表
finalized()方法
protected void finalize() throws Throwable {
try {
stream.close();
} catch (IOException e) {
} finally {
stream = null;
super.finalize();
}
}
GC负责调用finalize()方法。这个方法不需要程序员手动调用。JVM的垃圾回收期负责调用这个方法。finalize()只需要重写,重写完将来自动有人来调用。
finalize()方法的执行时期:当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法。
前端面试题
如何使用js和jquery设置div的宽和高
JS:
<script type="text/javascript">
var demo = document.getElementById('demo');
demo.style.width = '200px';
demo.style.height = '200px';
</script>
jquery:
$("#div1").css("height","320px");
$("#div1").css("width","480px");
如何隐藏div
通过css:display-none
将div的宽度和高度设置为0
opacity来设置不透明级别,设置为透明的
js有哪些数据类型
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Object类型
springboot和springmvc的区别
在了解两个东西或者是两个技术的区别时,首先得知道他们是什么,对于springmvc来说,根据官方文档的解释,springmvc是一个基于servlet API搭建的原始web框架,属于springweb模块的一部分,而springboot是spring发展到一定程度的产物。它可以说是一个全新的框架,也可以说是一种新的编码规范,springboot的产生,简化了框架的使用,“约定大于配置”,是springboot的宗旨,我们不需要在使用spring众多框架时,去配置大量而繁琐的配置文件了,只需要使用约定好的注解。
对于springboot和springmvc的区别
首先,
- springmvc是基于spring的一个mvc框架,主要为了简化web应用的开发。springboot实现了自动配置,降低了项目搭建的复杂度
- springmvc要自己配置web服务器启动,springboot内置了web服务器,不需要自己配置
- springmvc需要在web.xml中注册前端控制器和编写springmvc配置文件,而springboot不需要任何配置文件
spring的JDBC和Java原生态的JDBC有什么区别
spring的JDBC是对Java原生态JDBC进行了简单的封装,我们在spring中使用jdbc,只需要关注sql语句编写和返回的结果集就好了,像连接的创建和关闭,不用我们自己去管理,spring帮我们完成(通过IOC)
Redis缓存的理解
Redis是一个开源的,基于key-value的数据结构存储系统,支持多种类型的数据结构,比如String、数组、list、set、map。
Redis的缓存是存放在内存中的,可以通过设置一个定时器,定时将缓存中的数据进行持久化
mybatis的执行流程(工作原理)
// 1.加载配置文件 通过InputStream
InputStream is = Resources.getResourceAsStream("mybatis.xml");
// 2.创建sqlSession工厂
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(is);
// 3.创建sqlSession
SqlSession session = sf.openSession();
// 4.创建mapper接口对象 动态生成mapper接口实现类
DeptMapper mapper = session.getMapper(DeptMapper.class);
// 5.利用mapper对象进行持久化操作
Dept dept = mapper.selectByPrimaryKey("30");
System.out.println(dept);
// 6.关闭资源
session.close();
- 首先通过Resources去加载配置文件,返回一个io流
- 创建sqlSession
- 创建sqlSession
- 通过sqlSession调用mapper接口对象(通过Java反射机制)
- 利用mapper对象进行持久化操作
- 关闭资源
mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式
通过Java的反射机制创建对象,同时使用反射给对象的属性逐一赋值并返回,哪些关联不到映射关系的对象是无法赋值的,所以会返回null。
可以使用resultMap标签逐一定义列名和对象属性名之间的映射关系,第二种就是使用sql列起别名的方式
Mybatis映射文件中,如果A标签通过include引用了B标签的内容,那么B标签能否定义在A标签的后面,还是说必须定义在A标签的前面?
虽然Mybatis解析xml文件是按顺序解析的,但是被引用的B标签还是可以被定义在任何地方,Mybatis都能够正确识别
原理是,Mybatis在解析A标签的时候,如果发现引用了B标签,但是B标签还没有解析到,那么这个时候Mybatis会将A标签标记为未解析状态,然后继续往下解析其他内容,当所有标签解析完毕,Mybatis会重新解析那么被标记为未解析状态的标签。
笔试题
文件复制
// 指定文件要复制的文件
File file = new File("F:\\test1\\output.txt");
// 复制到哪里
File target = new File("F:\\test1\\copy1.txt");
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 输入流
fis = new FileInputStream(file);
// 输出流
fos = new FileOutputStream(target);
// 指定一个byte数组,读取一个字节数组长度和写出一个字节数组长度
byte[] bytes = new byte[1024];
// read方法读到末尾会返回-1
int len =0 ;
while ((len = fis.read(bytes))!=-1){
// 写入指定文件中
fos.write(bytes);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fos!=null)fos.close();
if (fis!=null) fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
单例模式
//懒汉式实现单例模式
public class SingleTon {
private SingleTon(){}
public static SingleTon s;
public static synchronized SingleTon getInstance(){
if (s==null){
s = new SingleTon();
}
return s;
}
}
//饿汉式实现单例模式
public class SingleTon {
private SingleTon(){}
public static SingleTon s = new SingleTon();
public static SingleTon getInstance(){
return s;
}
}
排序算法
冒泡排序
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-i-1; j++) {
if (arr[j]>arr[j+1]){
arr[j] = arr[j]+arr[j+1];
arr[j+1] = arr[j]-arr[j+1];
arr[j] = arr[j]-arr[j+1];
}
}
}
System.out.println(Arrays.toString(arr));
选择排序
for (int i = 0; i < arr.length-1; i++) {
for (int j = i; j < arr.length-1; j++) {
if (arr[i]>arr[j+1]){
arr[i] = arr[i] + arr[j+1];
arr[j+1] = arr[i] - arr[j+1];
arr[i] = arr[i] - arr[j+1];
}
}
}
System.out.println(Arrays.toString(arr));
插入排序
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if (arr[j]<arr[j-1]){
arr[j] = arr[j]^arr[j-1];
arr[j-1] = arr[j]^arr[j-1];
arr[j] = arr[j]^arr[j-1];
}
}
}
System.out.println(Arrays.toString(arr));
快速排序
二分查找
int[] arr = {10,20,30,40,50,60,70,80};
int target = 30;//目标值
int min = 0;//最小值0
int max = arr.length;//最大值:数组长度
while(min<max){//
int mid = (min + max)/2;//中间值
if (arr[mid] < target){
min = mid;
}
if (arr[mid] > target){
max = mid-1;
}
if (arr[mid] == target){
System.out.println(mid);
break;
}
}