***Statement 与 PreparedStatement 的区别
1、PreparedStatement 支持预编译,对于批量处理可以大大提高效率;Statement不支持预编译。
2、PreparedStatement 可避免如类似单引号的编码麻烦,Statement 不可以。
3、Statement 每次执行 sql 语句都要数据库执行 SQL 编译,间接增加了数据服务器的压力;preparedStatement 可以减少与服务器的交互,减轻数据服务器的压力。
4、PreparedStatement 可防止 Sql 助于,更加安全,而 Statement 不行。
5、如果是单条语句的执行 PreparedStatement 开销要大些,反而 Statement 更方便性能要好。
6、在 sql 语句出错时 PreparedStatement 不易检查,而 Statement 则更便于查错。
***JDBC 连接数据库的步骤
1、加载 JDBC 驱动程序(Class.forName(……))。
2、获得 Connection con; DriverManager.getConnection(url , uname , password )。
3、创建 statement stmt;con.prepareStatement(sql)。
4、执行 Sql;stmt.executeQuery(sql) 。
5、处理 ResultSet 结果集。
6、关闭 JDBC 对象。
***Servlet 的生命周期
Servlet 的生命周期主要为三个步骤初始化 init()、业务处理 service()、销毁 destory()。
1、init 阶段:init()方法在 Servlet 实例化的时候调用,而且只调用一次(对于
Servlet 的初始化,一般是第一次被请求时;或者在在 web.xml 中没有配置
<servlet/>标签的映射<servlet-mapping />这个时候,我们可以配置<servlet>元素中 指定了<load-on-startup>子元素时,容器在启动的时候自动加载这些 Servlet 并调用 init()方法),init()方法的作用是完成一些全局性的比较花费时间的初始化工作。
2、service()阶段:Servlet 继承了父类的 service()方法,那么前端 URL 发出
的请求不管是以 get 方式或者 post 方式,都将直接走重写的 service()方法,而不再走 doGet()和 goPost()方法。
3、终止阶段调用 destroy()方法:Servlet 容器关闭时调用,用来关闭 Servlet 占用的一些资源。
***Servlet3.0 有哪些新特性
Servlet 3.0 作为 Java EE 6 规范体系中一员,随着 Java EE 6 规范一起发布。该版本在前一版本(Servlet 2.5)的基础上提供了若干新特性用于简化 Web 应用的开发和部署。其中有几项特性的引入让开发者感到非常兴奋:
1、异步处理支持:有了该特性,Servlet 线程不再需要一直阻塞,直到业务处理完毕才能再输出响应,最后才结束该 Servlet 线程。在接收到请求之后,Servlet线程可以将耗时的操作委派给另一个线程来完成,自己在不生成响应的情况下返回至容器。针对业务处理较耗时的情况,这将大大减少服务器资源的占用,并且提高并发处理速度。
2、新增的注解支持:该版本新增了若干注解,用于简化 Servlet、过滤器(Filter) 和监听器(Listener)的声明,这使得 web.xml 部署描述文件从该版本开始不再是必选的了。
3、可插性支持:熟悉 Struts2 的开发者一定会对其通过插件的方式与包括Spring 在内的各种常用框架的整合特性记忆犹新。将相应的插件封装成 JAR 包并放在类路径下,Struts2 运行时便能自动加载这些插件。现在 Servlet 3.0 提供了类似的特性,开发者可以通过插件的方式很方便的扩充已有 Web 应用的功能,而不需要修改原有的应用。
4、原本文件上传时通过 common-fileupload 或者 SmartUpload,上传比较麻烦,在 Servlet 3.0 中不需要导入任何第三方 jar 包,并且提供了很方便进行文件上传的功能;
5、ServletContext 的性能增强除了以上的新特性之外,ServletContext 对象的功能在新版本中也得到了增强。现在,该对象支持在运行时动态部署 Servlet、过滤器、监听器,以及为 Servlet 和过滤器增加 URL 映射等。以 Servlet 为例, 过滤器与监听器与之类似。
补充:这里只是对新增特性的简单描述,如果运用还请参阅官方资料。
***Servlet 监听器的作用
1、监控器的作用就是监听一些重要事件的发生,监听器对象可以在事情发生前 、 发 生 后 可 以 做 一 些 必 要 的 处 理 。 Servlet 提 供 的 常 用 的 监 听 器 有ServletContextListener、HttpSessionListener、ServletRequestListener 等等,这些只是接口,如果要实现一个监听器只需要实现这些接口,同时在 web.xml 配置一下listener 就可以了。
2、ServletContextListener:Servlet 的上下文监听,它主要实现监听 ServletContext的创建和删除。该接口提供了两种方法 i.contextInitialized(ServletContextEvent event); 通知正在收听的对象,应用程 序已经被加载 和初始化。
ii.contextDestroyed(ServletCotextEvent event); 通知正在收听的对象,应用程序已经被载出,即关闭。
HttpSessionListener:HTTP 会话监听,该接口实现监听 HTTP 会话创建、销毁。该接口提供了一下两种方法
i.sessionCreated(HttpSessionEventevent); 通知正在收听的对象 , session 已 经 被 加 载 及 初 始 化
ii. sessionDestoryed(HttpSessionEvent event)l 通知正在收听的对象,session 已经被载出(HttpSessionEvent 类的主要方法是 getSession(),可以使用该方法回传一个session 对象)
ServletRequestListener : 该接口提供了以下两个方法。
i.requestInitalized(ServletRequestEvent event) 通 知 正 在 收 听 的 对 象 ,ServletRequest 已经被加载及初始化
ii.requestDestroyed(ServletRequestEvent event) 通知正在收听的对象,ServletRequest 已经被载出,即关闭
3、一些使用场景可以用来统计在线人数和在线用户、统计网站访问量、系统启动时初始化信息等。
***forward 与 redirect 区别
Forward:转发,是服务器内部的一种转向行为,客户端并不能察觉,URL 显示的依然是转发前的地址;它属于一次 Request 请求,转发目标页依然可以使用Request 范围内的数据。使用场景:多用户多角色的系统根据登录用户进行模块的跳转。
Redirect:重定向,服务器会首先响应请求端一个状态码,请求端根据状态码再次发生的请求,URL 的地址会换成后一次请求的地址;它属于两次 Request 请求,所以第一次 Request 请求范围内的数据将丢失,不能再从 Request 中获取数据。使用场景:Session 过期(或未登录时)跳转到登录页,系统异常跳转到异常页。
***Session 与 Cookie 的区别
Session:运行在服务器端,默认是保存在内存中,安全性高,可以存放对象,可以设置生命周期,当服务器端维护 Session 对象过多的时候,会影响到服务器的性能,可以将一部分 Session 序列化到硬盘上存储。当用户第一次请求生成Session 对象时会生成 sessionID 用来标识此对象,SessionID 将会返回给用户保存在cookie中
Cookie:是保存在客户端,一般不超过 4k,用户客户端对 cookie 数据量也有限制, 好像 20 个左右,Cookie 安全性低,可以被改写,而且容易被浏览器禁用,但如果 Cookie 完全被禁用,Session 的会话功能也将失效。
***如何实现一个自己的 session
要写一个自己的 session,首先要知道 session 的几个特点:
第一, 能够进行对象的保存;
第二,有一个唯一的识别码 sessionID 可以通过 cookie 中的 sessionID 来找到 session 对象;
第三,就是可以设置 session 的有效期;解决这三点就可以来实现我们自己的 session 了;上面三个条件中最容易实现的就是sessinID,在 Java 中生成一个不重复的 ID 太容易了,这里用 UUID 生成一个 32 位序列作为唯一识别码 token(token 就是上面的 sessionID,自己写时就不要用原来的名称了)。
下面推荐三种方案,面试时根据自己的理解选择。
第一种Map 方案:
1、定义一个全局的静态的Map 对象(最好用线程安全的实现类);
2、用户首次访问时生成一个 token 作为 Map 中的 key 值,Map 中的 value 可以根据需要定义成对象,此对象里面一定要有一个时间字段,来记录用户最近一次的访问时间;
3、定义一个后台线程,用来监控 Map 中对象的日期与系统日期时间的差值, 当大于设定的时间时,就把对象从 Map 中删除(模拟 session 过期清理)。
第二种 SQL 方案:
1、建一张 t_session 表,里面的主键为 token,至少有一个日期字段,其余的字段根据保存的对象需要建立;
2、用户首次访问时生成一个 token 作为主键,同时插入一个当前日期;后续只要用户对 Session 要操作的地方,就要更新 t_session 中的日期字段;
3、定义一个数据 JOB,用来监控 t_session 中对象的日期与系统日期时间的差值,当大于设定的时间时,就把对象从 t_session 中删除(模拟 session 过期清理)。
第三种缓存方案:
1、引入一个缓存 Encache 对象;
2、用户首次访问时生成一个 token 作为 Encache 中的 key 值,Value 值可以根据需要定义对象,最好是实现了序列化。
3、在缓存配置中声明一个过期日期。
综上:第一种方案有一个问题,就是当 Map 存和的对象足够多的时候,后台线程在扫描的时候会不会造成前台用户操作 Map 对象的阻塞,从原理上是有这存情况发生,总之随着 Map 存放的东西越多,性能下降的越厉害。第二种方案不多说了,每次操作都可能引起后台数据表的操作,而且在线用户多的时候,只是这块就会占用很多的连接数,有点浪费系统资源。第三种方案是我比较推崇的方试,不用再担心过期时间的管理,缓存本身就有过期时间管理的机制,有人担心持分布式的,即使有问题,我们还有 memcached 等其它缓存呢。总之根据业务场景需要来选择就行了。
***Http 请求中 Get 和 Post 区别
get,post 是前台与后台交互时两种请求方式。
Get:从 URL 上看它是以明文的方式展现(一般要对参数需要加密处理)在地址栏中,而且它对提交的内容长度有限制,不能超过 1024Btye;Get 一般用于向服务器中请求数据(查询时)。
Post:是一种自动加密的请求方式,而且理论请求的内容没有长度限制,一般用于表单提交,向服务器进行数据添加或者更新的时候使用。
***JSP 中动态 INCLUDE 与静态 INCLUDE 的区别
1、写法不同,动态包含<jsp:include page="目标页"></jsp:include>,而静态包含<%@ include file=” 目标文件”%>;动态包含中一般是同样的.jsp 页,而静态包含可以是其它.txt,.html 等文件。
2、动态包含是两个独立的文件,分别编译,但它总会动态检查被引入页中的内容变化,在执行到 jsp:include 时动态引入被包含的文件,而且可以向被引入的页面中传递参数。静态包含相当于在编译前将被包含的文件插入到<%@ include file="">位置,不会动态的检查被包含文件的变化,不能传递参数,而且两部分文件会编译到一个文件中去。
3、jsp 动态包含,侧重于功能引用,比如定义一个分页组件;而静态包含侧重于页面结构布局,比如用来划分页面版块。
***Servlet 是否线程安全并解释原因
Servlet 工作机制是单实例提供多线程的服务,它是通过一个调度线程来维护多个工作线程的有序执行;但由于多个线程共享一份实例,在对公共资源进行访问时一定会出现线程不同步的问题,即 Servlet 是线程不安全的。
回答完上面几乎就可以了,如果想多表示一下你的能力,可以多说一下,比如单例的好处?Servlet 容器默认采用单实例多线程的方式来处理请求,这样减少产生 Servlet 实例的开销,提升了对请求的响应时间。
如果继续问,如何避免产生线程不安全问题呢?其实方案很多,这里说一下通常用的方式;
第一,避免使用全局变量或者静态变量,这里全局变量或者静态变量在多线程情况下可能就是被争抢的公共资源。
第二,采用同步锁来保证线程安全,尽可能减小锁控制,这种方式可能会使性能下降不少。
第三,把 Servlet 改成单例单线程执行,这样一来,servlet 可能没什么性能而言了。建议第一种方式。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/15169.html