欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

数据库面试

程序员文章站 2022-04-21 23:37:16
...

1.JDBC实现分页: 上面几位仁兄的想法是对的,他是说查询时去掉前N页及N1之后的页的数据但写法上好象有点问题,我写的也许更易懂一点. SELECT TOP 20 * FROM VIPMES where 主键 NOT in (SELECT Top (当页前的记录数量) 主键 FROM VIPMES order by 主键 asc unit

1.JDBC实现分页:

上面几位仁兄的想法是对的,他是说查询时去掉前N页及N+1之后的页的数据但写法上好象有点问题,我写的也许更易懂一点.
SELECT TOP 20 * FROM VIPMES where 主键 NOT in
(SELECT Top (当页前的记录数量) 主键 FROM VIPMES order by 主键 asc
unit
SELECT Top (当页后的记录数量) 主键 FROM VIPMES order by 主键 desc)

其中,(当页前的记录数量)及(当页后的记录数量)可用算出结果代入.
比如数据条数为M,每页显示P行,现在显示第N页
则当前页前记录数为(N-1)*p,(当页后的记录数量)为M-N*P

2.游标

在数据库开发过程中,当你检索的数据只是一条记录时,你所编写的事务语句代码往往使用SELECT INSERT 语句。但是我们常常会遇到这样情况,即从某一结果集中逐一地读取一条记录。那么如何解决这种问题呢?游标为我们提供了一种极为优秀的解决方案。

1.游标和游标的优点

在数据库中,游标是一个十分重要的概念。游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标总是与一条SQL 选择语句相关联因为游标由结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成。当决定对结果集进行处理时,必须声明一个指向该结果集的游标。如果曾经用 C 语言写过对文件进行处理的程序,那么游标就像您打开文件所得到的文件句柄一样,只要文件打开成功,该文件句柄就可代表该文件。对于游标而言,其道理是相同的。可见游标能够实现按与传统程序读取平面文件类似的方式处理来自基础表的结果集,从而把表中数据以平面文件的形式呈现给程序。

我们知道关系数据库管理系统实质是面向集合的,在MS SQL SERVER 中并没有一种描述表中单一记录的表达形式,除非使用where 子句来限制只有一条记录被选中。因此我们必须借助于游标来进行面向单条记录的数据处理。由此可见,游标允许应用程序对查询语句select 返回的行结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作;它还提供对基于游标位置而对表中数据进行删除或更新的能力;而且,正是游标把作为面向集合的数据库管理系统和面向行的程序设计两者联系起来,使两个数据处理方式能够进行沟通。

2. 游标种类


MS SQL SERVER 支持三种类型的游标:Transact_SQL 游标,API 服务器游标和客户游标。
(1)Transact_SQL 游标
Transact_SQL 游标是由DECLARE CURSOR 语法定义、主要用在Transact_SQL 脚本、存储过程和触发器中。Transact_SQL 游标主要用在服务器上,由从客户端发送给服务器的Transact_SQL 语句或是批处理、存储过程、触发器中的Transact_SQL 进行管理。 Transact_SQL 游标不支持提取数据块或多行数据。
(2) API 游标
API 游标支持在OLE DB, ODBC 以及DB_library 中使用游标函数,主要用在服务器上。每一次客户端应用程序调用API 游标函数,MS SQL SEVER 的OLE DB 提供者、ODBC驱动器或DB_library 的动态链接库(DLL) 都会将这些客户请求传送给服务器以对API游标进行处理。
(3) 客户游标
客户游标主要是当在客户机上缓存结果集时才使用。在客户游标中,有一个缺省的结果集被用来在客户机上缓存整个结果集。客户游标仅支持静态游标而非动态游标。由于服务器游标并不支持所有的Transact-SQL 语句或批处理,所以客户游标常常仅被用作服务器游标的辅助。因为在一般情况下,服务器游标能支持绝大多数的游标操作。由于API 游标和Transact-SQL 游标使用在服务器端,所以被称为服务器游标,也被称为后台游标,而客户端游标被称为前台游标。在本章中我们主要讲述服务器(后台)游标。

使用游标

  这里要做一个声明,我们所说的游标通常是指显式游标,因此从现在起没有特别指明的情况,我们所说的游标都是指显式游标。要在程序中使用游标,必须首先声明游标。

  声明游标

  语法:

CURSOR cursor_name IS select_statement;


  在PL/SQL中游标名是一个未声明变量,不能给游标名赋值或用于表达式中。

  例:

DELCARE
CURSOR C_EMP IS SELECT empno,ename,salary
FROM emp
WHERE salary>2000
ORDER BY ename;
........
BEGIN


  在游标定义中SELECT语句中不一定非要表可以是视图,也可以从多个表或视图中选择的列,甚至可以使用*来选择所有的列 。

  打开游标

  使用游标中的值之前应该首先打开游标,打开游标初始化查询处理。打开游标的语法是:

OPEN cursor_name


  cursor_name是在声明部分定义的游标名。

  例:

OPEN C_EMP;


  关闭游标

  语法:

CLOSE cursor_name


  例:

CLOSE C_EMP;


  从游标提取数据

  从游标得到一行数据使用FETCH命令。每一次提取数据后,游标都指向结果集的下一行。语法如下:

FETCH cursor_name INTO variable[,variable,...]


  对于SELECT定义的游标的每一列,FETCH变量列表都应该有一个变量与之相对应,变量的类型也要相同。

  例:

SET SERVERIUTPUT ON
DECLARE
v_ename EMP.ENAME%TYPE;
v_salary EMP.SALARY%TYPE;
CURSOR c_emp IS SELECT ename,salary FROM emp;
BEGIN
OPEN c_emp;
FETCH c_emp INTO v_ename,v_salary;
DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename
||'is'|| v_salary);
FETCH c_emp INTO v_ename,v_salary;
DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename
||'is'|| v_salary);
FETCH c_emp INTO v_ename,v_salary;
DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename
||'is'|| v_salary);
CLOSE c_emp;
END


  这段代码无疑是非常麻烦的,如果有多行返回结果,可以使用循环并用游标属性为结束循环的条件,以这种方式提取数据,程序的可读性和简洁性都大为提高,下面我们使用循环重新写上面的程序:

SET SERVERIUTPUT ON
DECLARE
v_ename EMP.ENAME%TYPE;
v_salary EMP.SALARY%TYPE;
CURSOR c_emp IS SELECT ename,salary FROM emp;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO v_ename,v_salary;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename
||'is'|| v_salary);
END


  记录变量

  定义一个记录变量使用TYPE命令和%ROWTYPE,关于%ROWsTYPE的更多信息请参阅相关资料。

  记录变量用于从游标中提取数据行,当游标选择很多列的时候,那么使用记录比为每列声明一个变量要方便得多。

  当在表上使用%ROWTYPE并将从游标中取出的值放入记录中时,如果要选择表中所有列,那么在SELECT子句中使用*比将所有列名列出来要安全得多。

  例:

SET SERVERIUTPUT ON
DECLARE
R_emp EMP%ROWTYPE;
CURSOR c_emp IS SELECT * FROM emp;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO r_emp;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
END LOOP;
CLOSE c_emp;
END;


  %ROWTYPE也可以用游标名来定义,这样的话就必须要首先声明游标:

SET SERVERIUTPUT ON
DECLARE
CURSOR c_emp IS SELECT ename,salary FROM emp;
R_emp c_emp%ROWTYPE;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO r_emp;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
END LOOP;
CLOSE c_emp;
END;


 
  游标FOR循环

  在大多数时候我们在设计程序的时候都遵循下面的步骤:

  1、打开游标

  2、开始循环

  3、从游标中取值

  4、检查那一行被返回

  5、处理

  6、关闭循环

  7、关闭游标

3. Collection和Collections的区别

java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。

java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

具体的差别看看Java API文档就知道了。

4. Question: What do youunderstand by Synchronization?

Answer:Synchronization is a process of controlling the access of shared resources by the multiplethreads in such a manner that only one thread can access one resource at a time.In non synchronized multithreaded application, it is possible for one thread tomodify a shared object while another thread is in the process of using orupdating the object''s value. Synchronization prevents such type of datacorruption.

E.g.Synchronizing a function:

publicsynchronized void Method1 () {

// Appropriate method-related code.

}

E.g.Synchronizing a block of code inside a function:

publicmyFunction (){

synchronized (this) {

// Synchronized code here.

}

}

5.Question: What isCollection API?

Answer:The Collection API is a set of classes and interfaces that support operation oncollections of objects. These classes and interfaces are more flexible, morepowerful, and more regular than the vectors, arrays, and hashtables ifeffectively replaces.

Exampleof classes: HashSet, HashMap, ArrayList, LinkedList, TreeSet and TreeMap.

Exampleof interfaces: Collection, Set, List and Map.

6.Question: Is Iterator aClass or Interface? What is its use?

Answer:Iterator is an interface which is used to step through the elements of a Collection.

7.Question: What issimilarities/difference between an Abstract class and Interface?

Answer: Differences are as follows:

Interfacesprovide a form of multipleinheritance. Aclass can extend only one other class.

Interfaces are limited to publicmethods and constants with no implementation. Abstract classes can have apartial implementation, protected parts, static methods, etc.

AClass may implement several interfaces. But in case of abstract class, a classmay extend only one abstract class.

Interfacesare slow as it requires extra indirection to to find corresponding method in inthe actual class. Abstract classes are fast.

8.Question: Name the containers which uses BorderLayout as their default layout?

Answer: Containers which uses Border Layoutas their default are: window, Frame and Dialog classes.

9.Question: What do youunderstand by Synchronization?

Answer: Synchronization is a process of controlling the access of sharedresources by the multiple threads in such a manner that only one thread canaccess one resource at a time. In non synchronized multithreadedapplication, it is possible for one thread to modify a shared object whileanother thread is in the process of using or updating the object''s value.Synchronization prevents such type of data corruption.

E.g. Synchronizing a function:

public synchronized void Method1 () {

// Appropriate method-related code.

}

E.g. Synchronizing a block of code inside afunction:

public myFunction (){

synchronized (this) {

// Synchronized code here.

}

}

10.Question: What is Collection API?

Answer: The Collection API is a set ofclasses and interfaces that support operation on collections of objects. Theseclasses and interfaces are more flexible, more powerful, and more regular thanthe vectors, arrays, and hashtables if effectively replaces.

Example of classes: HashSet, HashMap,ArrayList, LinkedList, TreeSet and TreeMap.

Example of interfaces: Collection, Set,List and Map.

11.Question: Is Iterator a Class or Interface? What isits use?

Answer: Iterator is an interface which isused to step through the elements of a Collection.

12.构造器Constructor是否可被override(构造函数)
答:构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading
1). 构造器不能是native,final,static,synchronized的,可以是public,private,或什么都没有。
2). 构造器函数里可以写return呢,但后面什么都不许有(包括null)
3). 构造器不能返回值.
但如果有个"构造器"返值了,它就不是构造器喽,只是个普通方法
4). super();this();这两个方法只能在构造方法里调用.
5). 成员变量声明时候赋值,比构造函数还早.

13.在 java.sql 这个包里面有几个常用的接口,在进行JDBC编程里面会经常用到。

Connection

Statement

PreparedStatement

CallableStatement

1、Connection 接口,这个接口天天用,年年用,不用再说了。

2、Statement 接口。

在各个论坛上的文章里面,经常看到别人写的代码,都是很不规范,甚至存在安全隐患。

如:他们会这样写:

Statement stat = con.createStatement();

ResultSet rs = stat.executeQuery("select * from TabName whereuserName='"+userName+"'");

有的甚至将这些代码写在JSP页面中,另偶实在困惑。

如果要这样回变量,怎么不用PreparedStatement这个接口呢。

用到此接口时,最好直接写出完整的SQL语句:

如:ResultSet rs = stat.executeQuery("select * fromTableName ");

如:ResultSet rs = stat.eecuteQuery("select count(*) fromTableName");

3、PreparedStatement 接口,非常常用的接口。

用法:

PreparedStatement ps =con.prepareStatement(strSql);

strSql中的问号代码所传的参数,有几个就传几个。而且要对应相应的类型。

如:

String strSql = "select * from TableNamewhere userName=? and password=?";

PreparedStatement ps =con.prepareStatement(strSql);

ps.setString(1,"xxxxxxxx");

ps.setString(2,"yyyyyyyy");

ResultSet rs = ps.executeQuery();

这个接口所传的SQL命令是预编译的,所以速度方面比Statement这个接口要快得多。

4、CallableStatement 接口。用来处理存储过程。

用法:

CallableStatement cs = con.prepareCall("{call存储过程名(?,?,?...)}");

后面所还的括号是所传递的参数。如果没有则不用括号。

目前,大部份的JDBC编程都会用存储过程代替直接写SQL语句了。

如:

CallableStatement cs =con.prepareCall("{call prcSelectResult(?,?)}");

cs.setString(1,"TableName");

cs.setString(2,"*");

ResultSet rs = cs.executeQuery();

prcSelectResult的代码:

create proc prcSelectResult

@tabName varchar(50),

@colName varchar(50)

as

begin

declare @strSqlvarchar(600)

set @strSql ="select "+@colName+" from "+@tabName

exec (@strSql)

end

当然,这只是一个简单的例子。

可以看出,上面的几种数据库操作中,以存储过程方法最佳。因为存储过程在数据库中是预编译的,因此,他比PreparedStatement接口的预编译命令又高一筹。。

Connection 接口中的三个方法可用于创建这些类的实例。下面列出这些类及其创建方法:
  Statement ─ 由方法createStatement 所创建。Statement 对象用于发送简单的 SQL 语句。
  PreparedStatement ─ 由方法prepareStatement 所创建。PreparedStatement 对象用于发送带有一个或多个输入参数( IN 参数)的SQL 语句。PreparedStatement拥有一组方法,用于设置 IN 参数的值。执行语句时,这些 IN参数将被送到数据库中。PreparedStatement 的实例扩展了 Statement ,因此它们都包括了 Statement 的方法。PreparedStatement 对象有可能比 Statement 对象的效率更高,因为它已被预编译过并存放在那以供将来。
  CallableStatement ─ 由方法prepareCall 所创建。CallableStatement 对象 用于执行 SQL 储存程序 ─ 一组可通过名称来调用(就象函数的调用那样)的 SQL 语句。CallableStatement 对象从 PreparedStatement 中继承了用于处理 IN 参数的方法,而且还增加了用于处理 OUT 参数和 INOUT 参数的方法。


  以下所列提供的方法可以快速决定应用哪个Connection 方法来创建不同类型的 SQL 语句:

Statement 方法用于: 简单的 SQL 语句(不带参数)
prepareStatement 方法用于: 带一个或多个 IN 参数的 SQL 语句 经常被执行的简单 SQL 语句
CallableStatement 方法用于: 调用已储存过程2.1.7 事务事务由一个或多个这样的语句组成:这些语句已被执行、完成并被提交或还原。当调用方法commit 或 rollback 时,当前事务即告就结束,另一个事务随即开始。
  缺省情况下,新连接将处于自动提交模式。也就是说,当执行完语句后,将自动对那个语句调用 commit 方法。这种情况下,由于每个语句都是被单独提交的,因此一个事务只由一个语句组成。如果禁用自动提交模式,事务将要等到 commit 或 llback 方法被显式调用时才结束,因此它将包括上一次调用 commit 或 rollback 方法以来所有执行过的语句。对于第二种情况,事务中的所有语句将作为组来提交或还原。方法 commit 使 SQL 语句对数据库所做的任何更改成为永久性的,它还将释放事务持有的全部锁。而方法 rollback 将弃去那些更改。
  有时用户在另一个更改生效前不想让此更改生效。这可通过禁用自动提交并将两个更新组合在一个事务中来达到。如果两个更新都是成功,则调用 commit 方法,从而使两个更新结果成为永久性的;如果其中之一或两个更新都失败了,则调用 rollback 方法,以将值恢复为进行更新之前的值。
  大多数 JDBC 驱动程序都支持事务。事实上,符合JDBC 的驱动程序必须支持事务。DatabaseMetaData 给出的信息描述 DBMS 所提供的事务支持水平。2.1.8 事务隔离级别如果 DBMS 支持事务处理,它必须有某种途径来管理两个事务同时对一个数据库进行操作时可能发生的冲突。用户可指定事务隔离级别,以指明 DBMS 应该花多大精力来解决潜在冲突。例如,当事务更改了某个值而第二个事务却在该更改被提交或还原前读取该值时该怎么办 假设第一个事务被还原后,第二个事务所读取的更改值将是无效的,那么是否可允许这种冲突? JDBC 用户可用以下代码来指示 DBMS 允许在值被提交前读取该值(“dirty 读取”),其中 con 是当前连接:
  con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);
  事务隔离级别越高,为避免冲突所花的精力也就越多。Connection 接口定义了五级,其中最低级别指定了根本就不支持事务,而*别则指定当事务在对某个数据库进行操作时,任何其它事务不得对那个事务正在读取的数据进行任何更改。通常,隔离级别越高,应用程序执行的速度也就越慢(由于用于锁定的资源耗费增加了,而用户间的并发操作减少了)。在决定采用什么隔离级别时,开发人员必须在性能需求和数据一致性需求之间进行权衡。当然,实际所能支持的级别取决于所涉及的 DBMS 的功能。
  当创建 Connection 对象时,其事务隔离级别取决于驱动程序,但通常是所涉及的数据库的缺省值。用户可通过调用 setIsolationLevel方法来更改事务隔离级别。新的级别将在该连接过程的剩余时间内生效。要想只改变一个事务的事务隔离级别,必须在该事务开始前进行设置,并在该事务结束后进行复位。我们不提倡在事务的中途对事务隔离级别进行更改,因为这将立即触发 commit 方法的调用,使在此之前所作的任何更改变成永久性的。

14、Transation(事务处理)的概念:
在更新数据库时,默认情况下,更改是永久性写入到数据库。然而这种默认行为可以通过编写程序来关闭。在自动交付关闭的情况下,如果在更新时发生问题,则对数据库的每个更改都能够取消(或者说回退到最初的值)。如果更新成功,那么之后可以将这些更改永久性提交给数据库。这种方式也称为事务管理。
我们需要确保,要么所有的操作都发生,要么所有的操作都不发生。这就是事务管理的原则。

二、在JAVA中使用Transation(事务管理)保证数据库的完整性:
我们使用try-catch-finally块来正确地应对事务管理,首先,记录自动提交的当前状态。然后,在try块中,调用setAutoCommit(false)并执行一系列的查询或更新。如果发生故障,则在catch块中调用rollback;如果事务成功,则在try块的结尾调用commit。不管哪种方式,都在finally块中重置自动提交的状态。例如:

Connection connection = DriverManager.getConnection(url,username,password);
boolean autoCommit = connection.getAutoCommit();
Statement statement;
try{
connection.setAutoCommit(false); // 关闭数据库的自动提交
statement = connection.createStatement();
statement.execute(…);
statement.execute(..);

connection.commit(); // 如果所有语句执行成功则提交事务
}
catch(SQLException sqle){
connection.rollback(); // 如果有异常发生则回滚所有的事务
}
finally{
if(statement!=null){statement.close();}
connection.setAutoCommit(autoCommit); // 重置自动提交的状态
}
上面的代码中,从DriverManager获取连接的语句在try/catch块之外。这样除非成功获取连接,否则不会调用rollback。如果把获取连接的语句放在try/catch快之内,一旦在连接成功后发生异常,由于rollback的作用会把已经建立的连接断开。但是getConnection方法也会抛出SQLException异常这个异常要么被外围的方法重新抛出,要么在单独的try/catch块内捕获。

15.获取当前日期的问题

select to_char(sysdate,'YYYYMMDD hh24:mi:ss') from dual

select to_char(systdate,’YYYYMMDDhh24:mi:ss’)from dual