java大全

一、 Java 基础部分

基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法, io 的语法,虚拟机方面的语法。

1、一个 ". 源文件中是否可 以包括多个类(不是内部类)?有什么限制?

可以有多个类,但只能有一个public 的类,并且 public 的类名必须与文件名相一致。

2、java有没有goto?

java中的保留字,但现在没有在java中使用。

3、说说&和&&的区别

相同点:&和&&都可以用作逻辑与的运算符,表示逻辑与(and),运算符两边的表达式都为true时,整个表达式的结果才为true;如果运算符一方得表示式为false,则整个表达式得结果为false。

不同点:
&&有短路功能,当第一个表达式为false,则不用判断第二个表达式,整个表达式的结果为false.例如对于if(str!=null&&!str.equals("")),当str=null时,后面得表达式不会执行,就不会出现NullPointerException. 但是如果将&&换成&,则当str=null时,就会判断第二个表达式,就会抛出NullPointerException异常。再举一个例子:if(x32&++y>0)若x!=32,y会先加一再进行判断;而若是if(x32&&++y>0),y就不会加一。

&还可以用作位运算符,当操作符两边都不是boolean类型时,&表示按位与操作。我们通常使用0x0f与一个整数进行&运算,可以获得该整数的最低4个bit位。例如:0x31&0x0f的结果为0x01.

4、 switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上 ?

在switch expr1 )中 expr1 只能是一个整数表达式或者枚举常量(更大字体),整数表达式可以是 int 基本类型或 Integer 包装类型,由于, byte,short,char 都可以隐含转换为 int ,所以,这些类型以及这些类型的包装类型也是可以的。显然, long 和 S tring 类型都不符合 switch 的语法规定,并且不能被隐式转换成 int 类型,所以,它们不能作用于 swtich 语句中。

5、 short s1 = 1; s1 = s1 + 1; 有什么错 ?

   short s1 = 1; s1 += 有什么错 ?

(1)short s1 = 1; s1 = s1 + 1; 有错 。
在这里插入图片描述
说明:对于
short s1 = 1; s1 = s1 + 1; 由于 s1+1 运算时会自动提升表达式的类型,所以结果是 int 型,再赋值给 short 类型 s1 时,编译器将报告需要强制转换类型的错误。

(2) short s1 = 1; s1 += 1,没有错 。
在这里插入图片描述
说明:对于short s1 = 1; s1 += 1; 由于 += 是 java 语言规 定的运算符, java 编译器会对它进行特殊处理,因此可以正确编译。

6、 char 型变量中能不能存贮一个中文汉字 为什么 ?

char型变量是用来存储 Unicode 编码的字符的, unicode 编码字符集中包含了汉字,所以, char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode 编码字符集中,那么,这个 char 型变量中就不能存储这个特殊汉字。补充说明: unicode 编码占用两个字节,所以, char 类型的变量也是占用两个字节。
备注:后面一部分回答虽然不是在正面回答题目,但是,为了展现自己的学识和表现自己对问题理解的透彻深入,可以回答一些相关的知识,做到知无不言,言无不尽。

在这里插入图片描述

7、final的作用

(1)final修饰类,表示类不可变,不可继承。比如,String,不可变性
(2)final修饰方法,表示该方法不可重写。比如模板方法,可以固定我们的算法
(3)final修饰变量,这个变量就是常量

注意:

修饰的是基本数据类型,这个值本身不能修改。
修饰的是引用类型,引用的指向不能修改。

比如下面的代码是可以的
final Student student = new Student(1,“Andy”);
student.setAge(18);//注意,这个是可以的!

8、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

是引用变量不能改变,引用变量所指向的对象中的内容还是可以改变的。
在这里插入图片描述
拓展:

基本数据类型:byte、short、int、long、float、double、char、boolean
引用类型:类(class)、接口(interface)、数组(array)
基本类型保存的值,引用类型保存了是对象的地址,所有基本类型赋值是按值传递(拷贝赋值),引用类型赋值是按引用传递。

9、==与equals的区别

(1)==
a.基本类型:比较的是是否相同;
b.引用类型:比较的是内存地址是否相同;

(2)equals
a.基本类型:不能进行比较,会直接报错。因为基本数据类型不是类类型;
b.引用类型:比较的是地址值是否相同,等同于等同于” == ”。该方法继承自Object,在object中比较的是地址值。
在这里插入图片描述

package com.pbm;

public class Test {
	public static void main(String[] args) {
		String aa = "asd";
		String bb = "asd";
		int cc=10;
		int dd = 10;
		Integer ff =10;
		Integer gg =10;
		System.out.println(aa==bb); //true
		System.out.println(aa.equals(bb));  //true
		System.out.println(cc==dd); //true
		//System.out.println(cc.equals(dd));  //报错
		System.out.println(ff==gg); //true
		System.out.println(ff.equals(gg)); //true
	}	
}

注意:integer的坑

10、静态变量与实例变量的区别

(1)在语法定义上的区别:
静态变量前要加static关键字,而实例变量前则不加。
(2)在程序运行时的区别:实例变量必须创建对象后才可以通过这个对象来使用;
静态变量则可以直接使用类名来引用。

  • 实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
  • 静态变量不属于某个实例对象,而是属于类,也叫类变量,只要程序加载了类的字节码,不用创建任何实例对象就会被分配空间,就可以被使用,也就是说,你创建了多个对象,他们共用了一个静态变量,而实例对象是属于自己的独有的,不会被共享!
public class Test11 {
     //静态变量
	public static int staticVar = 0;
	//实例变量
	public int instanceVar = 0;
 
	public Test11() {
		staticVar++;
		instanceVar++;
		System.out.println("staticVar=" + staticVar + ",instanceVar="
				+ instanceVar);
	}
 
	public static void main(String[] args) {
		Test11 test = new Test11();  
		Test11 test1 = new Test11();
		Test11 test2 = new Test11();
	}
}

11、Integer和int的区别

①、Integer 是 int 封装类,int 是八大基本数据类型之一(byte,char,short,int,long,float,double,boolean)
②、Integer 是类,默认值为null,int是基本数据类型,默认值为0;
③、Integer 表示的是对象,用一个引用指向这个对象,而int是基本数据类型,直接存储数值。

12、Math.round(11 .5)等于多少 ? Math(-11.5) 等于多少

Math类中提供了三个与取整有关的方法:
ceil (向上取整)、
floor(向下取整) 、
round (四舍五入:加上0.5再向下取整)。

package com.sxt.test;
public class MathTest{
	public static void main(String[] args) {
		double a = 11.5;
		double b = -11.5;
		//四舍五入
		System.out.println("Math.round(a):"+Math.round(a));  //输出Math.round(a):12
		System.out.println("Math.round(b):"+Math.round(b));  //输出Math.round(b):-11
		//向上取整
		System.out.println("Math.ceil(a):"+Math.ceil(a));    //输出Math.ceil(a):12.0
		System.out.println("Math.ceil(b):"+Math.ceil(b));    //输出Math.ceil(b):-11.0
		//向下取整
		System.out.println("Math.floor(a):"+Math.floor(a));  //输出Math.floor(a):11.0
		System.out.println("Math.floor(b):"+Math.floor(b));  //输出Math.floor(b):-12.0

	}
}

13、请说出作用域public,private,protected,以及不写时的区别

在这里插入图片描述

14、overload和override 的区别

(1)overload(重载),是一个类中多态性的一种表现。
a.方法名相同
b.参数个数不同、参数类型不同、参数列表顺序不同
c.在参数个数、参数类型、参数列表顺序不同时,返回值可以不同。

public void m1(int x)
{ }

public int m1(int x, int y)
{
   return x+y;
}

public String m1(int x, int y,int z)
{
   return "abc";
}

public String m1(int x, String str)
{
    return "chongzai2";
}

(2)override(重写),是父类与子类之间多态性的一种表现。子类继承父类,子类里重新编写了父类中的同名(同参数)方法,也就是覆盖了父类的方法;
a.方法名相同
b.参数个数、参数类型、参数列表顺序相同
c.返回值相同
d.子类重写父类方法时,也就是子类覆盖了父类的方法,修饰权限只能等于或大于父类的权限。
e.子类编译时只能比父类抛出更少的异常。

import java.util.*;
class A{            //父类

    public int getVal()
    {
        return 5;
    }
}

class B extends A{  //通过子类对父类抽象方法的覆盖来实现多态,
     public int getVal()
     {
         return 10;
     }
}

public class Test3{
    public static void main(String []args)
    {
        B b=new B(); //通过子类创建的实例对象,调用
        A te=(A)b;

        int x=b.getVal();//调用这个方法,将调用子类中的定义方法。
        System.out.println(x);
    }
}

在这里插入图片描述

15、构造器construtor是否可以被override?

构造方法也叫构造器(construtor),用于给对象进行初始化操作,即为成员变量赋初始值。
说明格式:修饰符 类名(形参列表){}
构造器construtor不能被继承,因此不能被重写,但可以被重载。

16、接口是否可继承接口 ? 抽象类是否可实现接口 ? 抽象类是否可继承实体类(concrete class)? 抽象类中是否可以有静态的 main 方法?

(1)接口可以继承接口

public interface InterfaceA {
}
 
interface InterfaceB extends InterfaceA{
}

(2)抽象类可以实现接口

public interface InterfaceA {
}

abstract class TestA implements InterfaceA{	
}

(3)抽象类可以继承实体类(但前提是实体类必须有明确的构造函数)

public class TestA{	
}

abstract class TestB extends TestA{
}

(4)抽象类可以有静态的main方法
在这里插入图片描述
拓展:抽象类使用abstract 关键字,静态方法使用static关键字

17、面向对象的特征有哪些

面向对象的编程语言有封装、继承、抽象、多态等4个主要的特征。
(1)封装是保证软件部件具有优良的模块性的基础 封装 的目标就是要实现软件部件的“高内聚、低耦合”, 防止程序相互依赖性而带来的变动影响。
(2)在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并 可以 加入若干新的内容 ,或修改原来的方法使之更适合特殊的需要,这就是继承 。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系提高了软件的可重用性和可扩展性 。
(3)抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。
(4)多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象 ,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。

18、abstract class(抽象类)和interface(接口)有什么区别?

(1)概念
抽象类:被abstract修饰的类叫抽象类。比如abstract class A{},抽象类的作用为了子类继承它,提高代码重用性。
接口:我们可以把它看做是一种特殊的抽象类,接口中的所有方法都必须是抽象的,接口中的方法定义默认为 public abstract 类型,接口中的成员产量类型默认为 public static final。

(2)异同点
相同点:
a.两者都不能实例化
b.一个类若继承了抽象类或实现了接口,都需要对里面的抽象方法全部进行实现,否则还需要被声明为抽象类。

不同点:
在这里插入图片描述

19.String 是最基本的数据类型吗 ?

String不是最基本的数据类型。
基本数据类型包括byte 、 int 、 char 、 long 、 float 、 double 、 boolean 和 short 。
java.lang.String是final类型的,是不可以继承这个类、不能修改这个类。为了提高效率、节省空间,建议用StringBuffer类。

20、String s =“Hello”;s =s+“World!"; 这两行代码执行后,原始的 String 对象中的内容 到底变了没有?

没有。因String 被设计成不可变类,所以它的所有对象都是不可变象。在这段代码中, s 原先指向一个 String 对象,内容是 " Hello",然后我们对 s 进行了 操作,s 所指向的那个对象是没有发生了改变的。这时, s 不指向原来那个对象了,而指向了另一个 String 对象,内容为 “HelloWorld!”,原来那个对象还存在于内存之中,只是 s 这个引用变量不再指向它了。
在这里插入图片描述

21、是否可以继承 String 类 ?

不可以继承,Stringfinal

22、String 和 StringBuffer 的区别

相同点:可以储存和操作字符串,即包含多个字符的字符数据。
不同点:
(1)String是不可变类,String对象一旦被创建,其值不能被改变;StirngBuffer是可变类,当对象被创建后,仍然可以对其值进行修改。
(2)String 覆盖了 equals 方法和 hashCode方法; StringBuffer 没有覆盖 equals 方法和 hashCode 方法。

String、StringBuffer与StringBuilder之间区别

在这里插入图片描述
在这里插入图片描述
String Buffer是线程安全的,因为它的方法加了Synchronized对象锁。
在这里插入图片描述

执行速度比较:
执行速度:StringBuilder > StringBuffer > String

23、数组有没有 length() 这个方法 ? String 有没有 length() 这个方法?

数组没有length() 方法,但有length属性,返回表示该数组的长度;
String有length()方法,但没有length属性,返回便是该字符串的长度。
在这里插入图片描述

List 、 Set 、Map 三种集合之间的区别

在这里插入图片描述
1、元素重复性:

(1)List 允许有重复的元素。
(2)Set 集合不可重复。Set以及所有实现了Set接口的类都不允许重复值的插入,若多次插入同一个元素时,在该集合中只显示一个;
(3)Map 以键值对的形式对元素进行存储。Map键不可重复,值可重复

2、元素的有序性:

(1)List 有序;
(2)Set 中的元素都是无序的;但是某些Set的实现类以某种殊形式对其中的元素进行排序,如:LinkedHashSet按照元素的插入顺序进行排序;
(3)Map 跟Set一样对元素进行无序存储,但其某些实现类对元素进行了排序。如:TreeMap根据键对其中的元素进行升序排序

3、 元素是否为空值:

(1)List 允许任意数量的空值;
(2)Set 最多允许一个空值的出现;[ 当向Set集合中添加多个null值时,在该Set集合中只会显示一个null元素]
(3)Map 只允许出现一个空键,但允许出现任意数量的空值;

总结:

 List中的元素,有序、可重复、可为空;
 Set中的元素,无序、不重复、只有一个空元素;
 Map中的元素,无序、键不重,值可重、只可一个空键、可多空值

二. 算法部分

三. Java web 部分

1、Tomcat的优化经验

去掉对web.xml的监听,把jsp提前编辑成servlet。
有富余物理内容的情况,加大Tomcat使用的jvm的内存。

2、HTTP协议中,get请求和post请求的区别

(1)HTTP请求概述
HTTP协议称为超文本传输协议,目的是保证客户端与服务器之间的通信。HTTP的工作方式是客户端与服务器之间的请求–应答协议。在客户端与服务器之间进行请求和响应时,有两种基本的请求方式:get和post,其中get请求是指从指定的资源请求数据,post请求表示向指定的资源提交要被处理的数据。

(2)HTTP请求格式:
在HTTP请求中,首先是请求行;其次是,请求头(header);然后空一行,紧接着是请求的具体内容(request-body)

(3)get请求和post请求的异同
相同点:
a) get和post请求都是客户端与服务器之间得交互,请求—应答模式的协议

不同点:
a) get是从服务器上获取数据;post是向服务器传送数据,一般用于更新资源信息
b) get请求时通过URL直接请求数据,数据信息可以在URL中直接看到,比如浏览器访问;而post请求是放在请求头中的,我们是无法直接看到的
c) get提交有数据大小的限制,一般是不超过2KB,而POST理论上默认是没有限制
d) get请求因为数据参数是暴露在URL中的,所以安全性比较低,如密码不能暴露的就不能用get请求;post请求中,请求信息是放在请求头的,安全性较高,可以使用。

3、解释一下什么是 servlet;

Servlet是一种独立于平台和协议的服务端的java技术,可以生成动态WEB页面与传统的CGI(计算机图形接口)和其他类似的CGI技术相比。Servlet具有更好的可移植性。更强大的功能,更少的投资,更高的效率,更好的安全性。

servlet是使用java Servlet应用程序接口(API)及相关类和方法的java程序。java语言能够实现的功能Servlet基本都能够实现。(除了图形化界面)。Servlet 主要用于处理客户端传来的Http 请求,并返回一个响应,通常来说Servlet就是指HttpServlet,用于处理Http请求,其能够处理的请求有doGet(),doPost(),service()等方法,开发servlet时可以直接结成javax.servlet,http.HttpServlet.

Servlet需要在web.xml中进行描述,例如。映射执行servlet的名字,配置servlet类,初始化参数,进行安全配置,URL映射和设置启动优先权。Servlet不仅可以生成HTML脚本输出,也可以生成二进制表单输出。

Servlet应用广泛,现在许多流行框架都离不开Servlet的支持,比如SHH,Spring 容器启动的时候,要在web,xml中装载Spring容器和Actioncontext来初始化Spring的一些参数。如依赖注入,数据库表的映射,初始化系统的安全配置设置read等属性进行一些相关的操作。

4、说一说Servlet的生命周期,执行过程?

Servlet生命周期分为实例化、初始化、响应请求调用service()方法、消亡阶段调用destroy()方法。
执行过程如下:
1)当浏览器发送一个请求地址,tomcat会接收这个请求
2)tomcat会读取项目中的web.xml中的配置
3)当请求地址符合servlet-mapping标签映射的地址,会进入这个servlet
4)servlet首先会实例化(构造),然后初始化执行init()方法,init()方法至始至终执行一次,servlet对象是单实例
5)根据请求的方式是get或post,在service()方法中调用doget()或dopost()方法,完成此次请求
6)当服务器停止,会调用destroy()方法,销毁实例

5、实例化servlet有几种方式

Servlet实例化有两种,如下:
1,第一次请求时,实例化servlet对象
2,在web.XML文件中的<Servlet></Servlet>之间添加<loadon-startup>1</loadon-startup>,tomcat启动时就会实例化servlet对象

6、请写一个Servlet的基本架构。

public class ServletName extends HttpServlet {
		public void doPost(HttpServletRequest request,
		HttpServletResponse response)
		throws ServletException, IOException {
		}
		public void doGet(HttpServletRequest request,
		HttpServletResponse response)
		throws ServletException, IOException {
		}
	}

7、forward 和redirect的区别?

forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。 redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取,并且从浏览器的地址栏中可以看到跳转后的链接地址。前者更加高效,在前者可以满足需要时,尽量使用forward()方法,并且,这样也有助于隐藏实际的链接;在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用sendRedirect()方法。

总结:forward是程序内部跳转,不会跳出tomcat服务器,redirect可以外部跳转,从一个服务器跳转到另一个服务器。

一、 转发的原理
在这里插入图片描述
二、重定向的原理
在这里插入图片描述

8、servlet中怎么定义forward 和redirect

转发:request.getRequestDispatcher (“demo.jsp"). forward(request, response);
重定向:response.sendRedirect(“demo.jsp");

9、过滤器有哪些作用?

可以验证客户是否来自可信的网络,可以对客户提交的数据进行重新编码,可以从系统里获得配置的信息,可以过滤掉客户的某些不应该出现的词汇,可以验证用户是否登录,可以验证客户的浏览器是否支持当前的应用,可以记录系统的日志等等。

10、JSP的常用指令?

<%@page language=”java” contenType=”text/html;charset=gb2312” session=”true” buffer=”64kb” autoFlush=”true” isThreadSafe=”true” info=”text” errorPage=”error.jsp” isErrorPage=”true” isELIgnored=”true” pageEncoding=”gb2312” import=”java.sql.*”%>
isErrorPage:是否能使用Exception对象;isELIgnored:是否忽略EL表达式;
<%@include file=”filename”%>
<%@taglib prefix=”c”uri=”http://……”%>

11、JSP和Servlet中的请求转发分别如何实现?

JSP中的请求转发可利用forward动作实现:<jsp:forward />;
Serlvet中实现请求转发的方式为:
getServletContext().getRequestDispatcher(path).forward(req,res)。

12、乱码如何解决?

1)数据库连接出现乱码
是数据库连接中加入useUnicode=true&characterEncoding=utf-8;
2)设置页面编码,若是jsp页面,需编写代码
<%@page language=“java” pageEncoding=“UTF-8”
contentType=“text/html;charset=UTF-8” %>
若是html页面,在网页头部()中添加下面这段代码

3)将form表单提交方式变为post方式,即添加method="post";)在Servlet类中编写代码request.setCharacterEncoding("UTF-8"),而且必须写在第一行。 4)如果是get请求,在Servlet类中编写代码 byte [] bytes = str.getBytes("iso-8859-1"); String cstr = new String(bytes,"utf-8"); 或者直接修改Tomcat服务器配置文件server.xml增加内容: URIEncoding="utf-8"

13、session 和 application的区别?

1)两者的作用范围不同:
Session对象是用户级的,而Application是应用程序级别的
一个用户一个session对象,每个用户的session对象不同,在用户所访问的网站多个页面之间共享同一个session对象
一个Web应用程序一个application对象,每个Web应用程序的application对象不同,但一个Web应用程序的多个用户之间共享同一个application对象。

两者的生命周期不同:
session对象的生命周期:用户首次访问网站创建,用户离开该网站 (不一定要关闭浏览器) 消亡。
application对象的生命周期:启动Web服务器创建,关闭Web服务器销毁。

14、jsp有哪些内置对象?作用分别是什么?

JSP共有以下9种基本内置组件
request:用户端请求,此请求会包含来自GET/POST请求的参数;
response:网页传回用户端的回应;
pageContext:网页的属性是在这里管理;
session:与请求有关的会话期;
application:servlet正在执行的内容;
out:用来传送回应的输出;
config:servlet的构架部件;
page:JSP网页本身;
exception:针对错误网页,未捕捉的例外

15、Jsp有哪些动作?作用分别是什么?

JSP共有以下6种基本动作
jsp:include:在页面被请求的时候引入一个文件。
jsp:useBean:寻找或者实例化一个JavaBean。
jsp:setProperty:设置JavaBean的属性。
jsp:getProperty:输出某个JavaBean的属性。
jsp:forward:把请求转到一个新的页面。
jsp:plugin:根据浏览器类型为Java插件生成OBJECT或EMBED标记

16、 JSP中动态INCLUDE与静态INCLUDE的区别?

动态INCLUDE用jsp:include动作实现,<jsp:include page=included.jsp flush=true />它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数 ,先将嵌入的jsp页面编译,然后把编译后的内容放入到主页面进行处理,编译两次。
静态INCLUDE用include伪码实现,使用jsp指令引用<%@ include file=included.htm %>,不会检查所含文件的变化,适用于包含静态页面,先将内容先包含到主页面然后在一起编译,只编译一次。

17、 JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?

JSP是Servlet技术的扩展,本质上是Servlet的简易方式,更强调应用的外表表达。JSP编译后是"类servlet"。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑。

18、 页面传递对象的方法?

Request、session、application、cookie等

19、Cookied和session区别?

1)cookie数据存放在客户的浏览器上,session数据放在服务器上。
2)cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。
3)session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。
4)单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

第4部分 数据库

1. 触发器的作用?

触发器是一中特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化。可以联级运算。如,某表上的触发器上包含对另一个表的数据操作,而该操作又会导致该表触发器被触发。

2.什么是存储过程?用什么来调用?

存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。
调用:
1)可以用一个命令对象来调用存储过程。
2)可以供外部程序调用,比如:java程序。

3. 存储过程的优缺点?

优点:
1)存储过程是预编译过的,执行效率高。
2)存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。
3)安全性高,执行存储过程需要有一定权限的用户。
4)存储过程可以重复使用,可减少数据库开发人员的工作量。
缺点:移植性差

4. 存储过程与函数的区别

在这里插入图片描述

5. 索引的作用?和它的优点缺点是什么?

索引就一种特殊的查询表,数据库的搜索可以利用它加速对数据的检索。它很类似与现实生活中书的目录,不需要查询整本书内容就可以找到想要的数据。索引可以是唯一的,创建索引允许指定单个列或者是多个列。缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小。

6. 什么样的字段适合建索引

唯一、不为空、经常被查询的字段

7. 索引类型有哪些?

逻辑上:
Single column 单行索引
Concatenated 多行索引
Unique 唯一索引
NonUnique 非唯一索引
Function-based函数索引
Domain 域索引
物理上:
Partitioned 分区索引
NonPartitioned 非分区索引
B-tree:
Normal 正常型B树
Rever Key 反转型B树
Bitmap 位图索引

8. 什么是事务?什么是锁?

事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务。要将有组语句作为事务考虑,就需要通过ACID测试,即原子性,一致性,隔离性和持久性。

原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

锁:在所以的DBMS中,锁是实现事务的关键,锁可以保证事务的完整性和并发性。与现实生活中锁一样,它可以使某些数据的拥有者,在某段时间内不能使用某些数据或数据结构。当然锁还分级别的。

10. 视图的优缺点

优点:
1)对数据库的访问,因为视图可以有选择性的选取数据库里的一部分。 2)用户通过简单的查询可以从复杂查询中得到结果。 3)维护数据的独立性,试图可从多个表检索数据。 4)对于相同的数据可产生不同的视图。
缺点:
性能:查询视图时,必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,也把它变成一个复杂的结合体,需要花费一定的时间。

11. 列举几种表连接方式,有什么区别?

内连接、自连接、外连接(左、右、全)、交叉连接
内连接:只有两个元素表相匹配的才能在结果集中显示。
外连接:
左外连接:左边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
右外连接:右边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
全外连接:连接的表中不匹配的数据全部会显示出来。
交叉连接: 笛卡尔效应,显示的结果是链接表数的乘积。

12. 主键和外键的区别?

主键在本表中是唯一的、不可唯空的,外键可以重复可以唯空;外键和另一张表的主键关联,不能创建对应表中不存在的外键。

13. 在数据库中查询语句速度很慢,如何优化?

1.建索引
2.减少表之间的关联
3.优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据 量大的表排在前面
4.简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据
5.尽量用PreparedStatement来查询,不要用Statement

14. 数据库三范式是什么?

第一范式(1NF):字段具有原子性,不可再分。所有关系型数据库系统都满足第一范式。
数据库表中的字段都是单一属性的,不可再分。例如,姓名字段,其中的姓和名必须作为一个整体,无法区分哪部分是姓,哪部分是名,如果要区分出姓和名,必须设计成两个独立的字段。
第二范式(2NF):是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。
要求数据库表中的每个实例或行必须可以被惟一地区分。通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键。
第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来
形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是非主属性非部分依赖于主关键字。
第三范式(3NF):必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。
所以第三范式具有如下特征:
1,每一列只有一个值
2,每一行都能区分。
3,每一个表都不包含其他表已经包含的非主关键字信息。
例如,帖子表中只能出现发帖人的id,而不能出现发帖人的id,还同时出现发帖人姓名,否则,只要出现同一发帖人id的所有记录,它们中的姓名部分都必须严格保持一致,这就是数据冗余。

15. union和union all有什么不同?

UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。
UNION ALL只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。
从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复的数据的话,那么就使用UNION ALL。

16. Varchar2和varchar有什么区别?

Char的长度是固定的,而varchar2的长度是可以变化的,比如,存储字符串“abc”对于char(20),表示你存储的字符将占20个字节,包含17个空,而同样的varchar2(20)只占了3个字节,20只是最大值,当你存储的字符小于20时,按实际长度存储。
char的效率要被varchar2的效率高。
目前varchar是varchar2的同义词,工业标准的varchar类型可以存储空字符串,但是oracle不能这样做,尽管它保留以后这样做的权利。Oracle自己开发了一个数据类型varchar2,这个类型不是一个标准的varchar,他将在数据库中varchar列可以存储空字符串的特性改为存储null值,如果你想有向后兼容的能力,oracle建议使用varchar2而不是varchar

17. Oracle和Mysql的区别?

1)库函数不同。
2)Oracle是用表空间来管理的,Mysql不是。
3)显示当前所有的表、用户、改变连接用户、显示当前连接用户、执行外部脚本的语句的不同。
4)分页查询时候时候,mysql用limt oracle用rownum
5)sql的语法的不同。

18. Oracle语句有多少类型

Oracle语句分三类:DDL、DML、DCL。
DDL(Data Definition Language)数据定义语言,包括:
Create语句:可以创建数据库和数据库的一些对象。
Drop语句:可以删除数据表、索引、触发程序、条件约束以及数据表的权限等。
Alter语句:修改数据表定义及属性。
Truncate语句:删除表中的所有记录,包括所有空间分配的记录被删除。
DML(Data Manipulation Language)数据操控语言,包括:
Insert语句:向数据表张插入一条记录。
Delete语句:删除数据表中的一条或多条记录,也可以删除数据表中的所有记录,但是它的操作对象仍是记录。
Update语句:用于修改已存在表中的记录的内容。
Select语句:用于查询已存在表中的记录的内容。
DCL(Data Control Language)数据库控制语言,包括:
Grant语句:允许对象的创建者给某用户或某组或所有用户(PUBLIC)某些特定的权限。
Revoke语句:可以废除某用户或某组或所有用户访问权限

19. oracle分页语句

使用rownum,两种如下:
第一种:
select * from (select t.,rownum row_num from mytable t) b where b.row_num between 1 and 10
第二种:
select * from ( select a.
, rownum rn from mytable a where rownum <= 10 ) where rn >= 1
使用rowid,如下:
select * from scott.emp where rowid in (select rd from (select rowid as rd ,rownum as rn from scott.emp ) where rn<=6 and rn>3)

20. 从数据库中随机取50条

select * from (select * from t_example order by dbms_random.random) where rownum <= 50

21. order by与group by的区别

order by 排序查询、asc升序、desc降序
group by 分组查询、having 只能用于group by子句、作用于组内,having条件子句可以直接跟函数表达式。使用group by 子句的查询语句需要使用聚合函数。

22. commit在哪里会运用

oracle的commit就是DML语句提交数据(这里是释放锁不是锁表),在未提交前你前面的操作更新的都是内存,没有更新到物理文件中。
执行commit从用户角度讲就是更新到物理文件了,事实上commit时还没有写date file,而是记录了redo log file,要从内存写到data物理文件,需要触发检查点,由DBWR这个后台进程来写,这里内容有点多的,如果不深究的话你就理解成commit即为从内存更新到物理文件。

23. 行转列、列换行怎么转

1)使用decode函数
2)使用case when语句

24. 什么是PL/SQL?

PL/SQL是一种程序语言,叫做过程化SQL语言(Procedural Language/SQL)。PL/SQL是Oracle数据库对SQL语句的扩展。在普通SQL语句的使用上增加了编程语言的特点,所以PL/SQL把数据操作和查询语句组织在PL/SQL代码的过程性单元中,通过逻辑判断、循环等操作实现复杂的功能或者计算。PL/SQL 只有 Oracle 数据库有。 MySQL 目前不支持 PL/SQL 的。

25. 序列的作用

Oracle使用序列来生成唯一编号,用来处理一个表中自增字段。 Oracle序列是原子对象,并且是一致的。也就是说,一旦您访问一个序列号,Oracle将在处理下一个请求之前自动递增下一个编号,从而确保不会出现重复值。

26. 表和视图的关系

视图其实就是一条查询sql语句,用于显示一个或多个表或其他视图中的相关数据。
表就是关系数据库中实际存储数据用的。

27. oracle基本数据类型

1)字符串类型
char、nchar、varchar、varchar2、nvarchar2
2)数字类型
81
number、integer
3)浮点类型
binary_float、binary_double、float
4)日期类型
date、 timestamp
5)LOB类型
blob、clob、nclob、bfile

28. truncate与 delete区别

TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少。 DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。 TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。 TRUNCATE,DELETE,DROP放在一起比较: TRUNCATE TABLE:删除内容、释放空间但不删除定义。 DELETE TABLE:删除内容不删除定义,不释放空间。 DROP TABLE:删除内容和定义,释放空间。

29. oracle获取系统时间

select to_char(sysdate, ‘yyyy-MM-dd HH24:mi:ss’) from dual;

30. oracle怎么去除去重

使用distinct关键字

31. 现在有表:

A(id ,name,regdate)
B(id,groupid)
C(id,name2)
写出下面的SQL语句
A)统计A表中每个月注册用户数
select count(),to_char(regdate,‘yyyymm’) from A group by to_char(regdate,‘yyyymm’);
B)统计A表中有姓名相同的用户数
select count(
) from (select name from A group by name having count() >1);
C)如果表A中有姓名相同的用户,把相同的查出,写入表C中
nsert into C(name2) select name from A group by name having count(
) >1;
D)A中ID有多个相同的数据,A中姓名相同的ID只保留注册时间最大的数据
delete from E where e.regdate < (select max(regdate) from a X where E.id = X.id);

32. 现有表

Student(S#,SN,SD)学生表
Course(C#,CN,T#)课程表
SC(S#,C#,score)成绩表
1.查询选了课程‘税收’的学生的学号和名字
答:
select SN,SD from Student where S# in( select S# from Course C , SC where C.C#=SC.C# and CN=’税收基础’);
2.查询选课数量大于5的学生的学号和名字
答:
select SN,SD from Student where S# in (
select S# from SC group by S# having count(distinct C#) > 5);
)

3.建立一个学生表students,包括name,age,head_teacher,id,score(姓名,年龄,班主任,学号,成绩)
Create table students
(
Id number(9) not null primary key,
Name varchar2(40) not null,
Age int check(age between 0 and 100),
Head_teacher vachar2(40),
Score float
);
4.对上表插入一条记录,姓名:张三,年龄:18,班主任:李四,学号:22
Insert into student(id,name,age,head_teacher) values(‘22’,’张三’,’18’,’李四’);
5.对上表中的age+name创建一个索引,并说明它的作用和使用方法
Create index student_index on students(age,name);

33. 怎样把这样一个表(表名:tmp_table_201307)

在这里插入图片描述
查成这样一个结果
在这里插入图片描述

SELECT YEAR,
	SUM ( CASE WHEN MONTH = 1 THEN amount ELSE 0 END ) AS m1,
	SUM ( CASE WHEN MONTH = 2 THEN amount ELSE 0 END ) AS m2,
	SUM ( CASE WHEN MONTH = 3 THEN amount ELSE 0 END ) AS m3,
	SUM ( CASE WHEN MONTH = 4 THEN amount ELSE 0 END ) AS m4 
FROM
	tmp_table_201307 a 
GROUP BY
YEAR 
ORDER BY
	1;

34. 数据库中有一张表ismg_icp_flow,结构如下

在这里插入图片描述
期望的输出结果如下:
在这里插入图片描述

SELECT
	ICPNO,
	SERVICE_ID,
	SUM ( MT_RECV_OK ) TOTAL 
FROM
	ismg_icp_flow 
WHERE
	STAT_MIN BETWEEN to_date ( '2003-1-1', 'yyyy-mm-dd' ) 
	AND to_date ( '2003-2-1', 'yyyy-mm-dd' ) 
GROUP BY
	ICPNO,
	SERVICE_ID 
ORDER BY
	TOTAL;

五、Spring框架部分

1.你对spring的理解

(1)spring是一个轻量级框架,设计原则是非侵入性的。spring的核心是IOC容器,IOC是一种编程思想,是一种框架技术,用来管理控制生命周期和对象之间的关系,通过配置文件进行注入,很好地实现了对象与对象之间的解耦。
(2)IOC工作原理:IOC实现了工厂模式,通过读取application.xml配置文件的标签的类,注入到IOC容器中,通过构造或set方法注入,产生BeanFactory,BeanFactory通过getBean方法获取对象。
(3)Spring还提供了另外一种重要编程思想AOP,AOP称为面向切面编程,可以动态的将主线业务逻辑代码与实现功能代码分离,为了更清晰的逻辑,可以让你的业务逻辑去关注自己本身的业务,而不去想一些其他的事情,将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
(4)Spring提供了很多第三方框架的整合,如:hibernate、struts、mybatis、web service等,使用IOC管理所有的Java bean,这样可以让框架与框架之间偶尔度降低,方便项目的管理,提高开发效率。

2.什么是AOP?

Aspect Oriented Programming (面向方面编程)
OOP是面向对象编程,AOP是在OOP基础之上一种更高级的设计思想.
OOP和AOP之间也存在一些区别,OOP侧重于对象的提取和封装.
AOP侧重于方面组件,方面组件可以理解成封装了通用功能的组件,
方面组件可以通过配置方式灵活的切入到某一批目标对象方法上.
aop是面向切面编程,可以动态的将主线业务逻辑代码与实现功能代码分离,没有侵入性。为了更清晰的逻辑,可以让你的业务逻辑去关注自己本身的业务,而不去想一些其他的事情,将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

3.spring的通知类型有哪些

通知决定了方面组件功能在目标对象方法执行的时机。
Spring框架提供了以下5中类型通知:

  • 前置通知 < aop:before >

    方面功能在目标方法之前调用.

  • 后置通知 < aop:afterRerurning >
    方面功能在目标方法之后调用.(如果目标方法抛出异常则不会执行方面功能)

  • 最终通知 < aop:after >
    方面功能在目标方法之后调用.(目标方法有无异常都会执行方面功能)

  • 环绕通知 < aop:around >
    方面功能在目标方法之前和之后调用.

  • 异常通知 < aop:afterThrowing >
    方面功能在目标方法抛出异常之后调用.

4.什么是MVC?

MVC是一种开发模式,把业务逻辑代码与视图代码分离,通过控制器连接业务逻辑与视图。
MVC将一个应用程序分为三部分:
Model:业务逻辑的处理
View:代表和用户交互的界面
Controller :控制器,连接模型层与视图层。

优点:
1)代码结构层次清晰
2)就是低耦合
3)重用性高
缺点:一个应用程序分成了三个部分开发,增加开发工作量。

5.spring中bean的scope

目前,scope的取值有5种。
在Spring 2.0之前,有singletonprototype两种
在Spring 2.0之后,为支持web应用的ApplicationContext,推出另外三种:request,session和global session类型
singleton:在IOC容器中只存在一个实例
prototype:在IOC容器中只存在多个实例
request:使用在web应用中,相当于Servlet中的Request
session:使用在web应用中,相当于Servlet中的Session
global session:使用在web应用中,相当于Servlet中的application

6.spring注入方式有几种

spring有四种依赖注入方式,常用1.2两种

  • set方法注入
  • 构造器注入
  • 静态工厂方法注入
  • 实例工厂方法注入

7.springMVC工作原理

1).spring mvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。
2).DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller.
3).DispatcherServlet请求提交到目标Controller
4).Controller进行业务逻辑处理后,会返回一个ModelAndView
5).Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象
6).视图对象负责渲染返回给客户端。

在这里插入图片描述

8、为什么要用spring

AOP 让开发人员可以创建非行为性的关注点,称为横切关注点,并将它们插入到应用程序代码中。使用 AOP 后,公共服务 (比 如日志、持久性、事务等)就可以分解成方面并应用到域对象上,同时不会增加域对象的对象模型的复杂性。
IOC 允许创建一个可以构造对象的应用环境,然后向这些对象传递它们的协作对象。正如单词 倒置 所表明的,IOC 就像反 过来的 JNDI。没有使用一堆抽象工厂、服务定位器、单元素(singleton)和直接构造(straight construction),每一个对象都是用 其协作对象构造的。因此是由容器管理协作对象(collaborator)。
Spring即使一个AOP框架,也是一IOC容器。 Spring 最好的地方是它有助于您替换对象。有了 Spring,只要用 JavaBean 属性和配置文件加入依赖性(协作对象)。然后可以很容易地在需要时替换具有类似接口的协作对象。

9、请你谈谈SSH整合

Struts(表示层)+Spring(业务层)+Hibernate(持久层)

  • Struts:是一个表示层框架,主要作用是界面展示,接收请求,分发请求。在MVC框架中,Struts属于VC层次,负责界面表现,负责MVC关系的分发。(View:沿用JSP,HTTP,Form,Tag,Resourse ;Controller:ActionServlet,struts-config.xml,Action)
  • Hibernate:是一个持久层框架,它只负责与关系数据库的操作。
  • Spring:是一个业务层框架,是一个整合的框架,能够很好地黏合表示层与持久层。

10、介绍一下Spring的事务管理

事务就是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。
这样可以防止出现脏数据,防止数据库数据出现问题。
开发中为了避免这种情况一般都会进行事务管理。Spring中也有自己的事务管理机制,一般是使用TransactionMananger进行管理,可以通过Spring的注入来完成此功能。

spring提供了几个关于事务处理的类:
TransactionDefinition //事务属性定义
TranscationStatus //代表了当前的事务,可以提交,回滚。
PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子类。
一般事务定义步骤:

TransactionDefinition td = new TransactionDefinition();
TransactionStatus ts = transactionManager.getTransaction(td);
try{ //do sth
	transactionManager.commit(ts);
}catch(Exception e){transactionManager.rollback(ts);

}

spring提供的事务管理可以分为两类:编程式的和声明式的。编程式的,比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更灵活。

  • 编程式:主要使用transactionTemplate。省略了部分的提交,回滚,一系列的事务对象定义,需注入事务管理对象.
void add(){
transactionTemplate.execute( new TransactionCallback(){
	pulic Object doInTransaction(TransactionStatus ts){
		 //do sth
		 }
	}
}
  • 声明式:
    使用TransactionProxyFactoryBean:
  • PROPAGATION_REQUIRED
  • PROPAGATION_REQUIRED
  • PROPAGATION_REQUIRED,readOnly
    围绕Poxy的动态代理 能够自动的提交和回滚事务
    org.springframework.transaction.interceptor.TransactionProxyFactoryBean
    PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  • PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED–如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

11、Spring里面如何配置数据库驱动?

使用”org.springframework.jdbc.datasource.DriverManagerDataSource”数据源来配置数据库驱动。示例如下:

<bean id=”dataSource”>
<property name=”driverClassName”>
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name=”url”>
<value>jdbc:hsqldb:db/appfuse</value>
</property>
<property name=”username”><value>sa</value></property>
<property name=”password”><value></value></property>
</bean>

12、Spring里面applicationContext.xml文件能不能改成其他文件名?

ContextLoaderListener是一个ServletContextListener, 它在你的web应用启动的时候初始化。缺省情况下, 它会在WEB-INF/applicationContext.xml文件找Spring的配置。 你可以通过定义一个<context-param>元素名字为”contextConfigLocation”来改变Spring配置文件的位置。示例如下:

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/xyz.xml</param-value>
</context-param> </listener-class>
</listener>

13、如何在web应用里面配置spring?

在web.xml中加入如下同容,在启动web服务器时加载/WEB-INF/applicationContext.xml中的内容。

<servlet>
	<servlet-name>context</servlet-name>
	<servlet-class>
		org.springframework.web.context.ContextLoaderServlet
	</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

通过如下类得到ApplicationContext实例
WebApplicationContextUtils.getWebApplicationContext

14、Spring里面如何定义hibernate mapping?

添加hibernate mapping 文件到web/WEB-INF目录下的applicationContext.xml文件里面。示例如下:

<property name=”mappingResources”>
<list>
	<value>org/appfuse/model/User.hbm.xml</value>
</list>
</property>

15、解释一下Dependency injection(DI,依赖注入)和IOC(Inversion of control,控制反转)?

依赖注入DI是一个程序设计模式和架构模型, 一些时候也称作控制反转,尽管在技术上来讲,依赖注入是一个IOC的特殊实现,依赖注入是指一个对象应用另外一个对象来提供一个特殊的能力,例如:把一个数据库连接已参数的形式传到一个对象的结构方法里面而不是在那个对象内部自行创建一个连接。控制反转和依赖注入的基本思想就是把类的依赖从类内部转化到外部以减少依赖
应用控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。也可以说,依赖被注入到对象中。所以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。

Java进阶技术

一、Redis

1.什么是Redis?

Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。
Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、散列表、集合、有序集合。
与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。

2.为什么要用 Redis / 为什么要用缓存?

主要从“高性能”和“高并发”这两点来看待这个问题。
高性能
假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。再将该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
在这里插入图片描述

高并发
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
在这里插入图片描述

3.Redis为什么这么快?

(1)完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是O(1)
(2)数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的;
(3)采用单线程,避免了不必要的上下文切换和竞争,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
(4)使用 I/O 多路复用模型,非阻塞 IO;

4.Redis都有哪些数据类型?

Redis主要有5种数据类型,包括String,List,Hash,Set,ZSet
在这里插入图片描述
String应用场景
商品编号、订单号采用incr命令生成;
是否喜欢的文章(点赞数incr)
Hash应用场景
购物车(新增商品hset、增加商品数量hincrby
商品总数hlen、全部选中hgetall)
List应用场景
微信订阅公众号(订阅lpush、查看订阅号文章lrange)
Set应用场景
抽奖活动(参与sadd、显示参与人数scard、
随机抽取srandmember、spop)
文章点赞(新增点赞sadd、取消点赞srem、
展现所有点赞用户smember、点赞数统计scard)
社交平台(两个人的共同关注sinter、
QQ可能认识的人求差集sdiff)
Zset应用场景
根据商品销售对商品进行排序(zadd、zincrby、zrange)
抖音热搜排行榜

5.什么是Redis持久化?Redis 的持久化有哪些实现方式?

持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。
Redis 提供两种持久化机制 RDB(默认)AOF 机制
RDB持久化:是Redis DataBase缩写,快照
RDB是Redis默认的持久化方式。在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。在这里插入图片描述
如何触发RDB快照;保持策略。
配置文件中默认的快照配置,这三行save代码的意思是:
在3600秒(一个小时)内,如果有1个数据发生改变,则进行持久化。
在30秒内,如果有10个数据发生改变,则进行持久化。(原先是 save 300 100),我为了后面测试RDB,这里进行了修改。
在60秒内,如果有10000个数据发生改变,则进行持久化。
在这里插入图片描述工作流程:
redis根据配置尝试去生成rdb快照文件
redis主进程fork一个子进程出来
子进程尝试将内存中的数据dump到临时的rdb快照文件中
完成rdb快照文件的生成之后,覆盖旧的快照文件
优点:
只有一个文件 dump.rdb,方便持久化,容灾性好。
性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,保证了 redis 的高性能
数据集大时,比 AOF 的启动效率更高。
缺点
数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。

AOF持久化:Append Only File缩写
将Redis执行的每条写命令记录到单独的aof日志文件中,当重启Redis服务时,会从持久化的日志文件中恢复数据。
当两种方式同时开启时,数据恢复时,Redis会优先选择AOF恢复。
在这里插入图片描述
配置:
# 表示是否开启AOF持久化(默认no,关闭) appendonly yes
工作流程:
所有的写入命令会追加到AOF缓冲区中。
AOF缓冲区根据对应的策略向硬盘做同步操作。
随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。
当Redis服务器重启时,可以加载AOF文件进行数据恢复。
优点:
数据安全,可以配置每进行一次命令操作就记录到 aof 文件中一次。
通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。
缺点:
AOF 文件比 RDB 文件大,且恢复速度慢。
数据集大时,比 rdb 启动效率低。

6.什么是Redis事务?

事务是逻辑上的一组操作,要么都执行,要么都不执行。Redis 事务不是严格意义上的事务,只是用于帮助用户在一个步骤中执行多个命令。单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
Redis 事务可以理解为一个打包的批量执行脚本,redis 事务不保证原子性,且没有回滚,中间某条命令执行失败,前面已执行的命令不回滚,后续的指令继续执行。
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证
(1)批量操作在发送 EXEC 命令前被放入队列缓存。
(2)收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,前面已执行的命令不回滚,后续的命令继续执行。
(3)事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
Redis事务的三个阶段:
(1)事务开始 MULTI
(2)命令入队
(3)事务执行 EXEC

Redis事务的相关命令
在这里插入图片描述

7.谈谈你对Redis集群方案——哨兵模式 的理解
在这里插入图片描述

哨兵的介绍
sentinel,中文名是哨兵。哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能:
(1)集群监控:负责监控 redis master 和 slave 进程是否正常工作。
(2)消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
(3)故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
(4)配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。
哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。

8.Redis主从复制的原理是什么?

(1)从节点执行 slaveof 命令
(2)从节点只是保存了 slaveof 命令中主节点的信息,并没有立即发起复制。
(3)从节点内部的定时任务发现有主节点的信息,开始使用 socket 连接主节点。
(4)连接建立成功后,发送 ping 命令,希望得到 pong 命令响应,否则会进行重连。
(5)如果主节点设置了权限,那么就需要进行权限验证;如果验证失败,复制终止。
(6)权限验证通过后,进行数据同步,这是耗时最长的操作,主节点将把所有的数据全部发送给从节点。
(7)当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性。
在这里插入图片描述

9.Redis如何实现分布式锁?

Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系,Redis中可以使用SETNX命令实现分布式锁。
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
当且仅当 key 不存在,将 key 的值设为 value。若给定的 key 已经存在,则 SETNX 不做任何动作
返回值:设置成功,返回 1 。设置失败,返回 0 。
使用SETNX完成同步锁的流程及事项如下:
(1)使用SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,若返回1则获取成功。
(2)为了防止获取锁后程序出现异常,导致其他线程/进程调用SETNX命令总是返回0而进入死锁状态,需要为该key设置一个合理的过期时间。
(3)释放锁,使用DEL命令将锁数据删除。

10.Redis中的缓存穿透、缓存击穿、缓存雪崩是什么?

缓存穿透
当我们访问某个key的时候,此时会去redis缓存中查找,但是此时redis缓存中并不存在这个key,那么它就会去数据库中查找。而我们每次请求都是在查找这个key → redis缓存中没有 → DB中查找,反反复复就使得应用服务器压力变大、redis命中率降低,同时过多的非正常url请求也会造成数据库崩溃。
在这里插入图片描述解决方案:
(1)对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。
(2)设置可访问的名单(白名单):使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
(3)采用布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。

缓存击穿:
key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。在这里插入图片描述解决方案:
(1)预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的存活时长,避免在高并发期间这些数据过期。
(2)实时调整:现场监控哪些数据热门,实时调整key的过期时长。
(3)使用锁

缓存雪崩:
当我们访问多个key对应的数据时,这些key在redis中都过期(无法获取)了,那么这些大量的高并发请求就会转到后端DB中去查找访问,进而造成了数据库的崩溃现象。缓存雪崩与缓存击穿的区别在于:缓存雪崩是针对很多key而言的缓存,而缓存击穿则是针对某一个key。在这里插入图片描述解决方案:
构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)。
使用锁或队列:用加锁或者队列的方式保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况。
设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。
将缓存失效时间分散开:比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

二、RabbitMQ

1.RabbitMQ是什么?

RabbitMQ是一款开源的,Erlang编写的,基于AMQP(高级消息队列协议)协议的消息中间件。

2.为什么要使用消息队列?

从本质上来说是因为互联网的快速发展,业务不断扩张,促使技术架构需要不断的演进。
从以前的单体架构到现在的微服务架构,成百上千的服务之间相互调用和依赖。从互联网初期一个服务器上有 100 个在线用户已经很了不得,到现在坐拥10亿日活的微信。此时,我们需要有一个「工具」来解耦服务之间的关系、控制资源合理合时的使用以及缓冲流量洪峰等等。因此,消息队列就应运而生了。
它常用来实现:异步处理、服务解耦、流量控制(削峰)

3.说说RabbitMQ中的几大组件

在这里插入图片描述
在这里插入图片描述

4.消息队列有什么优缺点?

优点上面已经说了,就是在特殊场景下有其对应的好处,解耦、异步、削峰。缺点有以下几个:
(1)系统可用性降低:系统引入的外部依赖越多,越容易挂掉。万一 MQ 挂了,MQ 一挂,整套系统崩 溃,你不就完了?
(2)系统复杂度提高:硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?
怎么保证消息传递的顺序性?问题一大堆。
3)一致性问题:A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致 了。

5.如何保证消息的可靠性?

消息到MQ的过程中搞丢,MQ自己搞丢,MQ到消费过程中搞丢。
生产者到RabbitMQ:事务机制和Confirm机制,注意:事务机制和 Confirm 机制是互斥的,两者不能共存,会导致 RabbitMQ 报错。
RabbitMQ自身:持久化、集群、普通模式、镜像模式。
RabbitMQ到消费者:basicAck机制、死信队列、消息补偿机制。

6.RabbitMQ中常见交换机类型有哪些?

fanout:把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。
direct:把消息路由到BindingKey和RoutingKey完全匹配的队列中。
topic:RoutingKey 为一个 点号’.’: 分隔的字符串。比如: szh.name.love
BindingKey和RoutingKey一样也是点号“.“分隔的字符串。
BindingKey可使用 * 和 # 用于做模糊匹配,*匹配一个单词,#匹配多个或者0个

7.生产者发送消息的过程是怎样的?

(1) Producer先连接到Broker,建立连接Connection,开启一个信道(Channel)。
(2)Producer声明一个交换器并设置好相关属性。
(3)Producer声明一个队列并设置好相关属性。
(4)Producer通过路由键将交换器和队列绑定起来。
(5)Producer发送消息到Broker,其中包含路由键、交换器等信息。
(6)相应的交换器根据接收到的路由键查找匹配的队列。
如果找到,将消息存入对应的队列,如果没有找到,会根据生产者的配置丢弃或者退回给生产者。
(7)关闭信道,关闭连接。

8.消费者接收消息的过程是怎样的?

(1) Producer先连接到Broker,建立连接Connection,开启一个信道(Channel)。
(2)向Broker请求消费响应的队列中的消息,可能会设置响应的回调函数。
(3)等待Broker回应并投递相应队列中的消息,接收消息。
消费者确认收到的消息,ack。
(4)RabbitMQ从队列中删除已经确定的消息。
(5)关闭信道,关闭连接。

9.交换机无法根据自身类型和路由键找到符合条件队列时,有哪些处理方法?

mandatory :true 返回消息给生产者。
mandatory  : false 直接丢弃。

10.什么是死信队列?导致死信的原因有哪些?

死信,DLX,全称为 Dead-Letter-Exchange,死信交换器,死信邮箱。顾名思义就是无法被消费的消息,一般来说,producer 将消息投递到 broker 或者直接到 queue 里了,consumer 从 queue 取出消息进行消费,但某些时候由于特定的原因导致 queue 中的某些消息无法被消费,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有了死信队列。
(1)消息 TTL 过期
(2)队列达到最大长度 (队列满了,无法再添加数据到 mq 中)
(3)消息被拒绝 (basic.reject 或 basic.nack) 并且 requeue=false.

11.什么是延迟队列?使用场景有哪些?

存储对应的延迟消息,指当消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。
(1)订单在十分钟之内未支付则自动取消。
(2)新创建的店铺,如果在十天内都没有上传过商品,则自动发送消息提醒。
(3)用户注册成功后,如果三天内没有登陆则进行短信提醒。
(4)用户发起退款,如果三天内没有得到处理则通知相关运营人员。
(5)预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议

12.什么是优先级队列?

优先级高的队列会先被消费。
可以通过 x-max-priority 参数来实现。
当消费速度大于生产速度且Broker没有堆积的情况下,优先级显得没有意义

13.RabbitMQ中的事务机制?

RabbitMQ 客户端中与事务机制相关的方法有三个:
(1)channel.txSelect 用于将当前的信道设置成事务模式。
(2)channel.txCommit 用于提交事务 。
(3)channel.txRollback 用于事务回滚,如果在事务提交执行之前由于 RabbitMQ 异常崩溃或者其他原因抛出异常,通过txRollback来回滚

14.RabbitMQ中的发送确认机制?

生产者将信道设置成 confirm 模式,一旦信道进入 confirm 模式, 所有在该信道上面发布的消息都将会被指派一个唯一的 ID(从 1 开始),一旦消息被投递到所有匹配的队列之后,broker就会发送一个确认给生产者(包含消息的唯一 ID),这就使得生产者知道消息已经正确到达目的队列了。
confirm 模式最大的好处在于他是异步的,一旦发布一条消息,生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果 RabbitMQ 因为自身内部错误导致消息丢失,就会发送一条 nack 消息,生产者应用程序同样可以在回调方法中处理该 nack 消息。

15.如何保证RabbitMQ消息队列的高可用?

RabbitMQ 有三种模式:单机模式,普通集群模式,镜像集群模式。
单机模式:就是demo级别的,一般就是你本地启动了玩玩儿的,没人生产用单机模式
普通集群模式:意思就是在多台机器上启动多个RabbitMQ实例,每个机器启动一个。
镜像集群模式:这种模式,才是所谓的RabbitMQ的高可用模式,跟普通集群模式不一样的是,你创建的queue,无论元数据(元数据指RabbitMQ的配置数据)还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。

16.RabbitMQ模式?

(1)简单模式 (Simple / HelloWorld 单生产单消费)

在这里插入图片描述

(2)工作者模式 (Work单发送多接收)
一个生产者端,多个消费者端。
示例中为了保证消息发送的可靠性,不丢失消息,使消息持久化了。同时为了防止接收端在处理消息时down掉,只有在消息处理完成后才发送消息确认。
在这里插入图片描述

(3)发布订阅模式 (Publish/Subscribe)
使用场景:发布、订阅模式,生产者端发送消息,多个消费者同时接收所有的消息。
在这里插入图片描述

(4)路由模式 (Routing)
在这里插入图片描述

(5)topic主体模式
在这里插入图片描述

(6)RPC远程调用模式

三 、mybatis

1.MyBatis是什么?

MyBatis是一款优秀的dao持久层框架、一个半ORM(对象关系映射)框架。它支持定制化SQL、存储过程、高级映射、缓存机制,同时MyBatis几乎避免了JDBC代码中手动设置参数以及获取结果集等繁杂操作的过程。

2.JDBC编程有哪些缺陷?MyBatis又是如何改进的?

  • JDBC编程中频繁创建、释放数据库连接对象,容易造成系统资源浪费,影响系统性能。可以使用连接池解决这个问题。
    解决:在mybatis-config.xml中配置数据库连接池,使用连接池管理数据库连接。
  • JDBC编程中 sql 语句写在代码中造成代码不易维护,实际应用场景中sql的变化可能较大,sql变动需要改变java代码。
    解决:将SQL语句配置在XXXXmapper.xml映射文件中,与java代码分离。
  • JDBC编程中向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
    解决:Mybatis中自动将java对象映射至sql语句。
  • JDBC编程中对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
    解决:Mybatis中自动将sql执行结果映射至java对象。

3.MyBatis与Hibernate的区别在哪?

首先要提到一个词ORM。ORM(Object Relational Mapping)对象关系映射,是一种为了解决关系型数据库数据与简单Java对象(POJO)的映射关系的技术。
相同点
都是对jdbc的封装,都是持久层的框架,都用于dao层的开发。
不同点
Hibernate是全自动ORM映射工具,Hibernate 对SQL语句封装,提供了日志、缓存、级联(级联比 MyBatis 强大)等特性,此外还提供 HQL(Hibernate Query Language)操作数据库,数据库无关性支持好,但会多消耗性能。使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。
MyBatis 在查询关联对象或关联集合对象时,需要手动编写 SQL,支持动态 SQL、处理列表、动态生成表名、支持存储过程。所以,称之为半自动ORM映射工具

4.MyBatis的优缺点

优点
与传统的数据库访问技术相比,ORM有以下优点:

  • 基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除SQL与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
  • 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接。
  • 很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。
  • 提供映射标签,支持对象与数据库的字段映射;提供对象关系映射标签,支持对象关系组件维护。
  • 能够与Spring很好的集成。
    缺点
  • SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
  • SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库

5.请说说MyBatis的工作原理

在这里插入图片描述

  1. 通过加载mybatis全局配置文件以及mapper映射文件初始化configuration对象和Executor对象(通过全局配置文件中的defaultExecutorType初始化);
  2. 创建一个defaultSqlSession对象,将configuration对象和Executor对象注入给defaulSqlSession对象中;
  3. defaulSqlSession通过getMapper()获取mapper接口的代理对象mapperProxy(mapperProxy中包含defaultSQLSession对象)
    执行增删改查:
    1) 通过defaulSqlSession中的属性Executor创建statementHandler对象;
    2) 创建statementHandler对象的同时也创建parameterHandler和resultSetHandler;
  4. 通过parameterHandler设置预编译参数及参数值;
  5. 调用statementHandler执行增删改查;
  6. 通过resultsetHandler封装查询结果。

6.MyBatis的架构设计是怎样的?

在这里插入图片描述

  • API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
  • 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
  • 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
  • 引导层:加载xml配置和Java配置

7.#{}和${}的区别

  • #{}是占位符,预编译处理,可以防止SQL注入;${}是拼接符,字符串替换,没有预编译处理,不能防止SQL注入。
  • Mybatis在处理#{}时,#{}传入参数是以字符串传入,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法来赋值;Mybatis在处理${}时,是原值传入,
  • 是把${}替换成变量的值,相当于JDBC中的Statement编译。
  • #{} 的变量替换是在DBMS 中,变量替换后,#{} 对应的变量自动加上单引号; 的 变 量 替 换 是 在 D B M S 外 , 变 量 替 换 后 , { } 的变量替换是在 DBMS 外,变量替换后, DBMS{} 对应的变量不会加上单引号。

8.模糊查询like语句该怎么写

1、 “%”#{question}"%" 注意:因为#{…}解析成sql语句时候,会在变量外侧自动加单引号’ ',所以这里 % 需要使用双引号" ",不能使用单引号 ’ ',不然会查不到任何结果。

<select id="getEmpByName" resultType="com.szh.bean.Employee">
    select id,lastName,email,gender
	from employee
    where lastName like "%"#{lastName}"%"
</select>
 
List<Employee> list = mapper.getEmpByName("小");

2、 ‘%${question}%’ 可能引起SQL注入,不推荐

<select id="getEmpByName" resultType="com.szh.bean.Employee">
	select id,lastName,email,gender
	from employee
	where lastName like '%${lastName}%'
</select>
 
List<Employee> list = mapper.getEmpByName("小");

3、CONCAT(’%’,#{question},’%’) 使用CONCAT()函数,推荐。

<select id="getEmpByName" resultType="com.szh.bean.Employee">
    select id,lastName,email,gender
    from employee
    where lastName like concat("%",#{lastName},"%")
</select>
 
List<Employee> list = mapper.getEmpByName("小");

4、使用bind标签。

<select id="getEmpByName" resultType="com.szh.bean.Employee">
	<bind name="pattern" value="'%' + lastName + '%'"/>
	select id,lastName,email,gender
	from employee
	where lastName like #{pattern}
</select>
 
List<Employee> list = mapper.getEmpByName("小");

9.如何获取生成的主键?

对于支持主键自增的数据库(MySQL)
<!-- useGeneratedKeys 设置为"true"表明 MyBatis 要获取由数据库自动生成的主键,keyColumn指定数据库主键,keyProperty指定 Java 实体类中对应的主键字段 --> <insert id="insertUser" useGeneratedKeys="true" keyProperty="userId" > insert into user( user_name, user_password, create_time) values(#{userName}, #{userPassword} , #{createTime, jdbcType= TIMESTAMP}) </insert>
parameterType 可以不写,Mybatis可以推断出传入的数据类型。如果想要访问主键,那么parameterType 应当是java实体或者Map。这样数据在插入之后可以通过java实体或者Map来获取主键值。

10.当实体类中的属性名和表中的字段名不一样怎么办?

第1种:通过在查询的SQL语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
<select id="getEmpById" resultType="com.szh.bean.Employee"> select id,last_name lastName,email,gender from employee where id = #{id} </select>
第2种:通过< resultMap >来映射字段名和实体类属性名的一一对应关系。<resultMap id="myMap" type="com.szh.bean.Employee"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> </resultMap>
第3种:在mybatis全局配置文件中开启驼峰命名规则。
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>

11.什么是MyBatis的接口绑定?有哪些实现方式?

接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,我们调用接口方法的时候,最终会执行绑定的SQL语句。
接口绑定有两种实现方式,当Sql语句比较简单时候,可以使用注解绑定,当SQL语句比较复杂时候,一般用xml绑定的比较多。
(1)通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来实现接口绑定;
(2)通过在xml里面写SQL语句来实现绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全限定类名,同时接口的方法名和SQL语句的id一一对应。

12.使用MyBatis的mapper接口调用时有哪些要求?

(1) Mapper.xml文件中的namespace应该是对应mapper接口的全限定类名。
(2)Mapper接口方法名和mapper.xml中定义的sql语句id一一对应。
(3)Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql语句的parameterType的类型相同。
(4)Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql语句的resultType的类型相同。

13.最佳实践中,通常一个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中,每一个< select>、< insert>、< update>、< delete>标签,都会被解析为一个MappedStatement对象。
Dao接口里的方法,是不能重载的,因为是全限定类名+方法名的保存和寻找策略,需要保证全限定类名+方法名的唯一性。(重载了话,方法名一定是重复的)
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理对象proxy,代理对象proxy会拦截接口方法调用,转而执行方法对应的sql语句,然后将sql执行结果返回。

14.MyBatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?

Mybatis动态sql可以让我们在xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。
其执行原理为,使用OGNL(对象导航图语言Object Graph Navigation Language)从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能

15.MyBatis的一级、二级缓存是什么?

一级缓存:采用 PerpetualCache,HashMap 存储。MyBatis默认打开一级缓存,其存储作用域为 当前sqlSession会话对象,当 sqlSession flush 或 close 之后,该 sqlSession 中的所有 Cache 就将清空。可以调用 clearCache();//手动清理缓存。
二级缓存:默认也是采用 PerpetualCache,HashMap 存储,不同之处在于二级缓存的存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,开启二级缓存之后(在mybatis主配置文件中添加< setting name=“cacheEnabled” value=“true”/>;其次在对应的mapper映射文件中添加 < cache/>),对应的实体类需要实现Serializable序列化接口(可用来保存对象的状态)。
对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)进行了C/U/D 操作后,默认该作用域下所有缓存将被清理掉。

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花乐晴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值