声 明:你要是能看到最后算你牛p,不看绝对是你的损失。
最全的实际面试题大总结
1. 自我介绍(这个需要自己准备了);
2. 之前工作中主要负责的功能模块和详细流程;
下边是正儿八经的面试基础题
1. 数据库用过哪些,主要的区别是什么?
-----主要用过Oracle和MySQL两中数据库,他们之间的区别很多,我了解过的有:
MySql数据库是中小型数据库。Oracle是大型数据库。
mysql是免费开源的数据库,Oracle是付费的数据库。
mysql是默认提交的,oracle需要手动提交。
mysql是的sql语句相对实用灵活,oracle中规中矩相对复杂。(分页查询例子)
mysql数据库对诊断调优不够成熟,提供了慢查询日志。oracle的诊断调优就很成熟。
mysql默认不支持事务,oracle默认支持事务。
新建的数据库mysql数据库要比oracle小很多。
mysql的分区锁不够成熟。oracle的分区锁和分区索引很成熟。
oracle支持大并发,大访问量等(感觉回答这么多已经差不多了,再多会让人觉得是在背)。
2. like走不走索引?
------like后边如果是以%开头的不走索引,以字符串或者字母等是走索引的。
%开头索引失效,使用全表扫描。但可以通过翻转函数+like前模糊查询+建立翻转函数索引=走翻转函数索引,不走全表扫描。
3. mybatis中${}和#{}的区别?
-----#{}表示的是占位符,而${}是字符串拼接的意思。占位符安全但是被办法直接用关键字,字符串拼接一般字符和关键字都可以用,但是容易sql强制注入。
关于二维数组?
定义二维数组:
int [][] a =new int[3][4]; //定义一个二维数组,这个数组是由3个一维数组组成,每个一维数组的长度是4;一位数组里边存的是指向二维数组的地址。
定义不同长度的二维数组:
int [][] a = {{8,9},{7,3,2,1},{5,6,8,4,3,2}} //定义二维数组 ,数组里边的地址指向的数组长度不一致。
遍历二维数组需要双层循环。
至于一位数组二维数组之间的切换合并还没遇到过,之后更新;
4. 索引的类型?
-----有四种。
主键索引:创建主键会有这个索引,primary key。
唯一索引:创建唯一时的索引,unique。
全局索引:Test文本文件,全局索引只有MylASM。
普通索引:直接创建索引。
聚簇索引:是指索引顺序和物理存储的索引顺序一致,叶节点的索引值指向索引值。
非聚簇索引:索引顺序和物理存储数据无关,叶节点的索引节点指向对应的数据块。
5.为什么索引快?
-----因为他的二叉树以及占用空间小,所以方位快,效率高,根据索引上的指针逐一找到结果数据块。
6. 索引使用的场景?
-----1.数据量不大的表不用索引,因为扫描表的成本并不高。
2.不要设置过多的索引,占用磁盘空间,后期也不好维护。
3.合理的使用复合索引,覆盖索引。
4.对常用的范围查询的字段,可以考虑聚集索引。
5.避免对不常用的列,逻辑列,大字段列创建索引。
7. 创建数据库的注意事项是什么?
-------泛型:是一种创建数据库的规则和总结。
第一泛型:确保每列的原子性,是最基本的泛型(提高了分类性能)。
也就是说每个列的字段都要时不可分解的原子值,不能出现重复的组,和缺少唯一标识性字段列。如地址就不能简单直接的作为列名,因为它下边还有省市县等,所以要单独惊醒存储。
第二泛型:确保每列都和主键相关(减少数据库的冗余)。
在一个数据库中只能保存一种数据,不可以把多种数据保存到同一张数据库中。
第三泛型:确保每列都和主键直接相关,而不是简介相关(减少数据的冗余)。
查看索引: show index from 表明;
给name加索引: alter table 表明 add index 索引名(列名);
删除索引: alter table 表名 drop index 索引名;
复合索引: alter table 表名 add index(name,age);
(注意复合索引可以直接只用最左变得名走索引或者两个一起走索引,其它的不走这个索引)。
8. 日志常用的四个等级?
-----ERROR,WARN,INFO,DEBUG。
9. 事物的四个特性?隔离性的四个级别?
-----四个特性有:原子性,一致性,隔离性,持久性。
原子性:事务是数据库的逻辑工作单位,在事务的诸操作中要么全部提交,要么全部回滚。
一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。
隔离性:一个事务的执行不会被另一个事务所干扰。即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
隔离性的四个级别:未提交状态,已提交状态,可重复,可串行化。
10. IO流的设计模式?
由两种:适配器模式和装修模式。
Java的IO流库提供了一种链接(Chaining)机制,可以将一个流处理器跟另一个流处理器首位相连,以其中之一的输出作为另一个的输入而形成一个流管道链接。比如,常见的new DataInputStream(new FileInputStream(file))就是把FileInputStream流当作DataInputStream流的管道链接。
其次,对于Java IO流还涉及一种对称性的设计策略,其表现为输入输出对称性(如InputStream和OutputSteam的字节输入输出操作)和字节字符的对称性(InputStream和Reader的字节字符输入操作,OutputStream和Writer的字节字符输出操作)。
IO流涉及的装饰者设计模式:
FileInputStream inputStream=new FileInputStream(file);
//把inputStream装饰成BufferedReader来成为具备缓冲能力的reader
BufferedReader reader=new BufferedReader(inputStreamReader);
IO流涉及的适配器设计模式
FileInputStream fileInput=new FileInputStream(file);
//把fileInput文件字节流,通过适配器(InputStreamReader转换流)变为字符流
InputStreamReader input=new InputStreamReader(fileInput);
装饰者模式:给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例(各种字符流键装饰,各种字节流间装饰)。
适配器模式:有时候我们需要实现一个接口,但那个接口可能有很多抽象方法,我们只需要其中一个或多个方法。这时候我们可以创建一个类(适配器)实现接口,并重写接口中所有方法(空方法,有方法体,但方法体中无内容)。当我们需要接口中的某个方法时,只需继承类似于适配器的类 ,然后重写对应的方法即可。 将某个类的接口转换成我们期望的另一个接口表示,目的是消除由于接口不匹配所造成类的不兼容问题(字符流与字节流间互相适配)。
11. 设计模式?
1、单一职责原则(Single Responsibility Principle)
定义 : 应该有且只有一个原因引起类的变化
注意 : 这里的类不光指类,也适用于方法和接口,比如我们常说的一个方法实现一个功能
2、里氏代换原则(Liskov Substitution Principle)
定义 : 只要父类出现的地方子类就一定可以出现,而且替换为子类也不会出现任何异常或错误,使用者不需要知道是父类还是子类.但是返回来就不行了,有子类出现的地方,不一定能使用父类
使用规范 :子类必须完全实现父类的方法,如果子类无法完全实现父类的方法,则建议断开父子继承关系,采用依赖 聚集 | 组合 等关系来代替。
子类可以有自己的个性,覆盖或实现父类的方法时,输入参数可以被放大,比如父类中有一个方法的输入参数是 HashMap,子类的参数可以是 Map 类型,这样父类就可以被子类替换,如果反过来,则违背了里氏替换原则,所以子类中方法的前置条件必须与父类的被覆写的方法的前置条件相同或者更宽松
覆写或实现父类的方法时,输出结果可以被缩小,也就是说如果父类方法返回的类型 T,子类的相同方法
(重载或覆写)的返回值类型 S,S 和 T 要么同类型,要么 S 是 T 的子类;跟上面的道理一样
注意 : 采用里氏替换原则时,尽量避免子类的"个性",一旦子类有了"个性",子类和父类的关系就会变得不好调和
3、依赖倒置原则(Dependence Inversion Principle)
定义 : 依赖倒置原则包含三个含义
高层模块不应该依赖低层模块,两者都应该依赖其抽象
抽象不应该依赖细节
细节应该依赖抽象
高层模块和低层模块比较好理解,每一个逻辑都是由原子逻辑组成的,不可分割的原子逻辑是低层模块,原子逻辑再组装就是高层模块;
抽象指的是接口或者抽象类,两者都不能直接实例化;
细节就是实现类,实现接口或继承抽象类而产生的类就是细节,其特点是可以被实例化;
依赖倒置原则在 Java 中的实现是表现是:
模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生
的;
接口或抽象类不依赖于实现类实现类依赖接口或抽象类。这也是面向接口编程的精髓之一
遵循的规则 :
每个类尽量都有接口或抽象类,或者两者都有
变量的表面类型尽量是接口或者抽象类
任何类都不应该从具体类派生
尽量不要覆写基类的方法,如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要覆写
结合里氏替换原则使用
接口负责定义 public 属性和方法,并且声明与其他对象的依赖关系,抽象类负责公共构造部分的实现,实
现类准确的实现业务逻辑
4、接口隔离原则(Interface Segregation Principle)
我们先来看接口的定义 :
实例接口 : 在 Java 中声明一个类,然后用 new 关键字产生一个实例,它是对一类事物的描述,可以看成是一个接口
类接口 : 使用 interface 定义的接口
隔离的的理解 :
客户端不应该依赖它不需要的接口
类之间的依赖关系应该建立在最小的接口上
概括 : 建立单一接口,不要建立臃肿庞大的接口,也就是接口尽量细化,接口中的方法尽量少,这个是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
接口隔离原则的约束条件 :接口要高内聚,意思就是提高接口,类,模块的处理能力,减少对外的交互,再具体一点就是在接口中尽量减少对外的 public 方法,通过业务逻辑压缩接口中的 public 方法,定制服务,就是单独为一个个体提供优良的服务,比如我们写用户模块的时候,需要给用户提供查询信息,
修改密码,注册用户等信息,当管理员执行相同操作的时候,一般人会复用这些方法,
然后在这个的基础上再增加管理员自己的方法,这种设计方法肯定是有问题的,这样设计,当你修改了普通用户调用的接口实现时,管理员的实现也会发生不可预测的改变,我们应该为管理员单独写一个接口
接口设计是有限度的,接口的设计粒度越小,系统越灵活,这是肯定的,但灵活的同时带来的问题是 结构
复杂化,开发难度增加, 可维护性降低
一个接口只服务于一个子模块或业务逻辑
已经被污染了的接口,尽量去修改 ,若修改的风险较大,则采用适配器模式进行转化处理
了解环境,拒绝盲从,不要一味的去套设计模式,有的时候不用比用了更好,也不要去照搬别人的设计方
法,他的方法到你这不一定效果就好,毕竟业务逻辑不一样
5、迪米特法则(Demeter Principle)
定义 : 迪米特法则也叫最少知识原则,含义是 一个对象应该对其他对象有最少的了解,这个应该很好理解,就是降低各模块之间的耦合
6、开闭原则(Open Close Principle)
定义 : 一个软件实体如类,模块和函数应该对扩展开放,对修改关闭,开闭原则也是其他五个原则的基石
单例模式
单例模式可以分为懒汉式和饿汉式:
懒汉式单例模式:在类加载时不初始化。
饿汉式单例模式:在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快。
第一种(懒汉,线程不安全):
public class SingletonDemo1 {
private static SingletonDemo1 instance;
private SingletonDemo1(){}
public static SingletonDemo1 getInstance(){
if (instance == null) {
instance = new SingletonDemo1();
}
return instance;
}
}
下边有更精彩的!!!!!!!!!!
第二种(懒汉,线程安全):
public class SingletonDemo2 {
private static SingletonDemo2 instance;
private SingletonDemo3(){}
//这种写法在getInstance()方法中加入了synchronized锁。能够在多线程中很好的工
作,而且看起来它也具备很好的lazy loading,但是效率很低(因为锁),并且大多数
情况下不需要同步。
public static synchronized SingletonDemo2 getInstance(){
if (instance == null) {
instance = new SingletonDemo2();
}
return instance;
}
//这样处理就没有问题了吗?同样的原理,线程A和线程B,线程A读取instance值为null,此时cpu被线程B抢去
了,线程B再来判断instance值为null,于是,它开始执行同步代码块中的代码,对instance进行实例化。此时,线
程A获得cpu,由于线程A之前已经判断instance值为null,于是开始执行它后面的同步代码块代码。它也会去对
instance进行实例化。这样就导致了还是会创建两个不一样的实例。
private static SingletonDemo2 getInstance(){
if (instance == null) {
synchronized (SingletonDemo2 .class){
instance = new SingletonDemo2();
}
}
return instance;
}
//在同步代码块中instance实例化之前进行判断,如果instance为null,才对其进行实例化。这样,就能保证
instance只会实例化一次了。也就是所谓的双重检查加锁机制。
private static SingletonDemo2 getInstance(){
if (instance == null) {
synchronized (SingletonDemo2 .class){
if (instance == null) {
instance = new SingletonDemo2();
}
}
}
return instance;
}
}
第三种(饿汉):
public class SingletonDemo3 {
private static SingletonDemo3 instance = new SingletonDemo3();
private SingletonDemo3(){}
public static SingletonDemo3 getInstance(){
return instance;
}
}
第四种(饿汉,变种):
public class SingletonDemo4 {
private static SingletonDemo4 instance = null;
static{
instance = new SingletonDemo4();
}
private SingletonDemo4(){}
public static SingletonDemo4 getInstance(){
return instance;
}
}
工厂模式
工厂模式
简单工厂模式(Simple Factory Pattern)
从简单的工厂模式开始说起的话,我们要知道工厂模式的目的是什么?工厂模式的目的在于程序的可扩展性。而对于简单工厂模式来说,它是为了让程序有一个更好地封装,降低程序模块之间的耦合程度。
工厂方法模式
可以一定程度上解耦,消费者和产品实现类隔离开,只依赖产品接口(抽象产品),产品实现类如何改动与消费者完全无关。
可以一定程度增加扩展性,若增加一个产品实现,只需要实现产品接口,修改工厂创建产品的方法,消费者可以无感知(若消费者不关心具体产品是什么的情况)。
可以一定程度增加代码的封装性、可读性。清楚的代码结构,对于消费者来说很少的代码量就可以完成很多工作。
另外,抽象工厂才是实际意义的工厂模式,工厂方法只是抽象工厂的一个比较常见的情况。
抽象工厂模式(Abstract Factory Pattern)
从上面的工厂方法中的结构图中,我们可以看到其中的具体工厂A和B是两个完全独立的。两者除了都是抽象工厂的子类,没有任何其他的交集。但是,如果我们有这样一个需求:具体工厂A和B需要生产一些同类型的不同产品。那么我们就可以试试抽象工厂模式。
我们来看看抽象工厂模式是怎么定义的:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。同样在下面的结构图中,我们可以更好地解释这一定义。我们的抽象工厂中包含一系列的去构造一个抽象产品的方法,而具体产品的实现则是放在了具体工厂中进行。
代理模式
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子。
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类或者是继承相同父类.
下面举个案例来解释:
模拟保存动作,定义一个保存动作的接口:IUserDao.java,然后目标对象实现这个接口的
方法UserDao.java,此时如果使用静态代理方式,就需要在代理对象(UserDaoProxy.java)中也实现IUserDao接口.调用的时候通过调用代理对象的方法来调用目标对象.
需要注意的是,代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用
目标对象的方法
动态代理
代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建
代理对象/目标对象实现的接口的类型)
动态代理也叫做:JDK代理,接口代理
JDK中生成代理对象的API代理类所在包:java.lang.reflect.Proxy
JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为:
ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。
12. mongodb和oracle的区别
在MongoDB中,文档是对数据的抽象,它被使用在Client端和Server端的交互中。所有的Client端(各种语言的Driver)都会使用这种抽象,它的表现形式就是我们常说的BSON(Binary JSON )。
BSON是一个轻量级的二进制数据格式。
MongoDB能够使用BSON,并将BSON作为数据的存储存放在磁盘中。
当Client端要将写入文档,使用查询等等操作时,需要将文档编码为BSON格式,然后再发送给Server端。同样,Server端的返回结果也是编码为BSON格式再放回给Client端的。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,是一个基于分布式文件存储的数据库。面向集合存储,易存储对象类型的数据。
13. Map的遍历方式?
有两种:一种是迭代器遍历entrySet(),一种是获取key赋值到set中keySet();
Iterator it =map.keySet().iterator();
//获取迭代器
While(it.hasNext()){
Object key = it.next();
System.out.println(map.get(key));
}
Set<Map.Entry<K,V>> entrySet();
Iterator it = map.entrySet().inerator();
While(it.hasNext()){
Entry e = (Entry) it.next();
System.out.println(“键”+e.getKey()+”的值为”+e.getValue());
}
//推荐
Iterator<Entry<Integer,String>> Iterator = map.entrySet().iterator();
While(Iterater.hasNext()){
Entry<Integer,String> entry = iterator.next();
System.out.prinyln(entry.getKey()+entry.getValue());
}
14.关于map?
HashMap是最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。因为键对象不可以重复,所以HashMap最多只允许一条记录的键为Null,允许多条记录的值为Null,是非同步的。
Hashtable
Hashtable与HashMap类似,是HashMap的线程安全版,它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,它继承自Dictionary类,不同的是它不允许记录的键或者值为null,同时效率较低。
ConcurrentHashMap
线程安全,并且锁分离。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
ConcurrentHashMap锁的方式是稍微细粒度的。ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。
LinkedHashMap
LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先得到的记录肯定是先插入的,在遍历的时候会比HashMap慢,有HashMap的全部特性。
TreeMap
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。不允许key值为空,非同步的。
15.@Configuration 告诉Spring这是一个配置类。
16.@SpringBootApplication什么意思?分为三个注解?
-----@SpringBootApplication 是SpringBoot的入口类注解,它又分为三个子注解:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
…
}
@SpringBootConfiguration
读取配置文件,配置文件的路径是当前根目录(src/main/resources/application.yml等)
@EnableAutoConfiguration
开启自动配置,扫描当前的所有依赖的jar包,发现新的依赖出现将会将会根据依赖完各种自动配置(扫描start_web,自动配置内置tomcat默认路径、端口;依赖了rabbitmq,自动配置rabbitTemble)
@ComponetScan
属于Spring框架(@Component,@Service,@Controller,@Repository,@Entity),扫描范围默认情况下是启动类坐在的同名包及其子孙包。
其实下边才是精辟的知识点!!!!!!
17.String的常用方法?
-----Length 查看字符串的长度 返回值是int类型
EqualsIgnoreCase 比较两个字符串,不考虑大小写 返回值是布尔类型的
Equals 比较两个字符串 返回值是布尔类型
EndsWith 测试字符串是否是以自定的后缀结束的 返回值是布尔类型
CharAt 返回指定索引处的char值 返回是一个char
GetChars(int begin,int end,char[] char) 将字符从此字符串复制到目标字符数组
SubString(int begin,int end) 返回一个新字符串,根据两个索引
IndexOf() 返回自定字符串第一次出现的索引,两个参数的话是从第几个开始搜索
IsEmpty() 当且仅当length()为0时返回true。
LastIndexOf() 返回自定字符串最右边出现处的索引
Split() 根据此字符串拆分此字符串 返回的是String数组
StartWith() 测试字符串是否是指定的前缀开始
18.Linux怎样查询一个java正在运行?
-----在linux下查看多有java进程命令:ps -ef | grep java
停止特定java进程命令:kill -9 java进程序号
停止所有java进程命令:pkill -9 java
19.Linux的日志查询命令?
-----Tail -f filename // 查看文件的尾部内容 默认10行
Tail -n 20 filename // 显示filename最后20行
hand 仅仅显示前面的几行
hand -n 10 test.log // 查询日志文件中的头10行
hand -n -10 test.log //查询日志文件除了最后10行的其它所有日志
set -n ‘5,10p’ filename //查看文件的第5行到第10行
grep cat 等其它命令
20.抽象类和接口有什么区别?
抽象类和接口的区别
一 接口和抽象类的相似性
1 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。
2 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
二 接口和抽象类的区别
1 (不能为普通方法提供方法体)接口里只能包含抽象方法,静态方法和默认方法(加default),不能为普通方法提供方法实现,抽象类则完全可以包含普通方法,接口中的普通方法默认为抽象方法。
2 .(public static final 赋值)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的,并且必须赋值,否则通不过编译。
3 (是否有构造器)接口不能包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
4 .(不能包含初始化块)接口里不能包含初始化块,但抽象类里完全可以包含初始化块。
- (继承一个抽象类、多个接口)一个类只能继承一个抽象类,而一个类却可以实现多个接口。
什么时候使用抽象类和接口
如果你拥有一些方法并且想让他们中的一些有默认实现,那么使用抽象类吧。
如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
额外总结:
静态初始化块在类第一次加载时执行,且只执行一次。
非静态初始化块在构造器之前执行但前提是要调用构造方法。
静态初始化块》》非静态初始化块—构造器
非静态初始化块在构造器前面执行就想着不实例化也能执行…原来就算顺序是这样,也要初始化,不然无法执行初始化块。好坑的…(如标记11)
//非静态初始化块能初始化静态变量,也可以初始化实例变量。(顺序问题但是前提是得通过实例化来调用构造方法,内存中还没有这个实例变量,非静态变量依赖于对象存在。)
//静态初始化块可以初始化静态变量,但是不能初始化实例变量。和静态初始化块的加载时间有关
21.项目部署的流程?
1.安装JDK,并且设置JAVA_HOME、CLASSPATH等环境变量
2.安装tomcat,并且设置TOMCAT_HOME、添加tomcat相应路径到CLASSPATH中(由于启动tomcat时需要加载JAVA_HOME等环境变量)
3.安装mysql数据库
1.从myeclipse中将项目导出war文件
2.将导出的项目war文件放导服务器tomcat目录下webapp里面
3.修改tomcat的配置文件,打开tomcat目录下的conf文件,找到server.xml,用记事本打开
此时,我们就可以通过域名访问我们的项目了。
sql语句编写?
表的列名是 id name jibie
mysql怎样触发行锁和表锁?
innodb和myisam的区别?
InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。
以下是一些细节和具体实现的差别:
◆1.InnoDB不支持FULLTEXT类型的索引。
◆2.InnoDB 中不保存表的具体行数,也就是说,执行select count() from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含 where条件时,两种表的操作是一样的。
◆3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
◆4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
◆5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
另外,InnoDB表的行锁也不是绝对的,假如在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”
两种类型最主要的差别就是Innodb 支持事务处理与外键和行级锁.而MyISAM不支持.所以MyISAM往往就容易被人认为只适合在小项目中使用。
我作为使用MySQL的用户角度出发,Innodb和MyISAM都是比较喜欢的,但是从我目前运维的数据库平台要达到需求:99.9%的稳定性,方便的扩展性和高可用性来说的话,MyISAM绝对是我的首选。
原因如下:
1、首先我目前平台上承载的大部分项目是读多写少的项目,而MyISAM的读性能是比Innodb强不少的。
2、MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。能加载更多索引,而Innodb是索引和数据是紧密捆绑的,没有使用压缩从而会造成Innodb比MyISAM体积庞大不小。
3、从平台角度来说,经常隔1,2个月就会发生应用开发人员不小心update一个表where写的范围不对,导致这个表没法正常用了,这个时候MyISAM的优越性就体现出来了,随便从当天拷贝的压缩包取出对应表的文件,随便放到一个数据库目录下,然后dump成sql再导回到主库,并把对应的binlog补上。如果是Innodb,恐怕不可能有这么快速度,别和我说让Innodb定期用导出xxx.sql机制备份,因为我平台上最小的一个数据库实例的数据量基本都是几十G大小。
4、从我接触的应用逻辑来说,select count(*) 和order by 是最频繁的,大概能占了整个sql总语句的60%以上的操作,而这种操作Innodb其实也是会锁表的,很多人以为Innodb是行级锁,那个只是where对它主键是有效,非主键的都会锁全表的。
5、还有就是经常有很多应用部门需要我给他们定期某些表的数据,MyISAM的话很方便,只要发给他们对应那表的frm.MYD,MYI的文件,让他们自己在对应版本的数据库启动就行,而Innodb就需要导出xxx.sql了,因为光给别人文件,受字典数据文件的影响,对方是无法使用的。
6、如果和MyISAM比insert写操作的话,Innodb还达不到MyISAM的写性能,如果是针对基于索引的update操作,虽然MyISAM可能会逊色Innodb,但是那么高并发的写,从库能否追的上也是一个问题,还不如通过多实例分库分表架构来解决。
7、如果是用MyISAM的话,merge引擎可以大大加快应用部门的开发速度,他们只要对这个merge表做一些select count(*)操作,非常适合大项目总量约几亿的rows某一类型(如日志,调查统计)的业务表。
当然Innodb也不是绝对不用,用事务的项目如模拟炒股项目,我就是用Innodb的,活跃用户20多万时候,也是很轻松应付了,因此我个人也是很喜欢Innodb的,只是如果从数据库平台应用出发,我还是会首选MyISAM。
另外,可能有人会说你MyISAM无法抗太多写操作,但是我可以通过架构来弥补,说个我现有用的数据库平台容量:主从数据总量在几百T以上,每天十多亿 pv的动态页面,还有几个大项目是通过数据接口方式调用未算进pv总数,(其中包括一个大项目因为初期memcached没部署,导致单台数据库每天处理 9千万的查询)。而我的整体数据库服务器平均负载都在0.5-1左右。
怎样实现线程的互换?
为什么redis不用锁?
关于线程?
创建线程的两种方式?
通过继承Thread类实现;
通过实现Runnable接口实现;
通过Callable接口和FutureTask 类接口创建线程;
void start():启动一个新的线程,start方法必须子线程第一个调用的方法,start不能够重复调用,新线程会调用runnable接口提供的run方法
● void run():run方法是子线程的执行体,子线程从进入run方法开始直至run方法执行接收意味着子线程的任务执行接收,在主线程直接调用run方法是不能创建子线程,只是普通方法调用
● yield(); 让步或者暂停:,Thread类的静态方法。让正在执行的线程停止或者让步,让给优先级较高的线程获取CPU的执行权,(不一定会让出CPU执行权,如等地的线程优先级较低或者当前只有一个线程在执行时,那么当先线程又会立即获取CPU的执行权)
thread.yield() thread线程 != 正在执行的线程
● sleep(long millis)
sleep方法作用是让线程进行休眠,即让线程阻塞住,Thread类提供的静态方法,会抛出InterruptedException异常
● join():等待线程执行结束才继续执行.会抛出 InterruptedException异常
假如在a线程中b线程进行b.join调用,a线程等待b线程执行结束后才能继续执行,控制多线程按照次序执行
● interrupt(),中断方法:底层调用native方法,native方法的作用是对特定标识位做修改
主要作用于线程:运行中线程、阻塞线程(sleep、join)
运行中的线程:interrupt方法仅仅是对标志位做了修改,其他没有影响
阻塞线程:interrupt方法对标志位做了修改,另阻塞中的线程感知到标志位做了修改,就会中断当前的阻塞状态,抛出InterruptedException异常
● isInterrupted:判断是否发生了中断操作,返回为Boolean,true:表示发生中断 false:表示未发生中断
● setDaemon(boolean on):设置守护线程 ,true:设置为守护线程 false:用户线程 默认就是用户线程
● isDaemon():判断当前线程是否为守护线程,返回Boolean类型 true:守护线程 false:非守护线程
● setPriority(int newPriority)设置线程优先级,优先级分为10级,优先级数字越大,即优先级越高,优先级越高,被优先调用的概率会。
内部类不能声明静态变量。
死锁问题?
怎样检查java中是否有死锁情况?
定位死锁:
第一种:
1.利用jdk提供的工具定位死锁问题(首先进入CMD工具,再进入JDK的安装文件夹中的bin目录,执行jps命令)
2.jps显示所有当前Java虚拟机进程名及pid.(得到运行的线程Run的id值是12336.再执行jstack命令,)
3.jstack打印进程堆栈信息。
4.列出所有java进程。
5.我们检查一下DeadLockDemo,为什么这个线程不退栈。
我们直接翻到最后:已经检测出了一个java级别死锁。其中两个线程分别卡在了代码第38行和第24行。检查我们代码的对应位置,即可排查错误。此处我们是第二个锁始终拿不到,所以死锁了。
第二种
WIN+R,输入jconsole,
连接到需要查看的进程
打开线程选项卡,点击左下方的”检测死锁”
可以查看死锁的线程及其信息,
死锁一旦发生,我们就无法解决了。所以我们只能避免死锁的发生。
既然死锁需要满足四种条件,那我们就从条件下手,只要打破任意规则即可。
(互斥)尽量少用互斥锁,能加读锁,不加写锁。当然这条无法避免。
(请求和保持)采用资源静态分配策略(进程资源静态分配方式是指一个进程在建立时就分配了它需要的全部资源).我们尽量不让线程同时去请求多个锁,或者在拥有一个锁又请求不到下个锁时,不保持等待,先释放资源等待一段时间在重新请求。
(不剥夺)允许进程剥夺使用其他进程占有的资源。优先级。
(循环等待)尽量调整获得锁的顺序,不发生嵌套资源请求。加入超时。
arraylist和 LinkedList
- ArrayList的实现是基于数组来实现的,LinkedList的基于双向链表来实现。这两个数据结构的逻辑关系是不一样,当然物理存储的方式也会是不一样。
- 对于随机访问,ArrayList优于LinkedList。
- 对于插入和删除操作,LinkedList优于ArrayList
- LinkedList比ArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
hashmap和hashtable?
1、HashMap几乎可以等价于HashTable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而HashTable则不行)。
2、HashMap是非synchronized,而HashTable是synchronized,这意味着HashTable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
3、另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而HashTable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
4、由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。
5、HashMap不能保证随着时间的推移Map中的元素次序是不变的。
springmvc的流程
2.SpringMVC处理请求的流程
2.1 首先用户发送请求–>DispatherServlet
2.2 DispatcherServlet–>HandlerMapping
2.3 DispatcherServlet–>HandlerAdapter
2.4 HandlerAdapter–>处理器功能处理方法的调用
2.5 ModelAndView的逻辑视图名–>ViewRecolver
2.6 View–>渲染
2.7 返回控制权给DispatcherServlet,由DispatcherServlet返回呼应给用户,流程结束。
3. SpringMVC核心开发步骤
3.1 DispatcherServlet在web.xml中的部署描述,从而拦截请求到springMVC
3.2 HandlerMapping的配置,从而将请求映射到处理器
3.3 HandlerAdapter的配置,从而支持多种类型的处理器
3.4 处理器(页面控制器)的配置,从而刊行功能处理
3.5 ViewResolver的配置,从而将逻辑视图名解析为具体的视图技术
-
SpringMVC的组件
4.1 前端控制器(DispatcherServlet)
4.2 请求到处理器映射(HandlerMapping)
4.3 处理器适配器(HandlerAdapter)
4.4 视图解析器(ViewResolver)
4.5 处理器或页面控制器(Controller)
4.6 验证器(Validator)
4.6 命令对象(Command 请求参数绑定到的对象就叫命令对象)
4.7 表单对象(Form Object提供给表单展示和提交到的对象就叫表单对象) -
常用注解
5.1 @Controller:用于标识处理器类
@RestController注解相当于@ResponseBody + @Controller合在一起的作用
5.2 @RequestMapping:(窄化路径)请求到处理器功能方法的映射规则,可定义到类和方法
常用参数:value、method
可将@RequestMapping标签定义到类名处窄化路径
5.3 @RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定
常用参数:value、required、defaultValue
注:required设置成false的参数类型必须是引用类型,因为基本数据类型是不能为null的
5.4 @ModelAttribute:请求参数到命令对象的绑定
常用参数:value
5.4.1 可用@ModelAttribute标注方法参数,方法参数会被添加到Model对象中(作用:向视图层传数据)
5.4.2 可用@ModelAttribute标注一个非请求处理方法,此方法会在每次调用请求处理方法前被调用(作用:数据初始化)
5.4.3 可用@ModelAttribute标注方法,方法返回值会被添加到Model对象中(作用:向视图层传数据)
但此方法视图的逻辑图就会根据请求路径解析,例如:a/test42 --> /WEB-INF/a/test42.jsp
太麻烦几乎不用,不用直接保存到Model或ModelAndView中
5.5 @SessionAttributes:指定ModelMap中的哪些属性需要转存到session
常用参数:value、types
注1:必须放到class类名处
5.6 @InitBinder:用于将请求参数转换到命令对象属性的对应类型
例如:日期格式到后台的数据转换
birthday=2000年10月10日 --> java.util.Date birthday;
5.7 @RequestBody(重要):用于目前比较流行的ajax开发的数据绑定(即提交数据的类型为json格式)
-
SpringMVC核心开发步骤
3.1 DispatcherServlet在web.xml中的部署描述,从而拦截请求到springMVC
3.2 HandlerMapping的配置,从而将请求映射到处理器
3.3 HandlerAdapter的配置,从而支持多种类型的处理器
3.4 处理器(页面控制器)的配置,从而刊行功能处理
3.5 ViewResolver的配置,从而将逻辑视图名解析为具体的视图技术 -
SpringMVC的组件
4.1 前端控制器(DispatcherServlet)
4.2 请求到处理器映射(HandlerMapping)
4.3 处理器适配器(HandlerAdapter)
4.4 视图解析器(ViewResolver)
4.5 处理器或页面控制器(Controller)
4.6 验证器(Validator)
4.6 命令对象(Command 请求参数绑定到的对象就叫命令对象)
4.7 表单对象(Form Object提供给表单展示和提交到的对象就叫表单对象) -
常用注解
5.1 @Controller:用于标识处理器类
@RestController注解相当于@ResponseBody + @Controller合在一起的作用
5.2 @RequestMapping:(窄化路径)请求到处理器功能方法的映射规则,可定义到类和方法
常用参数:value、method
可将@RequestMapping标签定义到类名处窄化路径
5.3 @RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定
常用参数:value、required、defaultValue
注:required设置成false的参数类型必须是引用类型,因为基本数据类型是不能为null的
5.4 @ModelAttribute:请求参数到命令对象的绑定
常用参数:value
5.4.1 可用@ModelAttribute标注方法参数,方法参数会被添加到Model对象中(作用:向视图层传数据)
5.4.2 可用@ModelAttribute标注一个非请求处理方法,此方法会在每次调用请求处理方法前被调用(作用:数据初始化)
5.4.3 可用@ModelAttribute标注方法,方法返回值会被添加到Model对象中(作用:向视图层传数据)
但此方法视图的逻辑图就会根据请求路径解析,例如:a/test42 --> /WEB-INF/a/test42.jsp
太麻烦几乎不用,不用直接保存到Model或ModelAndView中
5.5 @SessionAttributes:指定ModelMap中的哪些属性需要转存到session
常用参数:value、types
注1:必须放到class类名处
5.6 @InitBinder:用于将请求参数转换到命令对象属性的对应类型
例如:日期格式到后台的数据转换
birthday=2000年10月10日 --> java.util.Date birthday;
5.7 @RequestBody(重要):用于目前比较流行的ajax开发的数据绑定(即提交数据的类型为json格式)
什么是ORM?
对象关系映射(Object -Relational Mapping 简称ORM)是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术;
简单的说,ORM是通过使用描述对象和数据库之间映射的元数据(在java中可以用XML或者是注解),将程序中的对象自动持久化到关系型数据库或者将关系型数据表中行数据转换成java对象,其本质上就是将数据从一种形式转换成另一种形式;
是不是觉得很有营养呢!!!!!下边的更有营养!!!!
解释一下MyBatis中命名空间(namespace)的作用?
在大型形目中,可能存在大量的SQL语句,这时候为每个SQL语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个SQL语句就成了定义在这个命名空间中的一个ID。只要我们保证每个命名空间中这个ID是唯一的,即使在不同映射文件中语句ID相同,也不会产生冲突。
MyBatis中动态SQL?
对于复杂的查询,我们可能会指定多个查询条件,但是这些条件可能存在也可能不存在,如果不使用持久层框架我们就需要自己拼装SQL语句,不过MyBatis提供了动态SQL的功能来解决这个问题。MyBatis中用于实现动态SQL的元素:
伪代码:
Select * from t_user where 1=1
<if test=”name!=null”>
And name=#{name}
<if test=”address!=null”>
And address =#{ address }
注意这里传过来的参数 提前需要做过拼接“%”+name+”%”
spring框架的认识?
轻量级的
IOC:控制反转,把以前程序员需要new对象的权利交由spring工厂来创建,弱耦合
DI:依赖注入,,Spring工厂不仅要创建对象 还维护类与类之间 类与类中属性之间依赖关系 。
Set注入:通过反射创建对象,调用set方法为属性赋值;
构造注入:通过反射创建对象,加载无参构造方法来为属性进行赋值;
自动装配:在bean标签上面配置,底层也是set注入进行赋值;
AOP:代理设计模式,支持面向切面编程,把业务逻辑和服务器分开。
静态代理:编译时以有代理类
动态代理:编译时没有代理类
JDK动态代理(基于接口)
Cglib动态代理(基于父类)
MVC框架:Spring的web框架是一个精心设计的框架,是web框架的一个很好的代替品
事务管理:Spring提供一个持续的事务管理接口,可以扩展事务
什么是Spring beans?
Spring beans是那些形成Spring应用的主干java对象。他们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中的形式定义。
Spring框架定义的beans嗾使单间beans。在bean tag 中有个属性singleton,它如果赋值为true,bean就是单间,否则就是一个prototype bean。默认是true,所以在Spring框架中的beans缺省都是单件
Spring bean的生命周期?
-
Spring容器从XML文件中读取bean的定义,并实例化bean。
-
Spring根据bean定义填充所有的属性。
-
如果bean实现了BeanNameAware接口,Spring传递bean的ID到setBeanName方法
-
如果bean实现了BeanFactoryAware接口,Spring传递beanfactory给setBeanFactory方法
-
如果没有任何与bean相关联的BeanPostProcessors,Spring会在postProcessAfterlnitialization()方法内调用他们
-
如果bean实现了lntializingBean,调用它的afterPropertySet方法,如果声明了初始化方法,调用此初始化方法
-
如果有BeanPostProcessors和bean关联,这些bean的postProcessAfterInitialization()方法将被调用
-
如果bean实现了DisposableBean,他将调用destroy()方法。
Spring支持的集中bena的作用域
Spring框架支持物种作用域
- Singleton:bean在每个Spring IOC容器中只有一个实例;
- Prototype:一个bean的定义可以有很多个实例。
- Request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
- Session:在一个Http Session中,一个bean定义对应一个实例。该作用域在基于web的Spring ApplicationContext情形下有效
- Global-session:在一个全局的Http Session中,一个bean定义对应一个实例,该作用域在基于Spring ApplicationContext情形下有效
list map set
List: 元素按顺序存储(有下标),元素可重复
a. ArrayList: 数组实现,查询快,增删慢,线程不安全 ,并发效率高;
b. Vetor: 数组实现 线程安全,并发效率低;
c. LinkedList: 双向链表实现,查询慢,增删快 不安全
d. copyOnWriteArrayList 是 list 的实现类,牺牲了写的效率提高了读的效率
Set:无序,五下标,元素不能重复
a. HashMap:重复的对象只有一个,顺序按hashCode值排列
b. LinkedHashSet:由链表组成,HashSet的子类 维护元素的顺序
c. TreeSet:排序的集合
a. hashMap: 数组加链表,线程不安全,键和值都可以是空,并发效率高
b. Hashtable: key和value不能为null,线程安全,并发效率低
c. LinkedHashMap:维护添加元素的顺序
d. TreeMap: 自动排序
e. Propweties:Hashtable的子类,key和value都是字符串,一般用在配置文件处理
集合接口和类的总结
f. ConcurrentHashMap:分段锁,并发执行给每段枷锁
Collection
|-- List (ArrayList LinkedList Vector copyOnWriteArrayList)
|-- Set (HashSet LinkedHashSet copyOnwriteArraySet)
|–SortedSet(TreeSet)
|-- Queue (LinkedList ConcurrentLinkedQueue)
|–BlockingQueue (ArrayBlockingQueue LinkedBlockingQueue)
Map (HashMap LinkedHashMap Hashtable properties ConcurrentHashMap)
|–SortedMap(TreeMap)
线程:
创建线程的两种方式:
- 继承Thread类,覆盖run方法
- 实现Runnable接口,覆盖run方法
线程,一个程序顺序执行款流程。进程由多个线程组成,彼此完成不同的工作,交替执行成为多线程
线程的状态
a. 初始状态(new线程对象被创建,就是初始状态,只在堆中开辟内存,与一般对象无异)
b. 就绪状态(ready调用start()之后,进入就绪状态,等待OS选中,并分配时间片)
c. 运行状态(获得时间片之后,进入运行状态,时间片到期,回到就绪状态)
d. 等待状态(join()无期限等待,Thread.sleep()填入毫秒,或抛出异常)
e. 终止状态(主线程main()或独立线程run()结束进入终止状态,释放持有的时间片)
每个 java 对象都有一个互斥锁标记,用来分配给线程
synchronized(o){同步代码块} 对 o 加锁的同步代码块,只有拿到 o 的锁标记的
线程,才能进入对 o 加锁的同步代码块。o 就是临界资源(多个线程共同访问同一个资源) 同步代码块就是原子操作(临界资源中不可分割的操作)
线程通信
This.wait(): 必须出现在对O枷锁的同步代码块
线程会释放拥有的所有所标记,进入等待状态(失去所标记和cpu)
This.notify()/notifyAll():从等待状态中释放一个/全部线程,必须出现在对O枷锁的同步代码块
开发者使用notifyAll()多,没办法确定某一个出来
####线程的三个核心概念:
- 原子性:一个操作要么全部执行,要么全部不执行
- 可见性:当多个线程并发访问共享变量时,一个线程对公共变量的修改,其他线程能够立即看到
- 顺序性:程序执行的顺序按照代码的先后顺序执行
处理器为了提高程序整体的执行效率,可能对代码进行优化,调整代码顺序,按照更加高效的顺序执行代码。
线程池
池:资源的重复利用
ForkJoinPool
ExecutorService(线程池接口)
ExecutorSercive es = Executors.newCachedThreadPool();
Callable<V> Future来装线程的返回值,异步通信
Lock对象
JDK5.0加入的,与synchronized比较
结构灵活,提供更多实用性方法,性能更优越,功能更强大
void lock()//获取锁,如果锁被占用,则等待
boolean tryLock()//尝试获取锁,成功返回 true,失败返回 false
void unlock()//释放锁
Lock中有一个newCondition()方法,返回值是一个Condition对象 :等待队列
volatile关键字
保证了可见性,用它修饰的变量,被修改的变量会立即被更新到内存中,并将该变量的所有缓存设为无效,恰线程读取时必须从主内存中读取,从而拿到最新的值
Oracle
操作数据库
Oracle中拼接 ||
数据去重
Select distinct 字段名 from 表名 (一般distinct一般后面只跟一个字段)
空值查询
Select * from 表名 where 字段名 is null (is not null 非空查询)
多条件查询(查询值为值1或者值为值2的数据)
Select * from 表名 where 字段名 =值1 or 字段名 =值2
区间查询(查询字段的值在值1和值2之间的数据)
Select * from 表名 wnere 字段名 between 值1 and 值2
枚举查询(查询在值1,值2,值3里面的数据)
Select * from 表名 where 字段名 in(值1,值2,值3)
模糊查询
Select * from 表名 where 字段名 like ‘%_abc%’
(_表示任意字符;%表示任意字符串)
分支查询
Select *
Case
when 条件 then 表达式
when 条件 then 表达式
else表达式
end
from employees
例:select first_name,salary,
case
when salary >= 10000 then ‘高收入’
when salary>=5000 then ‘中等收入’
else ‘低收入’
end as l
from employees;
把人员的工资分为 高收入,中等收入,低收入三种情况
排序
Selcet 字段名 from 表名
Where 条件
Order by 排序的字段名 desc(降序) | asc(升序,默认就是升序)
当排序的字段的值相同的情况下,想按着另外的顺序进行排序:
order by 字段名1 desc,字段名2 asc;—首先按着薪资降序排,当多个人的薪资相同了,这些相同的人员信息按着字段名2的字典顺序进行升序排列。
关键字
Dual 哑表:当查询语句中没有目标表的时候在from后面加上
Select sysdate from dual 查询系统当前时间
Oracle中的函数
Length()==返回实参这个字符串长度
Select * from 表名 where length(字段名1)>10
这句sql是查询字段名1这一列的长度超过10的数据
Mod()==求余数
Select * from 表名where mod(id,2)=0
查询id尾号为偶数的数据
组函数 :多行数据运行完组函数后,返回一个结果
Max : 最大值
Min : 最小值
Avg : 平均值
Sum : 总和
Count : 总行数
使用组函数后系统会自动排除值为的数据
分组查询
Select 分组字段,组函数 from 表名
where 条件
group by 分组字段
order by 排序字段
注意事项:
Select 后面值能跟分组的字段和组函数
分组查询后的过滤
Select 字段名 from 表名
Where 分组前的排除
Group by 分组字段
Having 分组后的过滤
注意:
Having用于分组后 where用于分组前
下边的是程序员都必要要知道的东西!!!!!!
数据库优化手段
- 索引优化
- 添加查询缓存
- 优化数据库的sql语句
- 数据库Cluster
索引优化:
- 作用:加快以索引字段为条件的查询效率
- 创建索引: create index idx 名字 on 表(字段)
- 删除索引: drop index idx 名字
- 查询某张表创建了那些索引: show index from 表名
- 特点
① 索引会占用存储空间,比较少
② MySQL会自动为primary列和unqiue列自动增加索引
③ MySQL数据库对数据做了DML(增删改)操作,需要同时做维护索引的操作,
索引会降低数据库的增删改的效率 - 使用原则:
一般对sql中的where条件字段或者order by字段建立索引
查询缓存:
- 在数据库操作对象DAO出增加查询缓存
- 注意数据的一致性,
① 支队查询结果进行缓存
② 缓存结果存放以业务逻辑相关为划分单位。 - 当执行增删改的时候,为了避免出现脏数据
- 缓存的原则时对那些查询需求远大于增删改需求的数据,进行缓存
SQL优化:
- 尽量不要给sql语句子句中使用函数,这样会使索引失效
- 如果已经确定查询结果只有一条数据,在查询的sql末尾添加limit 1,这样MySql的查询执行引擎在找到这条数据后会停止搜索,提高效率
- 模糊查询尽量使用右模糊:“xxx%”,“%xxx”会使该查询字段上的索引失效
- 如果非要使用表连接,最好这两个字段都是创建了索引的
String StringBuffer String builder的区别?
String对象不可变,在进行任何内容修改时都会创建新的字符串对象,一旦修改操作过多,就会造成大量的资源浪费
StringBuffer StringBuilder在进行字符串拼接的时候不会创建新的字符串对象,而是在原有对象上修改,不同的是StringBuffer的线程安全,StringBuilder线程不安全。
创建字符串对象的两种方式:字面值,new一个新的对象
String Pool串池:保存通过字面赋值的所有String对象,
Java有没有goto?
有,这个是保留字,现在不用了
一个”java”源文件中可以又几个类?有什么限制?
可以又多个类,只能由一个public修饰的类,并且类名与文件名要一致
short i=1,i=i+1;short j=1,j+=1;哪个会报错?
i+1的结果为int类型(运算时自动提升类型),而int转short类型或报错
+=是java中的运算符,java编译器会对他特殊的处理
用最有效的方法计算2乘以8等于几?
2<<3,将一个数左移n位,就相当于乘以了2的n次方。
Cpu支持移位运算,效率最高,
使用final修饰的变量有什么特点?final,finally,finallze的区别?
被final修饰的变量,变量不能变 。内部类要访问局部变量时,局部变量必须被final修饰
Finally 是异常处理语句中的结构,表示总是执行
Finalize是一个方法,在垃圾收集器执行的时候会被调用,如果覆盖了此方法,JVM不一定此方法总会被调用
heap和stack有什么区别?
java的内存分为两类,一类是栈内存,一类是堆内存。栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。
堆是与栈作用不同的内存,一般用于存放不在当前方法栈中的那些数据,例如,使用new创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量使用final修饰后,放在堆中,而不是栈中。
abstractclass和interface语法上有什么区别?
抽象类可以有构造方法,接口中不能有构造方法。
抽象类中可以有普通成员变量,接口中没有普通成员变量
抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然
eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
抽象类中可以包含静态方法,接口中不能包含静态方法
抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是publicstatic final类型,并且默认即为publicstatic final类型。
一个类可以实现多个接口,但只能继承一个抽象类。
Overload和Override的区别?Overloaded的方法是否可以改变返回值的类型?
Overload是重载的意思,Override是覆盖的意思,也就是重写。
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
override覆盖,它是覆盖了一个方法并且对其重写,以求达到不同的作用。
覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
覆盖的方法的返回值必须和被覆盖的方法的返回一致;
覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
Redis
Redis特点:
- 内存数据库,速度快,支持持久化,将内存中的数据保存在磁盘上;
- Redis不仅仅支持key-value类型的数据,还提供list(可重复的集合类型),set(不能重复的集合类型),zset(可以排序的set集合),hash(value是一个map类型)等数据结构的存入
- 支持数据备份
- 支持事务
Redis持久化: - RDB持久化,制定的时间间隔内生成快照
- AOF持久化,记录服务器执行的所有写操作,在服务器启动时,重新执行这些代码来进行数据还原
- AOF和RDB同时使用时优先使用AOF(aof保存的数据相对完整)
(RDB优劣:大批量恢复数据,并且对数据完整性不严可以使用RDB,他的最后一次持久化数据可能丢失)
RDB: redis创建子进程来进行持久化,想将数据写入一个文件中,持久化结束了,再用这个文件替换上次持久化的文件
(AOF优点 通过AOF持久化让redis变得耐久;aof文件过大时,自动重写;aof文件有序的保存了数据库执行的所有写操作,易读)
AOF: 一日志的方式记录每个写操作,将redis执行过的所有写操作都记录下来,redis启动时就会读取文件将执行的命令全部执行一次完成数据还原
AOF与RDB比较?
数据相同,AOF文件大于RDB文件
AOF的速度可能慢于RDB
Redis 的常用操作
Set str str 往redis中添加一个字符串数据结构的key-value
Get str根据key获取对应的value
Keys * 获取到所有的key
Select dbindex选择数据库
SpringMVC与struts2都是用了mvc框架,有啥区别?
接收参数:springMVC通过方法形参接收参数,struts2通过声明成员变量,提供get/set方法来接受参
跳转:struts2通过struts.xml中配置来进行转跳控制,springMVC中通过方法返回值/注解(常用)来进行控制跳转
数据传输:struts2中使用值栈,springMVC中使用各种作用域
V进入C:struts2中通过核心过滤器,进入strut.xml中找到匹配配置,进入对应的action,springMVC中在web.xml中配置找到springmvc配置文件/注解(常用)
springMVC运行效率比struts2高
解释说明Integer和int在开发应用中的区别?
Integer int
Integer默认值为null 默认值为0
Int的包装类 原始数据类型
请使用Java实现数组的排序
冒泡 : for(int I = 0 ; i<array.length; i++){
For(int j = 0 ; j<array.length-1-I ; j++){
If(array[j]>array[j+1]){
Int a = array[j];
Array[j] = array[j+1];
Array[j+1] = a;
}
}
}
排序 : for(int i = 0 ;i<array.length ;i++){
For(int j = i+1 ; j<array.length ; j++){
If(array[i]>array[j]){
Int a = array[i];
Array[i] = array[j];
Array[j] = a ;
}
}
}
工厂模式和代理模式
工厂模式:一个面条加工工厂,可以加工出来兰州拉面、重庆小面、方便面等多种多样的面条。就是一个抽象类(面),多个实体类(各种面条类),一个面条工厂(有一个create方法,创造面条,利用if或者 switch创建产品并返回)。这个面条工厂只负责加工面条(new一个对象),然后把它加工的面条给你(返回创建的对象),不负责面条的加葱花,加辣(执行对象自己的方法)
代理模式:一个班交班费,都是班长代理收费。就是一个person抽象类,多个学生类,一个班长代理(内置person属性),这个班长代理只负责拿到学生名单(初始化时,自己传一个person对象过去),拿走学生的money(执行person对象的方法),但是它不负责创造一个学生对象,(班长代理也创造不了,哈哈)
工厂模式与代理模式的区别,感觉就是工厂的各种面条,比如兰州拉面、重庆小面等,都是面条加工厂(工厂)制造的(由create制造)。而代理模式,则是传给班长(代理)一个同学(对象),班长代理就会替你把钱给交了(执行某些方法)。
工厂模式有三种实现,简单工厂模式,工厂方法模式,抽象工厂模式。
cglib动态代理和jdk动态代理(jdk的代理原理是只代理接口不代理类,Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的代理使用CGLIB来实现)。
通过生成被代理类的【子类】实现代理,所以 Cglib是无法代理final修饰的方法或类
Cglib和jdk动态代理的区别?
a) Jdk动态代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
b) Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理
c) 什么时候用cglib什么时候用jdk动态代理
i. 目标对象生成了接口 默认用JDK动态代理
ii. 如果目标对象使用了接口,可以强制使用cglib
iii. 如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换
d) JDK动态代理和cglib字节码生成的区别?
i. JDK动态代理只能对实现了接口的类生成代理,而不能针对类
ii. Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的
e) Cglib比JDK快
i. cglib底层是ASM字节码生成框架,但是字节码技术生成代理类,在JDL1.6之前比使用java反射的效率要高
ii. 在jdk6之后逐步对JDK动态代理进行了优化,在调用次数比较少时效率高于cglib代理效率
iii. 只有在大量调用的时候cglib的效率高,但是在1.8的时候JDK的效率已高于cglib
iv. Cglib不能对声明final的方法进行代理,因为cglib是动态生成代理对象,final关键字修饰的类不可变只能被引用不能被修改
f) Spring如何选择是用JDK还是cglib
i. 当bean实现接口时,会用JDK代理模式
ii. 当bean没有实现接口,用cglib实现
iii. 可以强制使用cglib(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)
Cglib是什么?
一. Cglib原理
动态生成一个要代理的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,它比Java反射的jdk动态代理要快
Cglib是一个强大的、高性能的代码生成包,它被广泛应用在许多AOP框架中,为他们提供方法的拦截
最底层的是字节码Bytecode,字节码是java为了保证依次运行,可以跨平台使用的一种虚拟指令格式
在字节码文件之上的是ASM,只是一种直接操作字节码的框架,应用ASM需要对Java字节码、class结构比较熟悉
位于ASM上面的是Cglib,groovy、beanshell,后来那个种并不是Java体系中的内容是脚本语言,他们通过ASM框架生成字节码变相执行Java代码,在JVM中程序执行不一定非要写java代码,只要能生成java字节码,jvm并不关系字节码的来源
位于cglib、groovy、beanshell之上的就是hibernate和spring AOP
最上面的是applications,既具体应用,一般是一个web项目或者本地跑一个程序、
使用cglib代码对类做代理?
使用cglib定义不同的拦截策略?
构造函数不拦截方法
用MethodInterceptor和Enhancer实现一个动态代理
Jdk中的动态代理
JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,但是JDK中所有要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中有一定的局限性,而且使用反射的效率也不高
Cglib实现
使用cglib是实现动态代理,不受代理类必须实现接口的限制,因为cglib底层是用ASM框架,使用字节码技术生成代理类,你使用Java反射的效率要高,cglib不能对声明final的方法进行代理,因为cglib原理是动态生成被代理类的子类
怎么使用动态代理的模式选择?
CGLib动态代理创建代理实例速度慢,但是运行速度快;JDK动态代理创建实例速度快,但是运行速度慢。如果实例是单例的,推荐使用CGLib方式动态代理,反之则使用JDK方式进行动态代理。Spring的实例默认是单例,所以这时候使用CGLib性能高。
在代码中的接口不管有没有实现接口,默认的都是cglib动态代理,如果要用jdk动态代理需要在配置文件中加入spring.aop.proxy-target-class这个属性的值。默认为true表示强制使用Cglib动态代理。
改过之后就会是实现接口的类变成了com.sun.proxy,表示使用的是JDK的动态代理。
那么使用aop时实现了接口的类就会使用JDK动态代理,没有实现接口的类仍然使用的是Cglib动态代理。
总结:
1.java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
2.JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
为什么JDK动态代理必须要实现接口?
因为java的单继承,动态生成的代理类已经继承了Proxy类,就不能再继承其他的类,要与代理类联系起来,只能实现接口
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
3.JDK动态代理与Cglib动态代理效率比较?
jdk1.7之前JDK动态代理的效率要低于Cglib,但jdk1.7之后,java做了优化JDK动态代理的效率要高于Cglib
虽然后来优化后JDK动态代理效率要高于Cglib,但并不是反射的效率要高于操作字节码。
操作字节码要效率远高于反射。
通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。
Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement,举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个、、、标签,都会被解析为一个MappedStatement对象。
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
第一种是使用标签,逐一定义列名和对象属性名之间的映射关系。
第二种是使用sql列的别名功能,将列别名书写为对象属性名,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
Xml映射文件中,除了常见的 select|insert|update|delete标签之外,还有哪些标签?
还有很多其他的标签,加上动态sql的9个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中为sql片段标签,通过标签引入sql片段,为不支持自增的主键生成策略标签
简述Mybatis的插件运行原理,以及如何编写一个插件?
Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,还需要在配置文件中配置你编写的插件。
Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
Mybatis映射文件中,如果A标签通过include引用了B标签的内容,请问,B标签能否定义在A标签的后面,还是说必须定义在A标签的前面?
虽然Mybatis解析Xml映射文件是按照顺序解析的,但是,被引用的B标签依然可以定义在任何地方,Mybatis都可以正确识别。
原理是,Mybatis解析A标签,发现A标签引用了B标签,但是B标签尚未解析到,尚不存在,此时,Mybatis会将A标签标记为未解析状态,然后继续解析余下的标签,包含B标签,待所有标签解析完毕,Mybatis会重新解析那些被标记为未解析的标签,此时再解析A标签时,B标签已经存在,A标签也就可以正常解析完成了。
简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?
Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。在Xml映射文件中,标签会被解析为ParameterMap对象,其每个子元素会被解析为ParameterMapping对象。标签会被解析为ResultMap对象,其每个子元素会被解析为ResultMapping对象。每一个、、、标签均会被解析为MappedStatement对象,标签内的sql会被解析为BoundSql对象
Struts2和springmvc区别
一、框架机制
- spring MVC是通过servlet的方式进行拦截,在第一次请求发送时初始化,并随着容器关闭而销毁。
- struts2是通过filter(拦截器)的方式进行拦截,在容器初始化时加载。晚于servlet销毁。
二、拦截机制
1.struts2 是类级别上的拦截,每次请求都会创建一个对应的action,一个url对应action中的一个方法,action类中的属性被所有方法共享,所以action在spring只能配置成多例的,因为是多例的,无法使用注解等方式开发。如果有两个请求同时访问action,则会发送线程并发,导致类属性值错乱,线程不安全。struts2通过类属性的方式接收请求参数,并通过get,set方法设置值,也可以通过模型驱动的方式注入值,action类需要继承ActionSupport实现ModelDrivenMO<T>接口。struts2使用的是值栈机制,将页面需要的值压入值栈,则可在页面上通过OGNL表达式获取。Struts2有自己的拦截机制,自定义Interceptor类,然后进行配置,配置文件非常大。
2.spring MVC是方法级别上的拦截,一个请求对应着一个controller中的方法,请求参数会封装到方法参数中,如果是对象类型的参数则需要在参数名前加上@RequestBody注解即可。controller类中的属性被方法所共享,controller类默认是单例的,在请求发送时不会创建对象,所以可以使用注解开发。spring MVC则是通过方法参数model对象来设置需要返回的值,(和request的用法相似,因为底层封装的就是request),在页面通过el表达式获取。springMVC有独立的AOP拦截机制。
三、性能方面
1.spring MVC几乎实现了零配置,在配置了基本的东西之后,再编写controller类和方法时,只需加上注解即可,无需频繁修改配置文件,而struts2的机制让他无法使用注解开发,那就需要编写一个action类配置一遍,显得非常繁琐。
四、集成
1.spring MVC和spring是同一家公司出的,所以整合时无需配置,而struts2则需要编写整合配置。
五、设计思想
1.struts2 更符合OOP编程思想,spring MVC 则是再servlet上扩展功能。
六、与ajax的集成
1.spring MVC只需要在交互方法上加上@ResponseBody即可在返回值中返回数据,spring MVC会自动将返回值数据转换成json数据。非常方便。
2.struts2则需要自己手动将返回值数据转换成json格式,再手动写回浏览器。返回 NONE;
springboot和springmvc的区别
springmvc从两个方面来看,一是spring,spring的核心中IOC和AOP,IOC就是控制反转(就是将原本由程序代码直接操作的对象的调用权交给容器),目的是为了减低计算机代码的耦合度,所谓的耦合度就是代码中的逻辑关系不要太紧密,避免后面改的人会因为不懂业务逻辑导致改错代码;除此之外也避免我们每次创建新的对象,减少对应的代码量。我们实际代码过程中最常见的方式是依赖注入(DI Dependency Injection),所谓依赖注入就是通过构造注入或者set进行注入。依赖查找(DL Dependency Lookup)这是通过名称和类型查找bean。AOP是面向切面编程,AOP分为五大部分:(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知。(2)JointPoint(连接点):程序执行中明确的点,一般是方法的调用。(3)Advice(通知):AOP在特定的切入点上做出的增强处理,有before,after,afterRunning,afterThrowing,around;(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式;(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强,Spring的AOP可以使用JDK代理,也可以使用CGLIB代理,前者基于接口,后者是基于子类。
通知类型:
(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可
(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值
(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名
来访问目标方法中所抛出的异常对象
(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式
(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint
springboot引入自动配置的概念,让项目配置变得更容易,Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的SpringBoot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。Spring Boot只是承载者,辅助开发者简化项目搭建过程的。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和SpringMVC的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。
springmvc与springboot的联系和区别:
联系:
Spring最初利用工厂模式(DI)和代理模式解耦应用组件,为了解耦开发了springmvc;而实际开发过程中,经常会使用到注解,程序的样板很多,于是开发了starter,这套就是springboot。
区别:
1.springboot是约定大于配置,可以简化spring的配置流程;springmvc是基于servlet的mvc框架,个人感觉少了model中的映射。
2.以前web应用要使用到tomat服务器启动,而springboot内置服务器容器,通过@SpringBootApplication中注解类中main函数启动即可。
如果下边的不会那就不叫程序员!!!!!
linux相关:
查看内核版本命令:
[root@SOR_SYS ~]# cat /proc/version
Linux version 2.6.18-238.el5 (mockbuild@x86-012.build.bos.redhat.com) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-50)) #1 SMP Sun Dec 19 14:22:44 EST 2010
[root@SOR_SYS ~]#
查看具体版本:
登录到linux执行cat /etc/redhat-release ,例如如下:
[root@SOR_SYS ~]# cat /etc/redhat-release
Red Hat Enterprise Linux AS release 4 (Nahant Update 4)
[root@SOR_SYS ~]#
分配ip: dhclient
查看ip:ip addr
返回上一级:cd …
进入下一级:cd filename(文件名必须在本目录下)
进去指定目录:cd /a/b(a,b代表根目录和后续子目录)
date 实践和日期
cal 当前日历
df 磁盘驱动器当前的可用空间
free 可用内存
exit 结束终端回话
pwd 查看当前工作目录
cd 将工作目录改变为主目录
cd- 将工作目录改变为先前的工作目录
cd~username 将工作目录改变为username的主目录
ls 列出目录内容,可以指定多个目录
以’.’字符开头的文件名是隐藏的,ls不会列出这些文件,除非输入ls -a
ls命令的常用选项:
-a 列出所有文件,包括以点号开头的文件
-l 将输出以长格式显示
-d 将此选项与-l选项结合使用,可查看目录的详细信息,而不是目录的内容
-F 在每个所列出的名字后面加上类型指示符(如在目录名后面加上一个斜杠)
-r 以相反的顺序显示结果
-S 按文件的大小对结果排序
-t 按修改时间排序
ls 长列表字段含义:
-表示一个普通文件,d表示目录(directory),l表示软链接
文件所有者、文件所属组中成员、其他所有人的访问权限
硬链接数目
文件所有者的名字
文件所属用户组的名称
文件大小
修改时间
文件名
file filename 确定文件类型
less filename 查看文件内容
mkdir directory… 创建目录
cp item1 item2 复制单个文件或目录
cp item… directory 复制多个项目进一个目录中
-a archive 复制文件和目录及其属性
-i -interactive 互动,覆盖之前会提示用户
-r -recursive 递归地复制目录及其内容
-u -update 只复制目标目录中不存在的文件或更新文件
-v -verbose 显示信息性消息
mv 移除和重命名文件
rm 删除文件和目录
ln 创建链接
ln file link 创建硬链接
ln -s item link 创建符号链接,item可以是文件也可以是目录
硬链接的局限性:
硬链接不能引用自身文件系统之外的文件,即不能引用与该链接不在同一磁盘分区的文件,简单地说无法跨越物理设备
硬链接无法引用目录
硬链接和文件本身没有什么区别,当硬链接被删除时,只是删除了这个链接,但是文件本身的内容依然存在,除非该文件的所有链接都被删除了。
符号链接是为了克服硬链接的局限性而创建的,符号链接是通过创建一个特殊类型的文件来起作用的,该文件包含了指向引用文件或目录的文本指针。
当删除一个符号链接时,删除的只是符号链接而没有删除文件本身。如果先于符号链接之前删除文件,那么这个链接依然存在,但却不指向任何文件,此时这个链接就称为坏链接。
由于文件名是由链接创建的,所以一个文件通常至少有一个链接。
ls -li 第一个字段就是索引节点号,看到fun和fun-hard共享同一个索引节点号,这就证实它们是相同。
type 显示命令的类型
which 显示可执行程序的位置
help + shell内置命令 获取帮助文档
可执行程序 + --help 显示命令的使用信息
man 显示程序的手册页
1 用户命令
2 内盒系统调用的程序接口
3 C库函数程序接口
4 特殊文件,如设备节点和驱动程序
5 文件格式
6 游戏和娱乐,例如屏幕保护程序
7 其他杂项
8 系统管理命令
apropos 显示合适的命令,带-k选项的man命令与apropos命令在功能上基本是一致的
whatis 显示命令的简要描述
info 显示程序的info条目
alias 创建自己的命令 alias name=‘string’
多条命令用;号分割开
删除别名,可使用unalias命令。
alias不带参数可查看在环境中定义的所有别名。
uniq 命令经常和sort命令结合使用,默认情况下,该命令删除文件中重复的行,如果我们想要查看重复的行,可以在uniq命令后面添加-d选项。
wc 打印行数、字数、字节数
grep 打印匹配行
head/tail 打印文件的开头部分/结尾部分
tee 读取标准输入,再把读到的内容复制到标准输出和一个或更多的文件中去。
!! 重复最后一个执行的命令(虽然↑+Enter键更简单)
!number 重复历史记录中第number行的命令
! string 重复最近的以string开头的历史记录
!?string 重复最近的含有string的历史记录
ps 输出和当前终端会话相关的进程信息
TTY: 进程的控制终端,“?”表示没有控制终端
TIME: 进程消耗的CPU时间总和
添加x选项,告知ps命令显示所有的进程
STAT:state的缩写,显示进程的当前状态
R 运行状态。正在/准备运行
S 睡眠状态。等待某时间发送,如键盘输入或收到网络报文
D 不可中断的睡眠状态。等待I/O操作,如硬盘驱动
T 暂停状态。
Z 无效或者僵尸进程,子进程被终止,但还没有被其父进程彻底释放掉
< 高优先级进程。较不友好,因为消耗更多CPU时间
N 低优先级进程。友好进程(a nice process)
s 包含子进程
- 位于后台的进程组
L: 有记忆体分页分配并锁在记忆体内
aux选项 输出更多的信息
top 实时显示当前所有任务的资源占用情况,默认3秒更新
在命令后面加上 & 使得进程在后台运行
jobs 列出所有活动作业的状态信息
bg 设置在后台中运行作业
fg 设置在前台中运行作业
fg %[jobspec] 使进程回到前台运行
ctrl + c 可以终止xlogo命令 —— 发出INT中断信号
ctrl + z 暂停前台进程 —— 发出TSTP 终端暂停信号
kill [-signal] PID 发送终止信号给某个进程
kill -l 查看更多信号
killall 杀死指定名字的进程
killall [-u user] [-signal] name…
shutdown 关机或者重启系统
pstree 树状模式显示进程列表,显示父子关系
vmstat 5 每隔五秒输出系统资源使用情况
xload 显示系统时间负载情况的图形化界面程序
tload 类似xload,但在终端绘制
vi 启动vi
:q 退出vi
:q! 强制退出vi
不能确定vi所处的状态,可以按ESC键两次返回初始状态
i 进入插入模式,按esc退出插入模式并返回命令模式
:w 将文件写入硬盘
光标移动:
hlkj 分别对应于上下左右方向键
数字0 至本行开头
命令模式下:
o 在当前行的下方开行
O 在当前行的上方开行
u 取消上述操作
删除命令:
x 当前字符
3x 当前字符和之后2个字符
dd 当前行
5dd 当前行之后4行
dW 当前字符到下一单词的起始
d$ 当前字符到当前行的末尾
d0 当前字符到当前行的起始
d^ 当前字符到当前下一个非空字符
dG 当前行到文件末尾
d20G 当前行到文件第20行
命令d不只是删除文本,而是在剪切文本。
命令y会复制文本,其用法与d命令相同。
合并行: 大写的J命令
查找与替换:
行内搜索: f命令,执行过一次之后,输入分号重复上一次搜索。
整个文件搜索: / + 查询的文本, 使用n可以重复搜索。
: 用于启动一条ex命令
% 确定操作范围,%代表从文件的第一行到最后一行。或者用1,$表示所有的行。
s 替换操作
/line/Line 搜索和替换的文本
g global,对搜索到的每一行和每一个实例都进行替换,如果g缺失,只替换每一行第一个符合条件的实例
c 替换之前请求用户确认
替换确认功能键:
y 执行替换
n 跳过替换
a 所有替换
q 停止替换
l last,此次替换后退出替换
切换文件
:n 切换到下一个文件
:N 切换回上一个文件
:buffers 显示所有文件
:buffer 2 切换到文件2
:e + file添加新的一个文件到编辑会话中,只能用:buffer+文件编号来切换文件。
:r + file 将指定文件内容插入到光标位置之前
sql优化:
第一种软优化:优化sql语句
重启mysql:service mysql restart;
mysql清屏:system clear、ctrl+L
mysql的逻辑分层:连接层,服务层,引擎层,存储层
innodb(默认):事务优先,(适合高并发操作,行锁)。
myisam:性能有限(表锁)
查看数据库引擎:支持哪些引擎?
show engines;
查看当前使用的引擎:show variables like ‘%storage_engine%’;
指定数据库对象的引擎:
create table tb(
id int(4) auto_increment,
name varchar(5),
dept varchar(5),
primary key(id)
)ENGING=MyISAM AUTO_INCREMENT=1
查看那些表加了锁: show open tables;// 1代表被加了锁。
分析表锁定的严重程度:show status like ‘table%’;
table_lock_immed
iate:立刻能获取到的表。
table_locks_waited: 需要等待的表锁数。 //后边的数越大,说明存在越大的锁竞争。
如果table_locks_immediate/table_locas_waite >5000 建议使用innodb引擎,否则用Myisam引擎。
DDL表示Data Definition Language数据定义语言,主要包括CREATE,ALTER,DROP;隐性提交的,不能rollback。
DML表示Data Manipulation Language数据操作语言,主要的DML有SELECT,INSERT,UPDATE,DELETE;可以手动控制事务的开启、提交和回滚的。
行锁是通过事务来解锁的;
行锁的特殊锁:间隙锁。也就是值在范围内,但是不存在。(如果操作一个表中数据的条件是大于1小于5的,但是数据中心没有3,执行到回滚段中时,where后边的条件内的所有数据都加锁,如果这个时候有个语句来操作where条件之间的数据,比如添加数据,那么是被锁定的)。
表锁是通过:unlock tables来解锁的,也可以通过提交或回滚事务来解锁;
行锁(默认InnoDB):
mysql每执行一行语句自动默认commit,(set autocommit=0,begin,start transaction三种设置不自动提交)
在查询语句后加for update 会对查询的语句加锁,别人在做操作时时加锁的。
oracle默认不自动commit,需要手动提交。
什么情况下会加锁:当两个用户同时访问一条数据,第一个人正在执行但是没提交,第二个人去操作会被锁行处于等待状态,如果等待过程中对方提交了(提交就是释放锁),则可执行,如果对方长时间没提交,则放弃操作。
行锁锁一行,操作不同数据不影响。
如果没有索引,行锁会转为表锁
查看目前的索引情况: show indexfrom linelock;
为表中的列加索引: alter table 表名 and index 索引名(列名)
如果索引列发生了类型转换,则行锁失效。
缺点:比表锁性能消耗大。
优点:并发能力强效率高。
所以高并发用InnoDB,否则则用MyISAM。
删除mysql注意事项:电脑自带的程序删除,将缓存文件中mysql(隐藏的)删掉,删除注册表中和mysql相关的(查找-删除-查找下一个-删除),重启计算机。
mysql端口号默认3306.
linux版本5.5.XX(XX代表数字)
mysql复制的原理:
主机做增删改操作,从机做查操作,当主机昨晚操作之后,会以日志的方式存放到这个binary log日志文件中,在从机有一个io线程来对这个binary log文件做读写操作,当发现有修改的数据时,会将修改的数据读出来写到从机的Relav log日志文件中,然后在通过sql线程对从机的数据库做读写操作。
mysql的主从复制是异步的,串行的,有时间延迟。所以如果主机或者从机坏掉了,备份的话可能会丢失一些少的数据。
操作数据库的流程:
首先客户端访问服务器提供sql语句--------》通过连接层,不做处理,提供与客户端连接的服务-------》再到服务层,有两个功能,一种是提供各种用户使用的接口,第二个是提供sql优化器sql语句会经过优化处理(弊端有时候会改数据)------》再到引擎层,提供了各种存储数据的方式(常见的有innodb引擎和myisam引擎)-------》存储层,存储数据
查询数据库支持什么引擎:show engines;
查看当前的存储引擎: show variables like ‘&storage_engine&’;
sql优化:性能低,执行时间长,等待时间长,sql语句欠佳(连接查询),索引失效,服务器参数设置不合理(缓冲区,线程数)。
sql语句优化:主要是优化索引
编写过程: 如 select…frim…join…on…where…group by…having…order by…limit…
解析过程:from…on…where…group by…having…select…order by …limit…
索引:相当于数的目录
索引:index是帮助mysql高效获取数据的数据结构,它是一种数据结构(B树,hash树,二叉树),索引用的是B树数据类型。
B树索引:(参考下图在网上找的)
拓展:三叉树,有数据有指针,比二叉树更高效性能更高,三层三叉树存的数据时百万级的,BTree树有很多类型,一般情况下是只B+树,数据全部存放在叶节点中(可以简单的理解为最底层)查询数据的次数是树的高度,如果树的高度是三就差三次。
不需要索引的条件:
1.索引本书是占内存/磁盘空间的。
2.索引不是所有情况都用的(数据量少,频繁更新的字段,很少使用的列)。
3.索引会降低增删改的效率(提高查询,降低增删改)。
优势:提高查询效率(降低了IO的使用率)。
降低CPU使用率(索引不需要排序,直接整理输出)
具体解析流程可查看之下网址:
https://www.cnblogs.com/annsshadow/p/5037667.html
索引的类型:
单值索引:如name的列加索引,那么这个name的索引就是单值索引(一个表可以有多个单一索引)。
唯一索引:唯一索引的值不能重复(一个表中可以有多个唯一索引)。
符合索引:多个列构成的索引(相当于书的二级目录)。
创建索引:create 索引类型 索引名 on 表(列名)
符合索引:create 索引类型 索引名 on 表(列1,列2…)
创建单值索引:create index name_index on user(name);
创建唯一索引:create unique index name_index on user(name);
创建符合索引:create index name_age_index on user(name,age…);
第二种创建索引:修改表(具体语法参考上边)
alter table 表名 add 索引类型 索引名(列名)
如果在id列上加上primary key 即使你没有加索引,数据库也会给你创建主键索引。如果那个列创建了唯一数据库也会为你添加唯一索引。
主键索引和唯一索引的区别:主键索引不能重复不能是null,唯一索引不能重复,可以是null。
删除索引:drop index 索引名 on 表名;
查询索引 show index from 表名 /G或者直接show index from 表名;
sql性能问题:
1.分析sql的执行流程:explain 可以模拟sql优化器执行sql语句,从而让程序员知道自己写的sql语句的状况,
2.mysql的查询优化会干扰我们的优化。
具体优化可查看官网优化:
https://dev.mysql.com/doc/refman/5,5/en/optimization.html
查询执行计划:explain+sql语句
随机拓展(desc降序,asc升序)
表的执行顺序是:笛卡尔积原理(三个数相乘,内层小的优先使用)
如:2 3 4 结果不管怎么成都是24
但是 2x3 =6 6x4=24 和 3x4=12 12x2=24 可以看出虽然结果一样 但是内层的数值6明显要小于12.
数据小的表优先查询,id值不同,id值越大越优先查询。
未完待续。。。。。
第二种 硬优化(分区):
针对海量数据键索引又会占用空间,和索引的维护,就可以使用分区(也就是大表拆成小表)。
竖切和横切。
竖切:垂直分表
两张表要有关联性所以两张表都要有id列。
横切:水平分表
一般情况下使用横切(水平分表)。因为建表的时候表的字段都不会设置的特别大,并且关联性也很强,以及记录不稳定。
好处是:物理上将一个表切成多个表。
坏处是:需要改sql语句,后期代码量的维护增加。(也就是说表分了,sql的语句的表名的都需要改变)
5.1之后以一个插件的形式添加了分区技术避免了这些坏处。
分区技术:
常用的分区技术是四种:(总共有五种,最常用的技术的顺序是下边的顺序)
1.RANGE分区:基于一个给定连续区间的列值(也就是给定的一个字段,基于这个字段为参考点),把多行分配给分区。
2.LIST分区:属于RANGE分区的一个特例,是以固定值或者是枚举值得分区(如男和女)。
3.HASH分区:将数据随机的平均分配到多个分区中(数值没有规律),可用于mysql分区技术的测试。
4.KEY分区:类似于HASH分区,区别在于KEY分区值计算一列或多列,且mysql服务器提供其自身的哈希函数。
RANGE分区:
如图:(网上找到的)
上边是创建表,中间的括号没有分好注意。
下边的创建四个分区的sql语句,语句含义依次是是:
所有store_id小于6的,放到p0分区,
所有大于等于6小于11的放到p1分区,
所有大于等于11小于16的放到p2分区,
所有大于等于16小于21的放到p3分区(特别注意本表store_id的值定义的是从1–20)。
下边是按年分区的例子:
意思跟之前的差不多,最下边的是大于等于2001年的放到p3分区。
虽然分了四个区,但是存储的文件是八个,每个分区生成两个文件,一个是存索引一个是存数据。再加上两个文件,也就是说如果一个表分四个区的话,会产生10个文件。
LIST分区:
首先来看下代码:
如图:意思差不多,如果store_id的值是3,5,6,9,17则放到pNorth分区,下边的一个意思(固定值、枚举值)。
HASH分区:(方便)
如图:根据hired的年来作为基准点,分四个区。不确定年份是多长时间的,就用HASH来随机的把数据分配到四个分区中。(通过hash算法的值来平均分配)
KEY分区:
对于其他存储类型的表,使用自己内部的hash算法来存的,这个函数是基于PASSWORD()一样的算法法则,可以不是整数如字符串等。
MySQL簇使用函数MD5()来实现KEY分区。
总结: