Java面试3

7、写一个 Singleton 出来。

第一种:饱汉模式

public classSingleTon {

private SingleTon(){

}

//实例化放在静态代码块里可提高程序的执行效率,但也可能更占用空间

private final static SingleTon instance =new SingleTon();

public static SingleTon getInstance(){

return instance;

}

}

第二种:饥汉模式

public classSingleTon {

private SingleTon(){}

private static instance = null;//newSingleTon();

public static synchronized SingleTongetInstance(){

if(instance == null)

instance = new SingleTon();

return instance;

}

}

第三种:用枚举

public enum SingleTon{

ONE;

}

第三:更实际的应用(在什么情况用单例)

public classSequenceGenerator{

//下面是该类自身的业务功能代码

private int count = 0;

public synchronized int getSequence(){

++count;

}

//下面是把该类变成单例的代码

private SequenceGenerator(){}

private final static instance = newSequenceGenerator();

public static SingleTon getInstance(){

return instance;

}

}

第四:

public class MemoryDao

{

private HashMap map = new HashMap();

publicvoid add(Student stu1){

map.put(SequenceGenerator.getInstance().getSequence(),stu1);

//把 MemoryDao 变成单例

}

Singleton 模式主要作用是保证在 Java 应用程序中,一个类 Class 只有一个实例存在。

一般 Singleton 模式通常有几种种形式:

第一种形式: 定义一个类,它的构造函数为 private 的,它有一个 static 的 private 的该类变

量,在类初始化时实例话,通过一个 public 的 getInstance 方法获取对它的引用,继而调用其

中的方法。

public class Singleton {

private Singleton(){}

//在自己内部定义自己一个实例,是不是很奇怪?

//注意这是 private 只供内部调用

private staticSingleton instance = new Singleton();

//这里提供了一个供外部访问本 class 的静态方法,可以直接访问

public staticSingleton getInstance() {

return instance;

}

}

第二种形式:

public class Singleton {

private static Singleton instance = null;

public static synchronized Singleton getInstance() {

//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次

//使用时生成实例,提高了效率!

if (instance==null)

instance=new Singleton();

return instance;

}

}

其他形式:

定义一个类,它的构造函数为 private 的,所有方法为 static 的。

一般认为第一种形式要更加安全些

8、递归算法题 1

一个整数,大于0,不用循环和本地变量,按照 n,2n,4n,8n 的顺序递增,当值大于5000

时,把值按照指定顺序输出来。

例:n=1237

则输出为:

1237,

2474,

4948,

9896,

9896,

4948,

2474,

1237,

提示:写程序时,先致谢按递增方式的代码,写好递增的以后,再增加考虑递减部分。

public static void doubleNum(int n)

{

System.out.println(n);

if(n<=5000)

doubleNum(n*2);

System.out.println(n);

}

Gaibaota(N) = Gaibaota(N-1) + n

9、递归算法题 2

第1个人10,第2个比第1个人大2岁,依次递推,请用递归方式计算出第8个人多大?

package cn.itcast;

import java.util.Date;

publicclass A1 {

public static voidmain(String [] args)

{

System.out.println(computeAge(8));

}

public static int computeAge(intn)

{

if(n==1)return 10;

returncomputeAge(n-1) + 2;

}

}

public static voidtoBinary(int n,StringBuffer result)

{

if(n/2 != 0)

toBinary(n/2,result);

result.append(n%2);

}

10、排序都有哪几种方法?请列举。用 JAVA 实现一个快速排序。

本人只研究过冒泡排序、选择排序和快速排序,下面是快速排序的代码:

public class QuickSort {

/**

* 快速排序

* @param strDate

* @param left

* @param right

*/

public void quickSort(String[] strDate,int left,int right){

String middle,tempDate;

int i,j;

i=left;

j=right;

middle=strDate[(i+j)/2];

do{

while(strDate[i].compareTo(middle)<0&& i<right)

i++; //找出左边比中间值大的数

while(strDate[j].compareTo(middle)>0&& j>left)

j--; //找出右边比中间值小的数

if(i<=j){ //将左边大的数和右边小的数进行替换

tempDate=strDate[i];

strDate[i]=strDate[j];

strDate[j]=tempDate;

i++;

j--;

}

}while(i<=j); //当两者交错时停止

if(i<right){

quickSort(strDate,i,right);//从

}

if(j>left){

quickSort(strDate,left,j);

}

}

/**

* @param args

*/

public static void main(String[] args){

String[] strVoid=newString[]{"11","66","22","0","55","22","0","32"};

QuickSort sort=new QuickSort();

sort.quickSort(strVoid,0,strVoid.length-1);

for(int i=0;i<strVoid.length;i++){

System.out.println(strVoid[i]+" ");

}

}

}

11、有数组 a[n],用 java 代码将数组元素顺序颠倒

//用下面的也可以

//for(inti=0,int j=a.length-1;i<j;i++,j--)是否等效于 for(int i=0;i<a.length/2;i++)呢?

importjava.util.Arrays;

public classSwapDemo{

public static void main(String[] args){

int [] a = new int[]{

(int)(Math.random() *1000),

(int)(Math.random() * 1000),

(int)(Math.random() *1000),

(int)(Math.random() *1000),

(int)(Math.random() * 1000)

};

System.out.println(a);

System.out.println(Arrays.toString(a));

swap(a);

System.out.println(Arrays.toString(a));

}

public static void swap(int a[]){

int len = a.length;

for(int i=0;i<len/2;i++){

int tmp = a[i];

a[i] = a[len-1-i];

a[len-1-i] = tmp;

}

}

}

12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一

千零一拾一元整)输出。

去零的代码:

returnsb.reverse().toString().replaceAll("零[拾佰仟]","零").replaceAll("零+万","万

").replaceAll("零+元","元").replaceAll("零+","零");

public class RenMingBi {

/**

* @param args add by zxx ,Nov 29, 2008

*/

private static finalchar[] data = new char[]{

'零','壹','贰','叁','肆','伍','陆','柒','捌','玖'

};

private static finalchar[] units = new char[]{

'元','拾','佰','仟','万','拾','佰','仟','亿'

};

public static voidmain(String[] args) {

// TODOAuto-generated method stub

System.out.println(

convert(135689123));

}

public static Stringconvert(int money)

{

StringBuffersbf = new StringBuffer();

int unit = 0;

while(money!=0)

{

sbf.insert(0,units[unit++]);

intnumber = money%10;

sbf.insert(0,data[number]);

money/= 10;

}

returnsbf.toString();

}

}

三. html&JavaScript&ajax 部分

1. 判断第二个日期比第一个日期大

如何用脚本判断用户输入的的字符串是下面的时间格式2004-11-21必须要保证用户

的输入是此格式,并且是时间,比如说月份不大于12等等,另外我需要用户输入两个,并

且后一个要比前一个晚,只允许用 JAVASCRIPT,请详细帮助作答,,

//这里可用正则表达式判断提前判断一下格式,然后按下提取各时间字段内容

<script type="text/javascript">

window.onload =function()

{

//这么写是为了实现 js 代码与 html 代码的分离,当我修改 js 时,不能影响 html 代

码。

document.getElementById("frm1").onsubmit=

function(){

vard1 = this.d1.value;

vard2 = this.d2.value;

if(!verifyDate(d1)) {alert("第一个日期格式不对");return false;}

if(!verifyDate(d2)) {alert("第二个日期格式不对");return false;}

if(!compareDate(d1,d2)){alert("第二个日期比第一日期小");return

false;}

};

}

functioncompareDate(d1,d2)

{

var arrayD1= d1.split("-");

var date1 =new Date(arrayD1[0],arrayD1[1],arrayD1[2]);

var arrayD2= d2.split("-");

var date2 =new Date(arrayD2[0],arrayD2[1],arrayD2[2]);

if(date1> date2) return false;

return true;

}

functionverifyDate(d)

{

vardatePattern = /^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2]\d|3[0-1])$/;

returndatePattern.test(d);

}

</script>

<form id="frm1" action="xxx.html">

<input type="text" name="d1" />

<input type="text" name="d2" />

<input type="submit"/>

</form>

2. 用 table 显示 n 条记录,每 3 行换一次颜色,即 1,2,3 用红色字体,4,5,

6 用绿色字体,7,8,9 用红颜色字体。

<body>

<table id="tbl">

<tr><td>1</td></tr>

<tr><td>2</td></tr>

<tr><td>3</td></tr>

<tr><td>4</td></tr>

<tr><td>5</td></tr>

<tr><td>6</td></tr>

<tr><td>7</td></tr>

<tr><td>8</td></tr>

<tr><td>9</td></tr>

<tr><td>10</td></tr>

</table>

</body>

<script type="text/javascript">

window.onload=function()

{

var tbl =document.getElementById("tbl");

rows =tbl.getElementsByTagName("tr");

for(i=0;i<rows.length;i++)

{

var j= parseInt(i/3);

if(j%2==0)rows[i].style.backgroundColor="#f00";

else rows[i].style.backgroundColor="#0f0";

}

</script>

3、HTML 的 form 提交之前如何验证数值文本框的内容全部为数字?否则的话

提示用户并终止提交?

<form onsubmit=’return chkForm(this)’>

<input type="text" name="d1"/>

<input type="submit"/>

</form>

<script type=”text/javascript” />

function chkForm(this)

{

var value = thist.d1.value;

var len =value.length;

for(vari=0;i<len;i++)

{

if(value.charAt(i)>"9"|| value.charAt(i)<"0")

{

alert("含有非数字字符");

returnfalse;

}

}

return true;

}

</script>

4、请写出用于校验 HTML 文本框中输入的内容全部为数字的 javascript 代码

<input type="text" id="d1" onblur=" chkNumber(this)"/>

<script type=”text/javascript” />

function chkNumber(eleText)

var value =eleText.value;

var len =value.length;

for(vari=0;i<len;i++)

{

if(value.charAt(i)>"9"|| value.charAt(i)<"0")

{

alert("含有非数字字符");

eleText.focus();

break;

}

}

}

</script>

除了写完代码,还应该在网页上写出实验步骤和在代码中加入实现思路,让面试官一看就明

白你的意图和检查你的结果。

5、说说你用过那些 ajax 技术和框架,说说它们的区别

四. Java web 部分

1、Tomcat 的优化经验

答:去掉对 web.xml 的监视,把 jsp 提前编辑成 Servlet。

有富余物理内存的情况,加大 tomcat 使用的 jvm 的内存

2、HTTP 请求的 GET 与 POST 方式的区别

答:servlet 有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。

这个生存期由 javax.servlet.Servlet 接口的 init,service 和 destroy 方法表达。

3、解释一下什么是 servlet;

答:servlet 有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。

这个生存期由 javax.servlet.Servlet 接口的 init,service 和 destroy 方法表达。

4、说一说 Servlet 的生命周期?

答:servlet 有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。

这个生存期由 javax.servlet.Servlet 接口的 init,service 和 destroy 方法表达。

Servlet 被服务器实例化后,容器运行其 init 方法,请求到达时运行其 service 方法,service

方法自动派遣运行与请求对应的 doXXX 方法(doGet,doPost)等,当服务器决定将实例

销毁的时候调用其 destroy 方法。

web 容器加载 servlet,生命周期开始。通过调用 servlet 的 init()方法进行 servlet 的初始化。

通过调用 service()方法实现,根据请求的不同调用不同的 do***()方法。结束服务,web 容

器调用 servlet 的 destroy()方法。

5、Servlet 的基本架构

public class ServletName extends HttpServlet {

public void doPost(HttpServletRequest request,HttpServletResponse response) throws

ServletException, IOException {

}

public void doGet(HttpServletRequest request,HttpServletResponse response) throws

ServletException, IOException {

}

}

6、SERVLET API 中 forward()与 redirect()的区别?

答:前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;后

者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的

地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量

使用 forward()方法,并且,这样也有助于隐藏实际的链接。在有些情况下,比如,需要跳

转到一个其它服务器上的资源,则必须使用

sendRedirect()方法。

7、什么情况下调用 doGet()和 doPost()?

Jsp 页面中的 FORM 标签里的 method 属性为 get 时调用 doGet(),为 post 时调用 doPost()。

8、Request 对象的主要方法:

setAttribute(String name,Object):设置名字为 name 的 request 的参数值

getAttribute(String name):返回由 name 指定的属性值

getAttributeNames():返回 request 对象所有属性的名字集合,结果是一个枚举的实例

getCookies():返回客户端的所有 Cookie 对象,结果是一个 Cookie 数组

getCharacterEncoding():返回请求中的字符编码方式

getContentLength():返回请求的 Body 的长度

getHeader(String name):获得 HTTP 协议定义的文件头信息

getHeaders(String name):返回指定名字的 request Header 的所有值,结果是一个枚举的

实例

getHeaderNames():返回所以 request Header 的名字,结果是一个枚举的实例

getInputStream():返回请求的输入流,用于获得请求中的数据

getMethod():获得客户端向服务器端传送数据的方法

getParameter(String name):获得客户端传送给服务器端的有 name 指定的参数值

getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的

实例

getParametervalues(String name):获得有 name 指定的参数的所有值

getProtocol():获取客户端向服务器端传送数据所依据的协议名称

getQueryString():获得查询字符串

getRequestURI():获取发出请求字符串的客户端地址

getRemoteAddr():获取客户端的 IP 地址

getRemoteHost():获取客户端的名字

getSession([Boolean create]):返回和请求相关 Session

getServerName():获取服务器的名字

getServletPath():获取客户端所请求的脚本文件的路径

getServerPort():获取服务器的端口号

removeAttribute(String name):删除请求中的一个属性

9、forward 和 redirect 的区别

forward 是服务器请求资源,服务器直接访问目标地址的 URL,把那个 URL 的响应内容读

取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,

所以它的地址栏中还是原来的地址。

redirect 就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来

说浏览器会用刚才请求的所有参数重新请求,所以 session,request 参数都可以获取。

10、request.getAttribute()和 request.getParameter()有何区别?

getParameter 得到的都是 String 类型的。或者是 http://a.jsp?id=123 中的 123,或者是某个表

单提交过去的数据。

getAttribute 则可以是对象。

getParameter()是获取 POST/GET 传递的参数值;

getAttribute()是获取对象容器中的数据值;

getParameter:用于客户端重定向时,即点击了链接或提交按扭时传值用,即用于在用表单

或 url 重定向传值时接收数据用。

getAttribute:用于服务器端重定向时,即在 sevlet 中使用了 forward 函数,或 struts 中使用了

mapping.findForward。getAttribute 只能收到程序用 setAttribute 传过来的值。

getParameter()是获取 POST/GET 传递的参数值;

getAttribute()是获取 SESSION 的值;

另外,可以用 setAttribute,getAttribute 发送接收对象.而 getParameter 显然只能传字符串。

setAttribute 是应用服务器把这个对象放在该页面所对应的一块内存中去,当你的页面服务器

重定向到另一个页面时,应用服务器会把这块内存拷贝另一个页面所对应的内存中。这样

getAttribute 就能取得你所设下的值,当然这种方法可以传对象。session 也一样,只是对象

在内存中的生命周期不一样而已。getParameter 只是应用服务器在分析你送上来的 request

页面的文本时,取得你设在表单或 url 重定向时的值。

getParameter 返回的是 String, 用于读取提交的表单中的值;

getAttribute 返回的是 Object,需进行转换,可用 setAttribute 设置成任意对象,使用很灵活,

可随时用;

11. jsp 有哪些内置对象?作用分别是什么?分别有什么方法?

答:JSP 共有以下9个内置的对象:

request 用户端请求,此请求会包含来自 GET/POST 请求的参数

response 网页传回用户端的回应

pageContext 网页的属性是在这里管理

session 与请求有关的会话期

application servlet 正在执行的内容

out 用来传送回应的输出

config servlet 的构架部件

page JSP 网页本身

exception 针对错误网页,未捕捉的例外

request 表示 HttpServletRequest 对象。它包含了有关浏览器请求的信息,并且提供了几个

用于获取 cookie, header,和 session 数据的有用的方法。

response 表示 HttpServletResponse 对象,并提供了几个用于设置送回浏览器的响应的

方法(如 cookies,头信息等)

out 对象是 javax.jsp.JspWriter 的一个实例,并提供了几个方法使你能用于向浏览器回送

输出结果。

pageContext 表示一个 javax.servlet.jsp.PageContext 对象。它是用于方便存取各种范

围的名字空间、servlet 相关的对象的 API,并且包装了通用的 servlet 相关功能的方法。

session 表示一个请求的 javax.servlet.http.HttpSession 对象。Session 可以存贮用户的

状态信息

applicaton 表示一个 javax.servle.ServletContext 对象。这有助于查找有关 servlet 引擎

和 servlet 环境的信息

config 表示一个 javax.servlet.ServletConfig 对象。该对象用于存取 servlet 实例的初始

化参数。

page 表示从该页面产生的一个 servlet 实例

12. jsp 有哪些动作?作用分别是什么?

(这个问题似乎不重要,不明白为何有此题)

答:JSP 共有以下6种基本动作

jsp:include:在页面被请求的时候引入一个文件。

jsp:useBean:寻找或者实例化一个 JavaBean。

jsp:setProperty:设置 JavaBean 的属性。

jsp:getProperty:输出某个 JavaBean 的属性。

jsp:forward:把请求转到一个新的页面。

jsp:plugin:根据浏览器类型为 Java 插件生成 OBJECT 或 EMBED 标记

13、JSP 的常用指令

isErrorPage(是否能使用 Exception 对象),isELIgnored(是否忽略表达式)

14. JSP 中动态 INCLUDE 与静态 INCLUDE 的区别?

答:动态 INCLUDE 用 jsp:include 动作实现

<jsp:include page=included.jsp flush=true />它总是会检查所含文件中的变化,适合用于包

含动态页面,并且可以带参数 静态 INCLUDE 用 include 伪码实现,定不会检查所含文件的

变化,适用于包含静态页面 <%@include file=included.htm %>

15、两种跳转方式分别是什么?有什么区别?

(下面的回答严重错误,应该是想问 forward 和 sendRedirect 的区别,毕竟出题的人不是

专业搞文字艺术的人,可能表达能力并不见得很强,用词不一定精准,加之其自身的技术面

也可能存在一些问题,不一定真正将他的意思表达清楚了,严格意思上来讲,一些题目可能

根本就无人能答,所以,答题时要掌握主动,只要把自己知道的表达清楚就够了,而不要去

推敲原始题目的具体含义是什么,不要一味想着是在答题)

答:有两种,分别为:

<jsp:include page=included.jsp flush=true>

<jsp:forward page= nextpage.jsp/>

前者页面不会转向 include 所指的页面,只是显示该页的结果,主页面还是原来的页面。执

行完后还会回来,相当于函数调用。并且可以带参数.后者完全转向新页面,不会再回来。

相当于 go to 语句。

16、页面间对象传递的方法

request,session,application,cookie 等

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

JSP 是 Servlet 技术的扩展,本质上是 Servlet 的简易方式,更强调应用的外表表达。JSP

编译后是"类 servlet"。Servlet 和 JSP 最主要的不同点在于,Servlet 的应用逻辑是在 Java

文件中,并且完全从表示层中的 HTML 里分离开来。而 JSP 的情况是 Java 和 HTML 可以

组合成一个扩展名为.jsp 的文件。JSP 侧重于视图,Servlet 主要用于控制逻辑。

18、MVC 的各个部分都有那些技术来实现?如何实现?

答:MVC 是 Model-View-Controller 的简写。Model 代表的是应用的业务逻辑(通过

JavaBean,EJB 组件实现),View 是应用的表示面(由 JSP 页面产生),Controller 是提供

应用的处理过程控制(一般是一个 Servlet),通过这种设计模型把应用逻辑,处理过程和显

示逻辑分成不同的组件实现。这些组件可以进行交互和重用。

19、我们在 web 应用开发过程中经常遇到输出某种编码的字符,如 iso8859-1

等,如何输出一个某种编码的字符串?

Public String translate(String str) {

String tempStr ="";

try {

tempStr = newString(str.getBytes("ISO-8859-1"), "GBK");

tempStr =tempStr.trim();

}

catch (Exception e) {

System.err.println(e.getMessage());

}

return tempStr;

}

20、现在输入 n 个数字,以逗号,分开;然后可选择升或者降序排序;按提交

键就在另一页面显示按什么排序,结果为,提供 reset

五.数据库部分

1、用两种方式根据部门号从高到低,工资从低到高列出每个员工的信息。

employee:

eid,ename,salary,deptid;

select * from employeeorder by deptid desc,salary

2、列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号

排序

创建表:

mysql> createtable employee921(id int primary key auto_increment,name

varchar(5

0),salary bigint,deptid int);

插入实验数据:

mysql> insert into employee921values(null,'zs',1000,1),(null,'ls',1100,1),(null,'ww',1100,1),(null,'zl',900,1) ,(null,'zl',1000,2), (null,'zl',900,2),(null,'zl',1000,2) , (null,'zl',1100,2);

编写 sql 语句:

()select avg(salary) from employee921 group by deptid;

()mysql>

selectemployee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from employee921where salary > (select avg(salary) from employee921 where

deptid = tid);

效率低的一个语句,仅供学习参考使用(在 group by 之后不能使用 where,只能使用

having,在 group by 之前可以使用 where,即表示对过滤后的结果分组):

mysql>

selectemployee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from employee921where salary > (select avg(salary) from employee921 group by

deptid havingdeptid = tid);

()select count(*) ,tid

from (

selectemployee921.id,employee921.name,employee921.salary,employee921.deptid tid

from employee921

where salary>

(selectavg(salary) from employee921 where deptid = tid)

) as t

group by tid ;

另外一种方式:关联查询

select a.ename,a.salary,a.deptid

from emp a,

(selectdeptd,avg(salary) avgsal from emp group by deptid ) b

where a.deptid=b.deptidand a.salary>b.avgsal;

3、存储过程与触发器必须讲,经常被面试到?

create procedure insert_Student (_name varchar(50),_age int ,out_id int)

begin

insert into studentvalue(null,_name,_age);

select max(stuId)into _id from student;

end;

call insert_Student('wfz',23,@id);

select @id;

mysql> create trigger update_Student BEFORE update on studentFOR EACH ROW

-> select * from student;

触发器不允许返回结果

create trigger update_StudentBEFORE update on student FOR EACH ROW

insert into student value(null,'zxx',28);

mysql 的触发器目前不能对当前表进行操作

create trigger update_StudentBEFORE update on student FOR EACH ROW

delete from articles where id=8;

这个例子不是很好,最好是用删除一个用户时,顺带删除该用户的所有帖子

这里要注意使用 OLD.id

触发器用处还是很多的,比如校内网、开心网、Facebook,你发一个日志,自动通知好友,

其实就是在增加日志时做一个后触发,再向通知表中写入条目。因为触发器效率高。而 UCH

没有用触发器,效率和数据处理能力都很低。

存储过程的实验步骤:

mysql> delimiter |

mysql> create procedure insertArticle_Procedure (pTitle varchar(50),pBid int,out

pId int)

-> begin

-> insert into article1value(null,pTitle,pBid);

-> select max(id) into pId fromarticle1;

-> end;

-> |

Query OK, 0 rows affected (0.05sec)

mysql> callinsertArticle_Procedure('传智播客',1,@pid);

-> |

Query OK, 0 rows affected (0.00sec)

mysql> delimiter ;

mysql> select @pid;

+------+

| @pid |

+------+

| 3 |

+------+

1 row in set (0.00 sec)

mysql> select * fromarticle1;

+----+--------------+------+

| id | title | bid |

+----+--------------+------+

| 1 | test | 1 |

| 2 | chuanzhiboke | 1 |

| 3 | 传智播客 | 1 |

+----+--------------+------+

3 rows in set (0.00 sec)

触发器的实验步骤:

create table board1(id intprimary key auto_increment,name varchar(50),articleCount int);

create table article1(id intprimary key auto_increment,title varchar(50)

,bid int referencesboard1(id));

delimiter |

create triggerinsertArticle_Trigger after insert on article1 for each ro

w begin

-> update board1 setarticleCount=articleCount+1 where id= NEW.bid;

-> end;

-> |

delimiter ;

insert into board1 value(null,'test',0);

insert into article1value(null,'test',1);

还有,每插入一个帖子,都希望将版面表中的最后发帖时间,帖子总数字段进行同步更新,

用触发器做效率就很高。下次课设计这样一个案例,写触发器时,对于最后发帖时间可能需

要用 declare 方式声明一个变量,或者是用 NEW.posttime 来生成。

4、数据库三范式是什么?

第一范式(1NF):字段具有原子性,不可再分。所有关系型数据库系统都满足第一范式)

数据库表中的字段都是单一属性的,不可再分。例如,姓名字段,其中的姓和名必

须作为一个整体,无法区分哪部分是姓,哪部分是名,如果要区分出姓和名,必须设计成两

个独立的字段。

第二范式(2NF):

第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必

须先满足第一范式(1NF)。

要求数据库表中的每个实例或行必须可以被惟一地区分。通常需要为表加上一个列,以存储

各个实例的惟一标识。这个惟一属性列被称为主关键字或主键。

第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖

主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成

一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,

以存储各个实例的惟一标识。简而言之,第二范式就是非主属性非部分依赖于主关键字。

第三范式的要求如下:

满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一

个数据库表中不包含已在其它表中已包含的非主关键字信息。

所以第三范式具有如下特征:

1,每一列只有一个值

2,每一行都能区分。

3,每一个表都不包含其他表已经包含的非主关键字信息。

例如,帖子表中只能出现发帖人的 id,而不能出现发帖人的 id,还同时出现发帖人姓名,

否则,只要出现同一发帖人 id 的所有记录,它们中的姓名部分都必须严格保持一致,这就

是数据冗余。

5、说出一些数据库优化方面的经验?

用 PreparedStatement 一般来说比 Statement 性能高:一个 sql 发给服务器去执行,涉及步

骤:语法检查、语义分析,编译,缓存

“inert into user values(1,1,1)”-à 二进制

“inert into user values(2,2,2)”-à 二进制

“inert into user values(?,?,?)”-à 二进制

有外键约束会影响插入和删除性能,如果程序能够保证数据的完整性,那在设计数据库时就

去掉外键。(比喻:就好比免检产品,就是为了提高效率,充分相信产品的制造商)

(对于 hibernate 来说,就应该有一个变化:empleyee->Deptment 对象,现在设计时就成

了 employeeàdeptid)看 mysql 帮助文档子查询章节的最后部分,例如,根据扫描的原理,下面的子查询语句要

比第二条关联查询的效率高:

1. select e.name,e.salarywhere e.managerid=(select id from employee where

name='zxx');

2. select e.name,e.salary,m.name,m.salary fromemployees e,employees m where

e.managerid = m.id andm.name='zxx';

表中允许适当冗余,譬如,主题帖的回复数量和最后回复时间等

将姓名和密码单独从用户表中独立出来。这可以是非常好的一对一的案例哟!

sql 语句全部大写,特别是列名和表名都大写。特别是 sql 命令的缓存功能,更加需要统一

大小写,sql 语句 à 发给 oracle 服务器 à 语法检查和编译成为内部指令 à 缓存和执行指令。

根据缓存的特点,不要拼凑条件,而是用?和 PreparedStatment

还有索引对查询性能的改进也是值得关注的。

备注:下面是关于性能的讨论举例

4航班 3个城市

m*n

select * from flight,city where flight.startcityid=city.cityidand city.name='beijing';

m + n

select * from flight where startcityid = (select cityid fromcity where cityname='beijing');

select flight.id,'beijing',flight.flightTime from flight wherestartcityid = (select cityid from city

where cityname='beijing')

6、union 和 union all 有什么不同?

假设我们有一个表 Student,包括以下字段与数据:

drop table student;

create table student

(

id int primary key,

name nvarchar2(50) not null,

score number not null

);

insert into student values(1,'Aaron',78);

insert into student values(2,'Bill',76);

insert into student values(3,'Cindy',89);

insert into student values(4,'Damon',90);

insert into student values(5,'Ella',73);

insert into student values(6,'Frado',61);

insert into student values(7,'Gill',99);

insert into student values(8,'Hellen',56);

insert into student values(9,'Ivan',93);

insert into student values(10,'Jay',90);

commit;

Union 和 Union All 的区别。

select *

from student

where id < 4

union

select *

from student

where id > 2 and id < 6

结果将是

1 Aaron 78

2 Bill 76

3 Cindy 89

4 Damon 90

5 Ella 73

如果换成 Union All 连接两个结果集,则返回结果是:

1 Aaron 78

2 Bill 76

3 Cindy 89

3 Cindy 89

4 Damon 90

5 Ella 73

可以看到,Union 和 Union All 的区别之一在于对重复结果的处理。

UNION 在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排

序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的

是过程表与历史表 UNION。如:

select * from gc_dfys

union

select * from ls_jg_dfys

这个 SQL 在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最

后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

而 UNION ALL 只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有

重复的数据,那么返回的结果集就会包含重复的数据了。

从效率上说,UNION ALL 要比 UNION 快很多,所以,如果可以确认合并的两个结果集

中不包含重复的数据的话,那么就使用 UNION ALL,

7.分页语句

取出 sql 表中第31到40的记录(以自动增长 ID 为主键)

sql server 方案1:

selecttop 10 * from t where id not in (select top 30 id from t order by id ) orde byid

sql server 方案2:

selecttop 10 * from t where id in (select top 40 id from t order by id) order by iddesc

mysql 方案:select * from t order by idlimit 30,10

oracle 方案:select * from (select rownum r,* from t where r<=40) wherer>30

--------------------待整理进去的内容-------------------------------------

pageSize=20;

pageNo = 5;

1.分页技术1(直接利用 sql 语句进行分页,效率最高和最推荐的)

mysql:sql = "select * from articles limit " +(pageNo-1)*pageSize + "," + pageSize;

oracle: sql = "select * from " +

"(selectrownum r,* from " +

"(select* from

articles order by postime desc)" +

"whererownum<= " +

pageNo*pageSize +") tmp " +

"wherer>" +

(pageNo-1)*pageSize;

注释:第7行保证 rownum 的顺序是确定的,因为 oracle 的索引会造成 rownum 返回不同的

简洋提示:没有 order by 时,rownum 按顺序输出,一旦有了 order by,rownum 不按顺序

输出了,这说明 rownum 是排序前的编号。如果对 order by 从句中的字段建立了索引,那

么,rownum 也是按顺序输出的,因为这时候生成原始的查询结果集时会参照索引表的顺序

来构建。

sqlserver:sql = "select top 10 * from id not id(select top" + (pageNo-1)*pageSize + "id from

articles)"

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?" --->binary directive

PreparedStatement pstmt = cn.prepareSatement(sql);

ResultSet rs = pstmt.executeQuery()

while(rs.next())

{

out.println(rs.getString(1));

}

2.不可滚动的游标

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select * from articles";

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?" --->binary directive

PreparedStatement pstmt = cn.prepareSatement(sql);

ResultSet rs = pstmt.executeQuery()

for(int j=0;j<(pageNo-1)*pageSize;j++)

{

rs.next();

}

int i=0;

while(rs.next() && i<10)

{

i++;

out.println(rs.getString(1));

}

}

cacth(){}

finnaly

{

if(rs!=null)try{rs.close();}catch(Exceptione){}

if(stm.........

if(cn............

}

3.可滚动的游标

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select * from articles";

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?" --->binary directive

PreparedStatement pstmt =

cn.prepareSatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,...);

//根据上面这行代码的异常 SQLFeatureNotSupportedException,就可判断驱动是否支持可

滚动游标

ResultSet rs = pstmt.executeQuery()

rs.absolute((pageNo-1)*pageSize)

int i=0;

while(rs.next() && i<10)

{

i++;

out.println(rs.getString(1));

}

}

cacth(){}

finnaly

{

if(rs!=null)try{rs.close();}catch(Exceptione){}

if(stm.........

if(cn............

}

8.用一条 SQL 语句查询出每门课都大于 80 分的学生姓名

name kecheng fenshu

张三 语文 81

张三 数学 75

李四 语文 76

李四 数学 90

王五 语文 81

王五 数学 100

王五 英语 90

准备数据的 sql 代码:

create table score(id int primary key auto_increment,namevarchar(20),subject

varchar(20),score int);

insert into score values

(null,'张三','语文',81),

(null,'张三','数学',75),

(null,'李四','语文',76),

(null,'李四','数学',90),

(null,'王五','语文',81),

(null,'王五','数学',100),

(null,'王五 ','英语',90);

提示:当百思不得其解时,请理想思维,把小变成大做,把大变成小做,

答案:

A: select distinct name from score where name not in (selectdistinct name from score

where score<=80)

B:select distince name t1 from score where 80< all (selectscore from score where

name=t1);

9.所有部门之间的比赛组合

一个叫 department 的表,里面只有一个字段 name,一共有4条纪录,分别是 a,b,c,d,对应四

个球对,现在四个球对进行比赛,用一条 sql 语句显示所有可能的比赛组合.

答:select a.name,b.name

from team a, team b

where a.name < b.name

10.每个月份的发生额都比 101 科目多的科目

请用 SQL 语句实现:从 TestDB 数据表中查询出所有月份的发生额都比101科目相应月份的

发生额高的科目。请注意:TestDB 中有很多科目,都有1-12月份的发生额。

AccID:科目代码,Occmonth:发生额月份,DebitOccur:发生额。

数据库名:JcyAudit,数据集:Select * from TestDB

准备数据的 sql 代码:

drop table if exists TestDB;

create table TestDB(id int primary key auto_increment,AccIDvarchar(20), Occmonth date,

DebitOccur bigint);

insert into TestDB values

(null,'101','1988-1-1',100),

(null,'101','1988-2-1',110),

(null,'101','1988-3-1',120),

(null,'101','1988-4-1',100),

(null,'101','1988-5-1',100),

(null,'101','1988-6-1',100),

(null,'101','1988-7-1',100),

(null,'101','1988-8-1',100);

--复制上面的数据,故意把第一个月份的发生额数字改小一点

insert into TestDB values

(null,'102','1988-1-1',90),

(null,'102','1988-2-1',110),

(null,'102','1988-3-1',120),

(null,'102','1988-4-1',100),

(null,'102','1988-5-1',100),

(null,'102','1988-6-1',100),

(null,'102','1988-7-1',100),

(null,'102','1988-8-1',100);

--复制最上面的数据,故意把所有发生额数字改大一点

insert into TestDB values

(null,'103','1988-1-1',150),

(null,'103','1988-2-1',160),

(null,'103','1988-3-1',180),

(null,'103','1988-4-1',120),

(null,'103','1988-5-1',120),

(null,'103','1988-6-1',120),

(null,'103','1988-7-1',120),

(null,'103','1988-8-1',120);

--复制最上面的数据,故意把所有发生额数字改大一点

insert into TestDB values

(null,'104','1988-1-1',130),

(null,'104','1988-2-1',130),

(null,'104','1988-3-1',140),

(null,'104','1988-4-1',150),

(null,'104','1988-5-1',160),

(null,'104','1988-6-1',170),

(null,'104','1988-7-1',180),

(null,'104','1988-8-1',140);

--复制最上面的数据,故意把第二个月份的发生额数字改小一点

insert into TestDB values

(null,'105','1988-1-1',100),

(null,'105','1988-2-1',80),

(null,'105','1988-3-1',120),

(null,'105','1988-4-1',100),

(null,'105','1988-5-1',100),

(null,'105','1988-6-1',100),

(null,'105','1988-7-1',100),

(null,'105','1988-8-1',100);

答案:

select distinct AccID from TestDB

where AccID not in

(selectTestDB.AccIDfrom TestDB,

(select * from TestDB where AccID='101') asdb101

whereTestDB.Occmonth=db101.Occmonth and

TestDB.DebitOccur<=db101.DebitOccur

);

11.统计每年每月的信息

year monthamount

1991 1 1.1

1991 2 1.2

1991 3 1.3

1991 4 1.4

1992 1 2.1

1992 2 2.2

1992 3 2.3

1992 4 2.4

查成这样一个结果

year m1 m2 m3 m4

1991 1.1 1.2 1.3 1.4

1992 2.1 2.2 2.3 2.4

提示:这个与工资条非常类似,与学生的科目成绩也很相似。

准备 sql 语句:

drop table if existssales;

create table sales(idint auto_increment primary key,year varchar(10), month varchar(10),

amountfloat(2,1));

insert into salesvalues

(null,'1991','1',1.1),

(null,'1991','2',1.2),

(null,'1991','3',1.3),

(null,'1991','4',1.4),

(null,'1992','1',2.1),

(null,'1992','2',2.2),

(null,'1992','3',2.3),

(null,'1992','4',2.4);

答案一、

select sales.year ,

(select t.amount fromsales t where t.month='1' and t.year= sales.year) '1',

(select t.amount fromsales t where t.month='1' and t.year= sales.year) '2',

(select t.amount fromsales t where t.month='1' and t.year= sales.year) '3',

(select t.amount fromsales t where t.month='1' and t.year= sales.year) as '4'

from sales group by year;

12.显示文章标题,发帖人、最后回复时间

表:id,title,postuser,postdate,parentid

准备 sql 语句:

drop table if exists articles;

create table articles(id int auto_increment primary key,titlevarchar(50), postuser

varchar(10), postdate datetime,parentid int referencesarticles(id));

insert into articles values

(null,'第一条','张三','1998-10-10 12:32:32',null),

(null,'第二条','张三','1998-10-10 12:34:32',null),

(null,'第一条回复1','李四','1998-10-10 12:35:32',1),

(null,'第二条回复1','李四','1998-10-10 12:36:32',2),

(null,'第一条回复2','王五','1998-10-10 12:37:32',1),

(null,'第一条回复3','李四','1998-10-10 12:38:32',1),

(null,'第二条回复2','李四','1998-10-10 12:39:32',2),

(null,'第一条回复4','王五','1998-10-10 12:39:40',1);

答案:

select a.title,a.postuser,

(selectmax(postdate) from articles where parentid=a.id) reply

from articles a where a.parentid is null;

注释:子查询可以用在选择列中,也可用于 where 的比较条件中,还可以用于 from 从句中。

13.删除除了 id 号不同,其他都相同的学生冗余信息

2.学生表如下:

id 号 学号 姓名课程编号课程名称分数

1 2005001 张三 0001 数学 69

2 2005002 李四 0001 数学 89

3 2005001 张三 0001 数学 69

A: delete from tablename where id 号 not in(select min(id 号) from tablename group by 学号,姓名,课程编号,课程名称,分数) 

实验:

create table student2(id int auto_increment primary key,codevarchar(20),name

varchar(20));

insert into student2 values(null,'2005001','张三'),(null,'2005002','李四'),(null,'2005001','张

三');

//如下语句,mysql 报告错误,可能删除依赖后面统计语句,而删除又导致统计语句结果不

一致。

delete from student2 where id not in(select min(id) fromstudent2 group by name);

//但是,如下语句没有问题:

select * from student2where id not in(select min(id) from student2 group by name);

//于是,我想先把分组的结果做成虚表,然后从虚表中选出结果,最后再将结果作为删除的

条件数据。

delete from student2 where id not in(select mid from (selectmin(id) mid

from student2 group by name) as t);

或者:

delete from student2 where id not in(select min(id) from (select* from s

tudent2) as t group by t.name);

注:出自牛客网-程序员笔试面试题库,程序员求职备考网站 http://www.nowcoder.com”,学习分享,侵删!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容