Java面试宝典2011版


1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法, 线程的语法,集合的语法, io 的语法,虚拟机方面的语法。 1、一个 ".java"源文件中是否可以包括多个类(不是内部类 )?有什么限制? 可以有多个类,但只能有一个 public 的类,并且 public 的类名必须与文件名相一致。 2、Java有没有 goto? java中的保留字,现在没有在 java中使用。 3、说说 &和&&的区别。 &和&&都可以用作逻辑与的运算符 ,表示逻辑与 (and),当运算符两边的表达式的结果都为 true 时,整个运算结果才为 true,否则,只要有一方为 false,则结果为 false。 &&还具有短 路的功能,即如 果第一个表达式为 false,则不再 计算第二个表达 式,例如,对 于 if(str != null &&!str.equals(“”))表达式 ,当str为null 时,后面的表达式不会执行 ,所以不会出 现 NullPointerException 如果将 &&改为 &,则会抛出 NullPointerException 异常 。If(x==33 & ++y>0) y会增长, If(x==33 && ++y>0)不会增长 &还可以用作位运算符,当 &操作符两边的表达式不是 boolean 类型时, &表示按位与操作,我 们通常使用 0x0f来与一个整数进行 &运算 ,来获取该整数的最低 4个bit 位,例如 ,0x31 & 0x0f 的结果为 0x01。 备注 :这道题先说两者的共同点 ,再说出 &&和&的特殊之处 ,并列举一些经典的例子来表明自 己理解透彻深入、实际经验丰富。 4、在 JAVA中如何跳出当前的多重嵌套循环? 在Java中,要想跳出多重循环 ,可以在外面的循环语句前定义一个标号 ,然后在里层循环体的 代码中使用带有标号的 break 语句,即可跳出外层循环。例如, ok: for(int i=0;i<10;i++) { for(int j=0;j<10;j++) { System.out.println(“i=” + i + “,j=” + j); if(j == 5) break ok; } } 另外,我个人通常并不使用标号这种方式,而是让外层的循环条件表达式的结果可以受到里层 循环体代码的控制,例如,要在二维数组中查找到某个数字。 int arr[][] = {{1,2,3},{4,5,6,7},{9}}; boolean found = false; for(int i=0;i 78,"def" ---> 62,"xyz" ---> 65 在hashSet 中的存储顺序不是 62,65,78,这些问 题感谢以前一个叫崔健的学员提出,最后通过查看源代码给他解释清楚,看本次培训学员当中 有多少能看懂源码 。LinkedHashSet 按插入的顺序存储 ,那被存储对象的 hashcode方法还有什么 作用呢? 学员想想 !hashset 集合比较 两个对象是否相 等,首先看 hashcode方法是否 相等,然后 看equals 方法是否相等 。new 两个 Student 插入到 HashSet 中,看HashSet 的size,实现 hashcode 和equals 方法后再看 size。 同一个对象可以在 Vector中加入多次。往集合里面加元素,相当于集合里用一根绳子连接到了 目标对象。往 HashSet 中却加不了多次的。 64、说出 ArrayList,Vector, LinkedList的存储性能和特性 ArrayList和Vector 都是使用数组方式存储数据 ,此数组元素数大于实际存储的数据以便增加和 插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作, 所以索引数据快而插入数据慢 ,Vector由于使用了 synchronized 方法 (线程安全 ),通常性能上 较ArrayList差,而LinkedList使用双向链表实现存储 ,按序号索引数据需要进行前向或后向遍 历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。 LinkedList也是线程不安全的 ,LinkedList提供了一些方法 ,使得 LinkedList 可以被当作堆栈和 队列来使用。 65、去掉一个 Vector 集合中重复的元素 Vector newVector = newVector(); For (int i=0;io1.age?1:age1 ){ regex = "" + seperators[0] + "|" + seperators[1]; }else{ regex = "" + seperators[0]; } words = results.split(regex); } public String nextWord(){ if(pos == words.length) return null; return words[pos++]; } } 2、编写 一个程序, 将 d:\java 目录下 的所有 .java 文件复 制到 d:\jad 目录下 ,并将原来 文件的扩 展名从 .java 改为 .jad。 (大家正在做上面这道题,网上迟到的朋友也请做做这道题,找工作必须能编写这些简单问题 的代码 !) 答: listFiles 方法接受 一个 FileFilter 对象,这 个 FileFilter 对象就是 过虑的策略对象, 不同的人 提供不同的 FileFilter 实现,即提供了不同的过滤策略。 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class Jad2Java { public static void main(String[] args) throws Exception { File srcDir = new File("java"); if(!(srcDir.exists() && srcDir.isDirectory())) throw new Exception("目录不存在 "); File[] files = srcDir.listFiles( new FilenameFilter(){ public boolean accept(File dir, String name) { return name.endsWith(".java"); } } ); System.out.println(files.length); File destDir = new File("jad"); if(!destDir.exists()) destDir.mkdir(); for(File f :files){ FileInputStream fis = new FileInputStream(f); String destFileName = f.getName().replaceAll("\\.java$", ".jad"); FileOutputStream fos = new FileOutputStream(new File(destDir,destFileName)); copy(fis,fos); fis.close(); fos.close(); } } private static void copy(InputStream ips,OutputStream ops) throws Exception{ int len = 0; byte[] buf = new byte[1024]; while((len = ips.read(buf)) != -1){ ops.write(buf,0,len); } } } 由本题总结的思想及策略模式的解析: 1. class jad2java{ 1. 得到某个目录下的所有的 java文件集合 1.1 得到目录 File srcDir = new File("d:\\java"); 1.2 得到目录下的所有 java 文件: File[] files = srcDir.listFiles(new MyFileFilter()); 1.3 只想得到 .java 的文件: class MyFileFilter implememyts FileFilter{ public boolean accept(File pathname){ return pathname.getName().endsWith(".java") } } 2.将每个文件复制到另外一个目录,并改扩展名 2.1 得到目标目录,如果目标目录不存在,则创建之 2.2 根据源文件名得到目标文件名,注意要用正则表达式,注意 .的转义。 2.3 根据表示目录的 File和目标文件名的字符串,得到表示目标文件的 File。 //要在硬盘中准确地创建出一个文件,需要知道文件名和文件的目录。 2.4 将源文件的流拷贝成目标文件流 ,拷贝方法独立成为一个方法 ,方法的参数采用 抽象流的形式。 //方法接受的参数类型尽量面向父类,越抽象越好,这样适应面更宽广。 } 分析 listFiles 方法内部的策略模式实现原理 File[] listFiles(FileFilter filter){ File[] files = listFiles(); //Arraylist acceptedFilesList = newArrayList(); File[] acceptedFiles = new File[files.length]; int pos = 0; for(File file: files){ boolean accepted = filter.accept(file); if(accepted){ //acceptedFilesList.add(file); acceptedFiles[pos++] = file; } } Arrays.copyOf(acceptedFiles,pos); //return (File[])accpetedFilesList.toArray(); } 3、编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串 ,但 要保证汉字不被截取半个,如 “我ABC”,4,应该截取 “我AB”,输入 “我ABC 汉DEF”,6,应 该输出 “我ABC”,而不是 “我ABC+汉的半个 ”。 答: 首先要了解中文字符有多种编码及各种编码的特征。 假设 n为要截取的字节数。 public static void main(String[] args) throws Exception{ String str = "我a爱中华 abc我爱传智 def'; String str = "我ABC 汉"; int num = trimGBK(str.getBytes("GBK"),5); System.out.println(str.substring(0,num) ); } public static int trimGBK(byte[] buf,int n){ int num = 0; boolean bChineseFirstHalf = false; for(int i=0;i=’0’&& ch<=’9’) { digitCount++ } else if((ch>=’a’&& ch<=’z’) || (ch>=’A’&& ch<=’Z’)) { engishCount++; } else { chineseCount++; } } System.out.println(……………); 5、说明生活中遇到的二叉树,用 java实现二叉树 这是组合设计模式。 我有很多个 (假设 10 万个 )数据要保存起来 ,以后还需要从保存的这些数据中检索是否存在某个 数据 ,(我想说出二叉树的好处 ,该怎么说呢?那就是说别人的缺点 ),假如存在数组中 ,那么 , 碰巧要找的数字位于 99999 那个地方,那查找的速度将很慢,因为要从第 1个依次往后取,取 出来后进行比较。平衡二叉树(构建平衡二叉树需要先排序,我们这里就不作考虑了)可以很 好地解决这个问题 ,但二叉树的遍历 (前序 ,中序 ,后序 )效率要比数组低很多 ,原理如下图 : 代码如下: package com.huawei.interview; public class Node { public int value; public Node left; public Node right; public void store(int value) { if(valuethis.value) { if(right == null) { right = new Node(); right.value=value; } else { right.store(value); } } } public boolean find(int value) { System.out.println("happen " + this.value); if(value == this.value) { return true; } else if(value>this.value) { if(right == null) return false; return right.find(value); }else { if(left == null) returnfalse; return left.find(value); } } public void preList() { System.out.print(this.value + ","); if(left!=null) left.preList(); if(right!=null) right.preList(); } public void middleList() { if(left!=null) left.preList(); System.out.print(this.value + ","); if(right!=null) right.preList(); } public void afterList() { if(left!=null) left.preList(); if(right!=null) right.preList(); System.out.print(this.value + ","); } public static void main(String [] args) { int [] data = new int[20]; for(int i=0;i this.value) { if(right != null) right.add(value); else { Node node = new Node(value); right = node; } } else{ if(left != null) left.add(value); else { Node node = new Node(value); left = node; } } } public boolean find(int value){ if(value == this.value) return true; else if(value > this.value){ if(right == null) return false; else return right.find(value); }else{ if(left == null) returnfalse; else return left.find(value); } } public void display(){ System.out.println(value); if(left != null) left.display(); if(right != null) right.display(); } /*public Iterator iterator(){ }*/ public static void main(String[] args){ int[] values = new int[8]; for(int i=0;i<8;i++){ int num = (int)(Math.random() * 15); //System.out.println(num); //if(Arrays.binarySearch(values, num)<0) if(!contains(values,num)) values[i] = num; else i--; } System.out.println(Arrays.toString(values)); Node root = new Node(values[0]); for(int i=1;iuser2.value) { return 1; }else { return user1.name.compareTo(user2.name); } } } ); Iterator iterator = results.keySet().iterator(); while(iterator.hasNext()) { String name = (String)iterator.next(); Integer value = (Integer)results.get(name); if(value > 1) { sortedResults.add(new User(name,value)); } } printResults(sortedResults); } private static void printResults(TreeSet sortedResults) { Iterator iterator = sortedResults.iterator(); while(iterator.hasNext()) { User user = (User)iterator.next(); System.out.println(user.name + ":" + user.value); } } public static void dealLine(String line,Map map) { if(!"".equals(line.trim())) { String [] results = line.split(","); if(results.length == 3) { String name = results[1]; Integer value = (Integer)map.get(name); if(value == null) value = 0; map.put(name,value + 1); } } } } 7、写一个 Singleton 出来。 第一种:饱汉模式 public class SingleTon { private SingleTon(){ } //实例化放在静态代码块里可提高程序的执行效率,但也可能更占用空间 private final static SingleTon instance = new SingleTon(); public static SingleTon getInstance(){ return instance; } } 第二种:饥汉模式 public class SingleTon { private SingleTon(){} private static instance = null;//new SingleTon(); public static synchronized SingleTon getInstance(){ if(instance == null) instance = new SingleTon(); return instance; } } 第三种:用枚举 public enum SingleTon{ ONE; } 第三:更实际的应用(在什么情况用单例) public class SequenceGenerator{ //下面是该类自身的业务功能代码 private int count = 0; public synchronized int getSequence(){ ++count; } //下面是把该类变成单例的代码 private SequenceGenerator(){} private final static instance = new SequenceGenerator(); public static SingleTon getInstance(){ return instance; } } 第四: public class MemoryDao { private HashMap map = new HashMap(); public void 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 static Singleton instance = new Singleton(); //这里提供了一个供外部访问本 class的静态方法,可以直接访问 public static Singleton 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); } 9、递归算法题 2 第1个人 10,第 2个比第 1个人大 2岁,依次递推,请用递归方式计算出第 8个人多大? package cn.itcast; import java.util.Date; public classA1 { public static void main(String [] args) { System.out.println(computeAge(8)); } public static int computeAge(int n) { if(n==1) return 10; return computeAge(n-1) + 2; } } public static void toBinary(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&& i0&& j>left) j--; //找出右边比中间值小的数 if(i<=j){ //将左边大的数和右边小的数进行替换 tempDate=strDate[i]; strDate[i]=strDate[j]; strDate[j]=tempDate; i++; j--; } }while(i<=j); //当两者交错时停止 if(ileft){ quickSort(strDate,left,j); } } /** *@param args */ public static void main(String[] args){ String[] strVoid=new String[]{"11","66","22","0","55","22","0","32"}; QuickSort sort=new QuickSort(); sort.quickSort(strVoid,0,strVoid.length-1); for(int i=0;i(一千零一拾一元 整)输出。 去零的代码: return sb.reverse().toString().replaceAll(" 零[拾佰仟]"," 零").replaceAll(" 零+万"," 万 ").replaceAll("零+元"," 元").replaceAll("零+","零"); public class RenMingBi { /** *@param args add by zxx ,Nov 29, 2008 */ private static final char[] data = new char[]{ '零','壹','贰','叁','肆','伍','陆','柒','捌','玖' }; private static final char[] units = new char[]{ '元','拾','佰','仟','万','拾','佰','仟','亿' }; public static void main(String[] args) { //TODO Auto-generated method stub System.out.println( convert(135689123)); } public static String convert(int money) { StringBuffer sbf = new StringBuffer(); int unit = 0; while(money!=0) { sbf.insert(0,units[unit++]); int number = money%10; sbf.insert(0, data[number]); money /= 10; } return sbf.toString(); } } 三. html&JavaScript&ajax 部分 1. 判断第二个日期比第一个日期大 如何用脚 本判断用户输入 的的字符串是下面 的时间格式 2004-11-21 必须要保 证用户的输 入是此格式 ,并且是时间 ,比如说月份不大于 12 等等 ,另外我需要用户输入两个 ,并且后一个 要比前一个晚,只允许用 JAVASCRIPT,请详细帮助作答, , //这里可用正则表达式判断提前判断一下格式,然后按下提取各时间字段内容
2. 用table 显示 n条记录,每 3行换一次颜色,即 1,2,3用红色字体, 4,5,6用绿色字体 , 7,8,9用红颜色字体。
1
2
3
4
5
6
7
8
9
10
3、HTML 的form 提交之前 如何验证数值文 本框的内容全部为 数字 ? 否则的话 提示用户并终 止提交 ?
4、请写出用于校验 HTML 文本框中输入的内容全部为数字的 javascript 代码 除了写完代码,还应该在网页上写出实验步骤和在代码中加入实现思路,让面试官一看就明白 你的意图和检查你的结果。 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() 有何区别 ? 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动作实现 它总是会检查所 含文件中的变化,适合用于包含动 态 页面,并且可以带参数 静态 INCLUDE 用include 伪码实现 ,定不会检查所含文件的变化,适用 于包含静态页面 <%@ include file=included.htm %> 15、两种跳转方式分别是什么 ?有什么区别 ? (下面的回答严重错误 ,应该是想问 forward和sendRedirect 的区别 ,毕竟出题的人不是专业搞 文字艺术的人,可能表达能力并不见得很强,用词不一定精准,加之其自身的技术面也可能存 在一些问题,不一定真正将他的意思表达清楚了,严格意思上来讲,一些题目可能根本就无人 能答,所以,答题时要掌握主动,只要把自己知道的表达清楚就够了,而不要去推敲原始题目 的具体含义是什么,不要一味想着是在答题) 答:有两种,分别为: 前者页面不会转向 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 = new String(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 employee order by deptid desc,salary 2、列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序 创建表: mysql> create table employee921(id int primary key auto_increment,name varchar(5 0),salary bigint,deptid int); 插入实验数据: mysql> insert into employee921 values(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,'z l',1000,2) ,(null,'zl',1100,2); 编写 sql语句: ()select avg(salary) from employee921 group by deptid; ()mysql> select employee921.id,employee921.name,employee921.salary,employee921.dep tid tid from employee921 where salary > (select avg(salary) from employee921 where deptid = tid); 效率低的一个语句 ,仅供学习参考使用 (在group by 之后不能使用 where,只能使用 having, 在group by 之前可以使用 where,即表示对过滤后的结果分组 ): mysql> select employee921.id,employee921.name,employee921.salary,employee921.dep tid tid from employee921 where salary > (select avg(salary) from employee921 group by deptid having deptid = tid); ()select count(*) ,tid from ( select employee921.id,employee921.name,employee921.salary,employee921.deptid tid from employee921 where salary > (select avg(salary) from employee921 where deptid = tid) ) as t group by tid ; 另外一种方式:关联查询 select a.ename,a.salary,a.deptid from emp a, (select deptd,avg(salary) avgsal from emp group by deptid ) b where a.deptid=b.deptid and a.salary>b.avgsal; 3、存储过程与触发器必须讲,经常被面试到 ? create procedure insert_Student (_name varchar(50),_age int ,out _id int) begin insert into student value(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 student FOREACHROW -> select * from student; 触发器不允许返回结果 create trigger update_Student BEFORE update on student FOREACHROW insert into student value(null,'zxx',28); mysql的触发器目前不能对当前表进行操作 create trigger update_Student BEFORE update on student FOREACHROW 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 article1 value(null,pTitle,pBid); -> select max(id) into pId from article1; -> end; -> | Query OK, 0 rows affected (0.05 sec) mysql> call insertArticle_Procedure('传智播客 ',1,@pid); -> | Query OK, 0 rows affected (0.00 sec) mysql> delimiter ; mysql> select @pid; +------+ | @pid | +------+ | 3 | +------+ 1 row in set (0.00 sec) mysql> select * from article1; +----+--------------+------+ | id | title | bid | +----+--------------+------+ | 1 | test | 1 | | 2 | chuanzhiboke | 1 | | 3 | 传智播客 | 1 | +----+--------------+------+ 3 rows in set (0.00 sec) 触发器的实验步骤: create table board1(id int primary key auto_increment,name varchar(50),ar ticleCount int); create table article1(id int primary key auto_increment,title varchar(50) ,bid int references board1(id)); delimiter | create trigger insertArticle_Trigger after insert on article1 for each ro w begin -> update board1 set articleCount=articleCount+1 where id= NEW.bid; -> end; -> | delimiter ; insert into board1 value (null,'test',0); insert into article1 value(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.salary where e.managerid=(select id from employee where name='zxx'); 2. select e.name,e.salary,m.name,m.salary from employees e,employees m where e.managerid = m.id and m.name='zxx'; 表中允许适当冗余,譬如,主题帖的回复数量和最后回复时间等 将姓名和密码单独从用户表中独立出来。这可以是非常好的一对一的案例哟! sql语句全部大写,特别是列名和表名都大写。特别是 sql命令的缓存功能,更加需要统一大小 写, sql 语句 ?发给 oracle 服务器 ?语法检查 和编译成为内部 指令 ?缓存和执 行指令。根据缓 存的 特点,不要拼凑条件,而是用 ?和PreparedStatment 还有索引对查询性能的改进也是值得关注的。 备注:下面是关于性能的讨论举例 4航班 3个城市 m*n select * from flight,city where flight.startcityid=city.cityid and city.name='beijing'; m + n select * from flight where startcityid = (select cityid from city where cityname='beijing'); select flight.id,'beijing',flight.flightTime from flight where startcityid = (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 只是简单的将两 个结果合并后就返回。这样,如果 返回的两个结果集中有重 复的数据,那么返回的结果集就会包含重复的数据了。 从效率上说 ,UNIONALL 要比 UNION 快很多 ,所以 ,如果可以确认合并的两个结果集中不 包含重复的数据的话,那么就使用 UNIONALL, 7.分页语句 取出 sql表中第 31 到40 的记录(以自动增长 ID为主键) sql server方案 1: select top 10 * from t where id not in (select top 30 id from t order by id ) orde by id sql server方案 2: select top 10 * from t where id in (select top 40 id from t order by id) order by id desc mysql方案: select * from t order by id limit 30,10 oracle方案: select * from (select rownum r,* from t where r<=40) where r>30 --------------------待整理进去的内容 ------------------------------------- pageSize=20; pageNo = 5; 1.分页技术 1(直接利用 sql语句进行分页,效率最高和最推荐的) mysql:sql = "select * from articles limit " + (pageNo-1)*pageSize + "," + pageSize; oracle: sql = "select * from " + "(select rownum r,* from " + "(select * from articles order by postime desc)" + "where rownum<= " + pageNo*pageSize +") tmp " + "where r>" + (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(Exception e){} 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(Exception e){} 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,name varchar(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 (select distinct name from score where score<=80) B:select distince name t1 from score where 80< all (select score 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,AccID varchar(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 distinctAccID from TestDB where AccID not in (select TestDB.AccIDfrom TestDB, (select * from TestDB where AccID='101') as db101 where TestDB.Occmonth=db101.Occmonth and TestDB.DebitOccur<=db101.DebitOccur ); 11.统计每年每月的信息 year month amount 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 exists sales; create table sales(id int auto_increment primary key,year varchar(10), month varchar(10), amount float(2,1)); insert into sales values (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 from sales t where t.month='1' and t.year= sales.year) '1', (select t.amount from sales t where t.month='1' and t.year= sales.year) '2', (select t.amount from sales t where t.month='1' and t.year= sales.year) '3', (select t.amount from sales 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,title varchar(50), postuser varchar(10), postdate datetime,parentid int references articles(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, (select max(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,code varchar(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) from student2 group by name); //但是,如下语句没有问题: select * from student2 where id not in(select min(id) from student2 group by name); //于是 ,我想先把分组的结果做成虚表 ,然后从虚表中选出结果 ,最后再将结果作为删除的条件 数据。 delete from student2 where id not in(select mid from (select min(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); 14.航空网的几个航班查询题: 表结构如下: flight{flightID,StartCityID ,endCityID,StartTime} city{cityID, CityName) 实验环境: create table city(cityID int auto_increment primary key,cityName varchar(20)); create table flight (flightID int auto_increment primary key, StartCityID int references city(cityID), endCityID int references city(cityID), StartTime timestamp); //航班本来应该没有日期部分才好,但是下面的题目当中涉及到了日期 insert into city values(null,'北京 '),(null,'上海 '),(null,'广州 '); insert into flight values (null,1,2,'9:37:23'),(null,1,3,'9:37:23'),(null,1,2,'10:37:23'),(null,2,3,'10:37:23'); 1、查询起飞城市是北京的所有航班,按到达城市的名字排序 参与运算的列是我起码能够显示出来的那些列,但最终我不一定把它们显示出来。各个表组合 出来的中间结果字段中必须包含所有运算的字段。 select * from flight f,city c where f.endcityid = c.cityid and startcityid = (select c1.cityid from city c1 where c1.cityname = "北京 ") order by c.cityname asc; mysql> select flight.flightid,'北京 ' startcity, e.cityname fromflight,city e wh ere flight.endcityid=e.cityid and flight.startcityid=(select cityid from city wh ere cityname='北京 '); mysql> select flight.flightid,s.cityname,e.cityname from flight,city s,city e wh ere flight.startcityid=s.cityid and s.cityname='北京 ' and flight.endCityId=e.cit yID order by e.cityName desc; 2、查询北京到上海的所有航班纪录(起飞城市,到达城市,起飞时间,航班号) select c1.CityName,c2.CityName,f.StartTime,f.flightID from city c1,city c2,flight f where f.StartCityID=c1.cityID and f.endCityID=c2.cityID and c1.cityName='北京 ' and c2.cityName='上海 ' 3、查询具体某一天( 2005-5-8)的北京到上海的的航班次数 select count(*) from (select c1.CityName,c2.CityName,f.StartTime,f.flightID from city c1,city c2,flight f where f.StartCityID=c1.cityID and f.endCityID=c2.cityID and c1.cityName='北京 ' and c2.cityName='上海 ' and 查帮助获得的某个日期处理函数 (startTime) like '2005-5-8%' mysql中提取日期部分进行比较的示例代码如下: select * from flight where date_format(starttime,'%Y-%m-%d')='1998-01-02' 15.查出比经理薪水还高的员工信息: Drop table if not exists employees; create table employees(id int primary key auto_increment,name varchar(50) ,salary int,managerid int references employees(id)); insert into employees values (null,' lhm',10000,null), (null,' zxx',15000,1 ),(null,'flx',9000,1),(null,'tg',10000,2),(null,'wzg',10000,3); Wzg 大于 flx,lhm 大于 zxx 解题思路: 根据 sql语句的查询特点,是逐行进行运算,不可能两行同时参与运算。 涉及了员工薪水和经理薪水,所有,一行记录要同时包含两个薪水,所有想到要把这个表自关 联组合一下。 首先要组合出一个包含有各个员工及该员工的经理信息的长记录 ,譬如 ,左半部分是员工 , 右半部分是经理。而迪卡尔积会组合出很多垃圾信息,先去除这些垃圾信息。 select e.* from employees e,employees m where e.managerid=m.id and e.sala ry>m.salary; 16、求出小于 45 岁的各个老师所带的大于 12 岁的学生人数 数据库中有 3个表 teacher 表, student表, tea_stu 关系表。 teacher 表teaID name age student 表stuID name age teacher_student 表teaID stuID 要求用一条 sql查询出这样的结果 1.显示的字段要有老师 name, age 每个老师所带的学生人数 2 只列出老师 age为40 以下,学生 age为12 以上的记录 预备知识: 1.sql 语句是对每一条记录依次处理,条件为真则执行动作( select,insert,delete,update) 2.只要是迪卡尔积,就会产生 “垃圾 ”信息,所以,只要迪卡尔积了,我们首先就要想到 清除 “垃圾 ”信息 实验准备: drop table if exists tea_stu; drop table if exists teacher; drop table if exists student; create table teacher(teaID int primary key,name varchar(50),age int); create table student(stuID int primary key,name varchar(50),age int); create table tea_stu(teaID int references teacher(teaID),stuID int references student(stuID)); insert into teacher values(1,'zxx',45), (2,'lhm',25) ,(3,'wzg',26) ,(4,'tg',27); insert into student values(1,'wy',11), (2,'dh',25) ,(3,'ysq',26) ,(4,'mxc',27); insert into tea_stu values(1,1), (1,2), (1,3); insert into tea_stu values(2,2), (2,3), (2,4); insert into tea_stu values(3,3), (3,4), (3,1); insert into tea_stu values(4,4), (4,1), (4,2) ,(4,3); 结果: 2?3,3?2,4?3 解题思路 :(真实面试答题时,也要写出每个分析步骤,如果纸张不够,就找别人要) 1要会统计分组信息,统计信息放在中间表中: select teaid,count(*) from tea_stu group by teaid; 2接着其实应该是筛除掉小于 12 岁的学生 ,然后再进行统计 ,中间表必须与 student关联才能得 到12 岁以下学生和把该学生记录从中间表中剔除,代码是: select tea_stu.teaid,count(*) total from student,tea_stu where student.stuid=tea_stu.stuid and student.age>12 group by tea_stu.teaid 3.接着把上面的结果做成虚表与 teacher进行关联,并筛除大于 45 的老师 select teacher.teaid,teacher.name,total from teacher ,(select tea_stu.tea id,count(*) total from student,tea_stu where student.stuid=tea_stu.stuid and stu dent.age>12 group by tea_stu.teaid) as tea_stu2 where teacher.teaid=tea_stu2.tea id and teacher.age<45; 17.求出发帖最多的人: select authorid,count(*) total from articles group by authorid having total= (select max(total2) from (select count(*) total2 from articles group by authorid) as t); select t.authorid,max(t.total) from (select authorid,count(*) total from articles )as t 这条语句不行,因为 max 只有一列,不能与其他列混淆。 select authorid,count(*) total from articles group by authorid having total=max(total)也不行。 18、一个用户表中有一个积分字段,假如数据库中有 100 多万个用户,若要在每年第一天凌晨 将积分清零,你将考虑什么,你将想什么办法解决 ? alter table drop column score; alter table add colunm score int; 可能会很快,但是需要试验,试验不能拿真实的环境来操刀,并且要注意, 这样的操作时无法回滚的,在我的印象中,只有 inert update delete等DML 语句才能回滚, 对于 create table,drop table ,alter table 等DDL 语句是不能回滚。 解决方案一, update user set score=0; 解决方案二 ,假设上面的代码要执行好长时间 ,超出我们的容忍范围 ,那我就 alter table user drop column score;alter table user add column score int。 下面代码实现每年的那个凌晨时刻进行清零。 Runnable runnable = new Runnable(){ public void run(){ clearDb(); schedule(this,new Date(new Date().getYear()+1,0,0)); } }; schedule(runnable, new Date(new Date().getYear()+1,0,1)); 19、一个用户具有多个角色,请查询出该表中具有该用户的所有角色的其他用户。 select count(*) as num,tb.id from tb, (select role from tb where id=xxx) as t1 where tb.role = t1.role and tb.id != t1.id group by tb.id having num = select count(role) from tb where id=xxx; 20. xxx 公司的 sql面试 Table EMPLOYEES Structure: EMPLOYEE_IDNUMBER Primary Key, FIRST_NAME VARCHAR2(25), LAST_NAME VARCHAR2(25), Salary number(8,2), HiredDate DATE, Departmentid number(2) Table Departments Structure: Departmentid number(2) Primary Key, DepartmentName VARCHAR2(25). (2)基于上述 EMPLOYEES 表写出查询 :写出雇用日期在今年的 ,或者工资在 [1000,2000]之间 的,或者员工姓名 (last_name)以’Obama’打头的所有员工 ,列出这些员工的全部个人信息 。(4 分) select * from employees where Year(hiredDate) = Year(date()) or (salary between 1000 and 200) or left(last_name,3)='abc'; (3) 基于上述 EMPLOYEES 表写出查询:查出部门平均工资大于 1800 元的部门的所有员工 ,列 出这些员工的全部个人信息 。(4分) mysql> select id,name,salary,deptid did from employee1 where (select avg(salary) from employee1 where deptid = did) > 1800; (4) 基于上述 EMPLOYEES 表写出查询:查出个人工资高于其所在部门平均工资的员工,列出 这些员工的全部个人信息及该员工工资高出部门平均工资百分比 。(5分) select employee1.*,(employee1.salary-t.avgSalary)*100/employee1.salary from employee1, (select deptid,avg(salary) avgSalary fromemployee1 group by deptid) as t where employee1.deptid = t.deptid and employee1.salary>t.avgSalary; 21、注册 Jdbc驱动程序的三种方式 22、用 JDBC 如何调用存储过程 代码如下: package com.huawei.interview.lym; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Types; public class JdbcTest { /** *@param args */ public static void main(String[] args) { //TODO Auto-generated method stub Connection cn = null; CallableStatement cstmt = null; try { //这里最好不要这么干,因为驱动名写死在程序中了 Class.forName("com.mysql.jdbc.Driver"); //实际项目中,这里应用 DataSource数据,如果用框架, //这个数据源不需要我们编码创建,我们只需 Datasource ds = context.lookup() //cn = ds.getConnection(); cn = DriverManager.getConnection("jdbc:mysql:///test","root","root"); cstmt = cn.prepareCall("{call insert_Student(?,?,?)}"); cstmt.registerOutParameter(3,Types.INTEGER); cstmt.setString(1, "wangwu"); cstmt.setInt(2, 25); cstmt.execute(); //g