Java面试小结(三)

关于JDBC、Mybatis、网络基础,JavaWeb,参考博客Review-Day10

JDBC6大编程步骤

  • 加载驱动 - 加载驱动实现类 - Driver

  • 获取连接 - 和db进行连接 - DriverManager

  • 获取语句对象Statement

    • 写sql语句
    • 由语句对象将sql发送到mysql-server,如果执行的是DQL,还需要进行结果集处理,执行第4步
  • 处理结果集 - 通过光标来获取表中的数据 - ResultSet

  • 关闭对象-ResultSet,Statement,Connection

SQL注入

负责发送sql语句的对象 - Statement语句对象 - 引发sql注入问题 - 是因为参数硬拼接到了sql语句中

传入非法的参数

sql注入的场景:

username是外部传过来的参数.该参数直接会被拼接到sql语句中.

rs = st.executeQuery(sql);

1
2
3
4
5
public User getByUsername(String username) {
//...
String sql = "select * from t_user where username='"+username+"'";
//...
}

PrepareStatement和Statement区别

  • PreparedStatement继承自Statement,都是接口
  • Statement适用于运行静态 SQL 语句[参数直接硬拼接到sql语句]。 Statement 接口不接受参数。
  • **PrepareStatement计划多次使用同一条 SQL 语句[适合执行同构的sql]**, PreparedStatement接口运行时接受输入的参数。
  • PrepareStatement有效防止sql注入
  • PreparedStatement会预编译SQL语句,Statement每次都会解析/编译SQL
  • PreparedStatement的效率 比 Statement 的效率高

连接池的工作原理

数据库连接池的基本思想就是为数据库连接 建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去

连接池的工作原理主要由三部分组成,分别为连接池的建立、连接池中连接的使用管理、连接池的关闭。

  • 连接池的创建
    一般在系统初始化时,连接池会根据系统配置建立,并在池中创建了几个连接对象,以便使用时能从连接池中获取。
    连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。Java中提供了很多容器类可以方便的构建连接池,例如Vector[线程安全的类]、Stack等。

  • 连接池连接的使用管理
    连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其管理策略是:
    当客户端·请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户端使用;如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没达到就重新创建一个连接给请求的客户端;如果达到就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户端。 当客户端释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池中删除该连接,否则保留为其他客户服务。该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接锁带来的系统资源开销。

  • 连接池的关闭
    当应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,该过程正好与创建相反

ORM思想(对象关系映射)

表和实体类息息相关

Mybatis(半自动ORM框架)和hibernate(全自动ORM框架)区别

  • Mybatis 和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
  • Mybatis 直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁, -但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
  • Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate 开发可以节省很多代码,提高效率。

Mybatis(面对简单的封装,自动封装结果集)和JDBC(手动封装结果集)区别

Mybatis免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作.

复杂的查询那么仍然是需要手动进行映射的[列-属性]

${ }和#{ }区别

#{}是预编译处理, ${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性

resultType和resultMap区别

resultType
  • 只有select标签才需要指定resultType属性

  • 自动映射

  • mybatis什么时候才能够实现自动映射的效果 - 一定是查询出来的列名和实体类属性名高度保持一致

  • 或者出来的列名是一个合法的匈牙利命名 - 实体类属性的小驼峰.

resultMap
  • 当查询的列值不能自动映射/绑定实体类的属性的时候,需要通过resultMap来进行一一绑定.

selectOne和selectList区别

  • selectOne - 负责加载唯一的一条数据 - 返回的是一个单个对象

  • selectList - 负责加载多条数据,返回一个集合

  • 如果在必须使用selectList,不小心使用到了selectOne.那么就会抛出异常

延迟加载

MyBatis中的延迟加载,也称为懒加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。例如在进行一对多查询的时候,只查询出一方,当程序中需要多方的数据时,mybatis再发出sql语句进行查询,这样子延迟加载就可以的减少数据库压力。MyBatis 的延迟加载只是对关联对象的查询有迟延设置,对于主加载对象都是直接执行查询语句的。

一级缓存和二级缓存

一级缓存

mybatis中是自动开启一级缓存的.

SqlSession = Connection[Jdbc中的一次连接] + Cache[默认开启的就是一级缓存]

一级缓存是SqlSession级别的.

  • 优先到一级缓存中去查询是否存在这个实体对象.如果有直接返回.否则才会和db进行交互
  • 目的好处 - 为了提高查询效率的
二级缓存

mybatis并没有自动开启二级缓存,手动配置启动二级缓存

  • 优先从一级缓存中去查找是否存在对象,如果不存在执行2,存在,直接返回了
  • 再到二级缓存中去查找是否存在对象.如果不存在,则会和db进行交互
  • 将对象散列的属性数据放一份到二级缓存.将整个实体对象[整体]放入到一级缓存中.

SqlSessionFactoryBuilder,SqlSessionFactory和SqlSession == Connection + Cache(一级缓存)

SqlSessionFactoryBuilder

仅仅只会使用到一次.

SqlSessionFactory build(InputStream in);

功能:读取xml的字节输入流来构建一个重量级的对象SqlSessionFactory - 相当于jdbc数据源对象[BasicDataSource].

SqlSessionFactory

重量级的对象 - 不能随意创建多个或者随意销毁 - 耗时间 - 占内存 - 单例

一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例

SqlSession openSession();//获取Session对象

SqlSession

作用:负责和db进行CRUD操作.

与db进行一次会话 - 一次连接.相当于JDBC中的Connection对象.但是比jdbc多出缓存的功能.

SqlSession=Connection[db连接] + Cache[默认的一级缓存];

SqlSession 的实例不是线程安全的,因此是不能被共享的.每个线程都应该有它自己的 SqlSession 实例.

session应该是一个局部变量

回顾java知识点

当线程执行到方法的时候,就会在本地开辟一块区域 - 线程栈[独占的]

association和collection区别(Mybatis加载一/多的区别)

  • 关联-association
  • 集合-collection

association是用于一对一和多对一,而collection是用于一对多的关系

写出几个常见的SQL标签/动态SQL

  • 循环容器的标签forEach

  • concat模糊查询

  • choose (when, otherwise)标签
    choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的sql。类似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。

  • selectKey 标签

  • if标签

  • if + where 的条件判断

  • if + set实现修改语句

  • if + trim代替where/set标签

Mybatis分页插件

PageHelper方法使用了静态的ThreadLocal参数,分页参数和线程是绑定的。内部流程是ThreadLocal中设置了分页参数(pageIndex,pageSize),之后在查询执行的时候,获取当线程中的分页参数,执行查询的时候通过拦截器在sql语句中添加分页参数,之后实现分页查询,查询结束后在 finally 语句中清除ThreadLocal中的查询参数

PageHelper首先将前端传递的参数保存到page这个对象中,接着将page的副本存放入ThreadLoacl中,这样可以保证分页的时候,参数互不影响,接着利用了mybatis提供的拦截器,取得ThreadLocal的值,重新拼装分页SQL,完成分页。

Servlet生命周期

init,service[doGet,doPost],destroy方法

  • 第一阶段 - Servlet何时被实例化
    如果配置了0
    如果配置了0或者正数,意味着启动tomcat的时候,就会立即初始化该servlet实例,并且利用该实例立即去调用init方法.
    如果值一样,根据上下的配置顺序.如果值不一样.数值越小,优先级越高.
    如果没有配置
    当请求第一次到达的时候,tomcat容器会初始化该servlet的实例.然后利用该实例立即去调用init方法
    init方法仅仅只会执行1次.

  • 第二阶段
    来自于client端的请求永远是永远是先到达service方法.如果本servlet中没有重写service方法
    那么会自动进入到父类HttpServlet中的service方法,根据请求的方式来决定调用doGet方法还是doPost方法.
    再在重写之后的doGet方法或者doPost方法中来处理请求和响应.

  • 第三阶段
    当我们关闭tomcat的时候,会调用destroy方法.

post和get区别

  • (1).get请求一般用于获取数据,post请求一般用于需要发数据到后台时使用

  • (2).get请求的参数,会放在url上,所以安全性,隐私性会比较差,post请求的参数会放在request.body中,比较的安全

  • (3).get请求不受到刷新,回退的影响,post请求则会在网页回退或者刷新后,重新进行发送

  • (4).get请求会被缓存,post请求不会被缓存

  • (5).get请求会被记录在浏览器的历史记录中,post请求则不会被记录

  • (6).get请求可以被收藏为标签,post不能被收藏为标签

  • (7).get请求只能进行url编码,post请求则支持多种编码

  • (8).get请求通常通过url地址栏请求,post通常通过表单发送数据请求

  • (9). post请求url长度理论上没有限制,get请求有限制[不同的浏览器不一样]

如何处理中文乱码

1
req.setCharacterEncoding("utf-8");

转发/重定向

转发
  • 转发发生在服务器端的跳转
  • 共享request作用域中的数据
  • 地址栏不变
重定向
  • 重定向发生在客户端的跳转
  • 至少2次请求,不能获取request作用域中的数据
  • 地址栏是会发生变化的
  • 可以重定向到其他站点

Cookie和session

  • cookie数据存放在客户的浏览器上,session数据放在服务器上.
  • cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。
  • 设置cookie时间可以使cookie过期。但是使用session-destory(),我们将会销毁会话。
  • session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用cookie。
  • 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。(Session对象没有对存储的数据量的限制,其中可以保存更为复杂的数据类型)

注意:

  • session很容易失效,用户体验很差;

  • 虽然cookie不安全,但是可以加密 ;

  • cookie也分为永久和暂时存在的;

  • 浏览器 有禁止cookie功能 ,但一般用户都不会设置;

  • 一定要设置失效时间,要不然浏览器关闭就消失了;

例如:

​ 记住密码功能就是使用永久cookie写在客户端电脑,下次登录时,自动将cookie信息附加发送给服务端。

​ application是全局性信息,是所有用户共享的信息,如可以记录有多少用户现在登录过本网站,并把该信息展示个所有用户。

两者最大的区别在于生存周期,一个是IE启动到IE关闭.(浏览器页面一关 ,session就消失了),一个是预先设置的生存周期,或永久的保存于本地的文件。(cookie)

Session信息是存放在server端,但session id是存放在client cookie的,当然php的session存放方法是多样化的,这样就算禁用cookie一样可以跟踪

Cookie是完全保持在客户端的如:IE firefox 当客户端禁止cookie时将不能再使用

Cookie如何管理session

诞生背景:session为什么要进行管理?

原因:通过http协议发送的请求,http协议无状态的协议 - server不能够判断后续的多次请求是来自于同一个客户端[server本身不标识客户端.]

  • 何时才会创建session空间
    1-1. 当后端代码中第一次出现req.getSession();
    1-2. 第一次访问jsp文件,只要设置成false,就不会创建session空间.
1
<%@ page contentType="text/html;charset=UTF-8" language="java" session="true" %>
  • 当第一次请求到达req.getSession();的时候,tomcat服务器会创建一个Session空间,并且给这个空间分配一个唯一的id
    接着创建了cookie,这个cookie中存放了这个空间的id,并且通过响应头信息将这个cookie发送到client端,并且保存在client

  • 后续的请求会带上存储sessionid的cookie一起发送到server端.由tomcat解析cookie中的session空间的id,然后将这个client联系到这个client对应的session空间

Http和Https

  • HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
  • 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
  • HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
  • http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
  • HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

TCP(三次握手)

tcp-三次握手.png

  • SYN:连接请求/接收 报文段 - 同步位

  • seq:发送的第一个字节的序号

  • ACK:确认报文段

  • ack:确认号。希望收到的下一个数据的第一个字节的序号

  • client和server一开始都是出于close状态

  • client自己想要建立请求 - 主动打开,server端被动打开的,然后server进入到listen监听状态.

  • (1)首先客户端向服务器端发送一段TCP报文,其中:
    标记位为SYN,表示“请求建立新连接”;序号为Seq=X;随后客户端进入SYN-SENT阶段。

  • (2)服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,其中:
    标记位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);序号为Seq=y;确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。

  • (3)客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。其中:
    标记位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;随后客户端进入ESTABLISHED阶段。
    服务器收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。

为什么不能两次握手

  • client发送第一个请求①到server,但是由于网络不稳定,此次请求尚未到达server
  • client发现server一直没有回复,再发一次请求②[第一次我握手,嗨,我要建立连接],第二个请求顺利到达server
  • server和client进行第二次握手[好的,你建立吧].
  • client和server进行第三次握手[那好,我真的建立]
  • 此时第一次请求慢吞吞的到达server了.[syn=1,seq=x],server会认为是一个新的请求过来了.
  • server和client想要进行第二次握手ack=x+1[确认号]
  • client分析ack不是自己的,直接忽略此次来自于server端握手.
  • server就会一直处于等待状态.

http状态码

  • 200 - 请求成功
  • 301 - 资源(网页等)被永久转移到其它URL
  • 404 - 请求的资源(网页等)不存在
  • 500 - 内部服务器错误
分类 分类描述
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误

三大作用域

  • request作用域 - HttpServletRequest,一次请求,一次响应.
  • session作用域 - HttpSession - 一次会话期间,浏览器开启,浏览器关闭
  • application作用域 - ServletContext - 服务器开启 - 服务器关闭 - 整个应用期间

HttpServletRequest和HttpServletResponse

  • HttpServletRequest
    extends javax.servlet. ServletRequest[I]
    所有的请求的信息都被封装到了HttpServletRequest对象中

  • HttpServletResponse
    extends javax.servlet. ServletResponse[I]
    所有的响应给客户端的信息全部封装到这个对象中了.

Filter和Intecepor

Filter有如下几个用处。

  • 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
  • 根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
  • 在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
  • 根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。

  • Filter是基于函数回调的,而Interceptor则是基于Java反射的。
  • Filter依赖于Servlet容器,而Interceptor不依赖于Servlet容器。
  • Filter对几乎所有的请求起作用,而Interceptor只能对action请求起作用。
  • Interceptor可以访问Action的上下文,值栈里的对象,而Filter不能。
  • 在action的生命周期里,Interceptor可以被多次调用,而Filter只能在容器初始化时调用一次。

监听器

Listener监听器就是一个实现特定接口的普通Java程序,这个程序专门用于监听一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。

  • 监听器Listener就是在application,session,request三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件。

  • Listener是Servlet的监听器,可以监听客户端的请求,服务端的操作等。

  • Listener实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等.

九大内置对象

  • out(JspWriter):等同与response.getWriter(),用来向客户端发送文本数据;
  • config(ServletConfig):对应“真身”中的ServletConfig;
  • page(当前JSP的真身类型):当前JSP页面的“this”,即当前对象;
  • pageContext(PageContext):页面上下文对象,它是最后一个没讲的域对象;
  • exception(Throwable):只有在错误页面中可以使用这个对象;
  • request(HttpServletRequest):即HttpServletRequest类的对象;
  • response(HttpServletResponse):即HttpServletResponse类的对象;
  • application(ServletContext):即ServletContext类的对象;
  • session(HttpSession):即HttpSession类的对象