目录
10、一条查询语句中包含所有的子句,那么各子句之间的执行顺序?(面)
15、lombok的使用需要在IDE中提前安装插件!!!,如果项目在Linux系统中部署发布.是否需要提前安装插件!!!
1.反射代码
2.冒泡排序
package cn.tedu.array;
import java.util.Arrays;
/**本类用来完成冒泡排序*/
public class TestBubbleSort {
public static void main(String[] args) {
//1.创建一个无序的数组
int[] a = {27,96,73,25,21};
//2.调用method()完成排序
int[] newA = method(a);
System.out.println("排序完毕:"+Arrays.toString(newA));
}
public static int[] method(int[] a) {
//1.外层循环,控制比较的轮数,假设有n个数,最多比较n-1次
//开始值:1 结束值:<= a.length-1 变化:++
//控制的是循环执行的次数,比如5个数,最多比较4轮,<= a.length-1,最多取到4,也就是[1,4]4次
for(int i = 1 ; i <= a.length-1 ; i++) {
System.out.println("第"+i+"轮:");
//2.内层循环:相邻比较+互换位置
for(int j=0; j < a.length-i ; j++) {
//相邻比较,a[j]代表的就是前一个元素,a[j+1]代表的就是后一个元素
if(a[j] > a[j+1]) {
//交换数据
int t = a[j];
a[j] = a[j+1];
a[j+1] = t;
//System.out.println("第"+(j+1)+"次比较交换后:"+Arrays.toString(a));
}
}
System.out.println("第"+i+"轮的结果:"+Arrays.toString(a));
}
return a;//把排序好的数组a返回
}
}
3、单例工厂
方案一:饿汉式
1)把本类的构造方法私有化–为了不让外界调用构造函数来创建对象
2)通过本类的构造方法创建对象,并把这个对象也私有化,为了防止外界调用
3)提供公共的全局访问点向外界返回本类的唯一的一个对象
注意:公共方法需要设置成静态–需要跳过对象,通过类名直接调用这个返回本类对象的公共方法
对象也需要设置成静态的–这个对象需要在静态方法中被返回,而静态只能调用静态
方案二:懒汉式
==延迟加载的思想:==我们有的时候有些资源并不是需要第一时间就创建出来,所以需要延迟到需要时再创建
这样既可以提升性能,又可以节省资源
1)把本类的构造方法私有化–为了不让外界调用构造函数来创建对象
2)创建了一个本类类型的引用类型变量【这个变量后续用来保存创建出来的对象的地址值】
3)提供公共的全局访问点向外界返回本类的唯一的一个对象
4、二分查找算法
//二分查找测试类
//注意:二分查找必须用在有序列表中进行二分查找
public class BinaryChopTest {
public static void main(String[] args) {
int[] arrays = {1, 6, 10, 11, 12, 100};
for (int i = 0; i <= 10; i++) {
int sign = recursionBinarySearch(arrays, i, 0, arrays.length - 1);
if (sign == -1) {
System.out.println("在数组中找不到" + i + "这个元素");
System.out.println("目标元素" + i + "在数组的第" + sign + "位置");
}
sign = -1;
}
}
/**
* 使用二分查找和递归的结合进行查找
* 时间复杂度:O(logN)
* @param arrays 有序数组
* @param target 要查找的元素(目标元素)
* @param low 最低位
* @param high 最高位
* @return 找到的位置
*/
public static int recursionBinarySearch(int[] arrays, int target, int low, int high){
if (target < arrays[low] || target > arrays[high] || low > high) {
return -1;
}
int middle = (low + high) / 2; //初始化中间位置的值
if (arrays[middle] > target) {
return recursionBinarySearch(arrays, target, low, middle - 1);
} else if (arrays[middle] < target) {
return recursionBinarySearch(arrays, target, middle + 1, high);
} else {
return middle;
}
}
}
5、集合的遍历方式
方式一:使用普通for循环,size()和get(int index)结合。【只能操作list集合】
ArrayList list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
for(int i = 0; i < list.size(); i++){
System.out.println(list.get(i));
}
方式二:使用普通for,toArray()方法先将集合转为数组,然后遍历数组。【能操作所有的单列集合】
Collection c = new ArrayList(); // 多态,父类引用指向子类对象
c.add("a"); // 添加元素
c.add("b");
c.add("c");
Object[] objs = c.toArray(); // 将集合转换为数组
for(int i = 0; i < objs.length; i++){ // 遍历数组
System.out.println(objs[i]);
}
方式三:迭代器遍历,Iterator()获取到迭代器,然后通过迭代器的方法获取。
// 创建集合对象
Collection c = new ArrayList();
c.add("a"); // 添加元素
c.add("b");
c.add("c");
// 获取迭代器对象
Iterator it = c.iterator(); // 多态,实际上获取的是Iterator的实现类对象
While(it.hasNext()) { // boolean hasNext():判断是否有元素可以获取,没有就结束循环,用于循环结束的条件
System.out.println(it.next()); // Objext next():返回下一个元素
}
方式四:列表迭代器遍历,listIterator()先获取到列表迭代器,然后通过列表迭代器的方法【只适用于list集合】
// 创建集合对象
ArrayList list = new ArrayList();
// 添加元素
list.add("a");
list.add("b");
list.add("c");
// 获取列表迭代器
ListIterator lit = list.listIterator();
// 循环获取到每一个元素
while(lit.hasNext()){ // boolean hasNext():判断是否有元素可以获取,没有就结束循环
System.out.println(lit.Next()); // E next():获取元素
}
方式五:增强for -->快捷键:fore 按 alt + /;
// 创建集合对象
Collection<String> c = new ArrayList<String>(); //父类引用指向子类对象
c.add("a");
c.add("b");
c.add("c");
// 增强for循环遍历集合
for(String s : c){ //增强for遍历集合底层使用的是迭代器,不能对集合中的元素进行增删操作
System.out.println(s);
}
通过两种方法遍历上题中的map集合
package work;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/*
* 依次获取每个键值对的键和值
* Set<T> keySet
*
* Set<Map.Entry<K,V>> entrySet()
* getKey
* getValue
*/
public class Work02_TraversalMap {
public static void main(String[] args) {
Map<String,Integer> hashMap = new HashMap<String,Integer>();
hashMap.put("张三", 41);
hashMap.put("李四", 24);
hashMap.put("王五", 19);
hashMap.put("秦六", 26);
//遍历方式一
Set<String> keys = hashMap.keySet();
for(String key:keys) {
System.out.println(key + hashMap.get(key));
}
System.out.println("---------------------");
//遍历方式二
Set<HashMap.Entry<String, Integer>> entry = hashMap.entrySet();
for(HashMap.Entry<String,Integer> en:entry) {
System.out.println(en.getKey() + " : " + en.getValue());
}
}
}
6、怎么跨域请求:
1.添加跨域注解
2.使用jsp技术
7、事务的最高权限可以限制到具体的方法还是类
Spring事务注解是个典型的Spring AOP的注解。方法上面加上@Transactional,方法就有了事务的能力。
8、数据库的内链接外链接
内链接又叫等值连接:就是求两个表相同的部分;内连接:在每个表中找出符合条件的共有记录。[x inner join y on...]
外连接:左连接,右连接和全连接。
左连接的应用实例:根据左表的记录,在被连接的右表中找出符合条件的记录与之匹配,如果找不到与左表匹配的,用null表示
Select * from tableA left join tableB On tableA.column1=tableB.column2;
右连接:根据右表的记录,在被连接的左表中找出符合条件的记录与之匹配,如果找不到匹配的,用null填充。[x right [outer] join y on...]
Select * from tableA right join tableB On tableA.column1=tableB.column2
全连接:返回符合条件的所有表的记录,没有与之匹配的,用null表示(结果是左连接和右连接的并集)
第一种写法:(full join .. on ..)
自连接:MySQL数据库中不提供全连接,可用left join和right join将两张表的数据取出,再用union去重。
语法:Select * from tableA left join tableB On table A.column1 = tableB.column1
Union
Select * from tableA right join tableB On tableA.column1 = tableB.column1;
9、数据库怎么储存数据
行和列储存数据
前端传给后台数据,后台需要保存到数据库中,数据保存分为更新和新增,这两种操作的实现方法又是不一样的。
那么一般有两种方法来实现数据保存:
1.dao层或者是facade层,直接Delete(remove)改该数据表,再insert(persist)数据。
2.根据传入的数据进行分类,是新增的、更新的还是已经不存在的,在分别进行新增、更新或者是删除操作。
这种方法的实现,一般是4个list,一个放从后台查询的lists全部数据,其他三个分别为insertList、updateList和deleteList。
通过关键字,在lists中没有记录的关键字放入insertList中,其他的也是按照关键字
10、一条查询语句中包含所有的子句,那么各子句之间的执行顺序?(面)
FROM-->WHERE(过滤条件)-->GROUP BY(分组)-->HAVING(过滤条件)-->SELECT(查询)-->ORDER BY(排序)-->limit(分页)
11、sql语句的优化
1.避免Select *
Selcet中每少提取一个字段,数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。
1)尽量避免select * 的存在,使用具体的列代替*,避免多余的列
2)使用where限定具体要查询的数据,避免多余的行
3)使用top,distinct关键字减少多余重复的行
4. insert插入优化
分析说明:insert into select批量插入,明显提升效率,可以尽量避免一个个循环插入。
5. 优化修改删除语句
如果你同时修改或删除过多数据,会造成cpu利用率过高从而影响别人对数据库的访问。如果采用单一循环操作,效率会更低。折中的办法就是,分批操作数据。
6.避免全表扫描
在多数情况下,Oracle使用索引来更快地遍历表,优化器主要根据定义的索引来提高性能。但是,如果在SQL语句的where子句中写的SQL代码不合理,
就会造成优化器删去索引而使用全表扫描。
Where中少用NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE,它们会引起全表扫描。避免使用like和or语句。
7.sql语句用大写的;因为oracle总是先解析sql语句,把小写的字母转换成大写的再执行。
8.用Where子句替代having子句
12、消息队列
1.消息队列使用的场景和中间件有很多,但解决的核心问题主要是:异步、解耦、消峰填谷。
2.缺点主要在于系统的可用性、复杂性、一致性问题,引入消息队列后,需要考虑MQ的可用性,万一MQ崩溃了岂不是要爆炸?
而且复杂性明显提高了,需要考虑一些消息队列的常见问题和解决方案,还有就是一致性问题,一条消息由多个消费者消费,
万一有一个消费者消费失败了,就会导致数据不一致。
3.RabbitMQ有三种模式:单机模式,普通集群模式,镜像集群模式
镜像集群模式是所谓的RabbitMQ的高可用模式,跟普通集群模式不一样的是,你创建的queue,
无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,
都会自动把消息到多个实例的queue里进行消息同步。
优点在于你任何一个实例宕机了,没事儿,别的实例都可以用。
缺点在于性能开销太大和扩展性很低,同步所有实例,这会导致网络带宽和压力很重,而且扩展性很低,
每增加一个实例都会去包含已有的queue的所有数据,并没有办法线性扩展queue。
开启镜像集群模式可以去RabbitMQ的管理控制台去增加一个策略,指定要求数据同步到所有节点的,
也可以要求就同步到指定数量的节点,然后你再次创建queue的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。
13、数据库的还原和备份
数据库导入和导出
导出数据库: 将mysql中的数据库以 xxx.sql文件进行转储.
导入数据库: 读取xxx.sql文件 之后工具执行其中的sql,最终实现数据的导入功能.
说明: 上述的操作称之为数据库冷备份. 一般在生产环境下 为了保证数据的安全.一般都会定期冷备份.(周期3-7天左右) 一般一式3份. 数据库的冷备份是恢复数据最后有效的手段.
特点: 冷备份容易丢失数据. 热备份可以实现实时备份.
14线程等待的区别
sleep是Thread类中的方法,wait是Object类的方法,
sleep不会释放对象锁,wait会释放对象锁。
sleep可以在任何地方用,wait()只能在synchronized方法或块中使用。
sleep一定要传入参数,wait不传参数的时候是进入无限等侍,要使用notife才能唤醒。
15、lombok的使用需要在IDE中提前安装插件!!!,如果项目在Linux系统中部署发布.是否需要提前安装插件!!!
答案: 不要!!!
原因: lombok插件编译期有效.(编译期:由xxx.java文件编译为xxxx.class文件).在打包之前class文件中已经包含了set/get等方法,所以项目打包之后可以直接运行.无需安装插件!!!.
16、Spring容器如何理解
4.2.1 关于IOC的说明
IOC: 控制反转
具体含义: 将对象创建的权利交给Spring容器管理.
原因: 如果将对象自己管理,则必然出现耦合性高的现象. 不方便扩展
容器: 是一种数据结构类型 Map<K,V>集合
KEY: 类名首字母小写
Value: Spring为当前的类创建的对象.
只要程序启动成功,则Map集合中(容器),里边包含了所有的IOC管理的对象