参考: (JDBC常见面试题集锦1)http://blog.csdn.net/spidercoco/article/details/21439057
(JDBC常见面试题集锦2)http://blog.csdn.net/spidercoco/article/details/21508763
JDBC接口及相关类在java.sql包和javax.sql包里。我们可以用它来连接关系型数据库,执行SQL查询,存储过程,并处理返回的结构。
JDBC接口让Java程序和JDBC驱动实现了松耦合,使得切换不同的数据库变得更加简单。
JDBC API使用Java的反射机制来实现Java程序和JDBC驱动的松耦合。所有操作都是通过JDBC接口完成的,而驱动只有在通过Class.forName反射机制来加载的时候才会出现。
JDBC连接时和数据库服务器建立的一个会话,可以想象成时一个和数据库的Socket连接。
使用Class.forName(),驱动类就会注册到DriverManager里面并加载到内存中:
调用DriverManager.getConnection方法并传入数据库连接的URL,用户名、密码,就能获取到连接对象。
创建JDBC连接器需要提供四个基本数据:
JDBC驱动值
数据库连接字
使用DatabaseMetaData可以获取到服务器的信息。当和数据库建立了连接之后,可以通过调用Connection的getMetaData方法获取数据库的元信息。DatabaseMetaData里面有很多方法,通过它们可以获取到数据库的产品名称,版本号,配置信息等。
Statement是JDBC中用来执行数据库SQL查询语句的接口。通过调用连接对象的createStatement方法可以生成一个Statement对象。通过调用它的execute,execeteQuery,executeUpdate方法来执行静态SQL查询。
默认情况下,一个Statement同时只能打开一个ResultSet。如果想操作多个ResultSet的话,需要创建多个Statement。Statement接口的所有execute方法开始执行时都会默认关闭当前打开的ResultSet。
用来执行任意的SQL语句。如果查询结果时一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或update查询,就会返回false。可以通过getResultSet方法来获取ResultSet,或者通过getUpdateCount方法来回去更新的记录条数。
Note:execute方法不能用于PreparedStatement或者CallableStatement。
用来执行select查询,并且返回ResultSet。即使查询不到记录返回的ResultSet也不会为null(never null)。通常使用executeQuery来执行查询语句,如果传进来的是insert或者update的话,它会抛出SQLException。
Note:execute方法不能用于PreparedStatement或者CallableStatement。
用来执行inset,update或者delete语句(DML),或者什么也不返回的DDL语句。如果时DML语句的话,返回更新的条数;如果时DDL语句的话,返回0.
Note:execute方法不能用于PreparedStatement或者CallableStatement。
只有当不确定时什么语句的时候才应该使用execute方法,否则应该使用executeQuery或者executeUpdate方法。
有时候表会生成主键,这时候就可以用Statement的getGeneratedKeys方法来获取这个自动生成的主键的值。
可以用来限制返回的数据集的行数(通过SQL语句也可以实现这个功能)。
当数据库在执行一条查询语句时,查询到的数据是在数据库的缓存中维护的。ResultSet其实引用的是数据库中缓存的结果。
假设我们有一条查询返回了100行数据,我么把fetchsize设置成了10,那么数据库驱动每次只会取10条数据,也就是说得取10次。当每条数据需要处理的时间较长的时候并且返回数据又非常多的时候,这个可选参数就变的非常有用了。
public interface PreparedStatement extends Statement
代表的是一个预编译的SQL语句,它提供的setter方法可以传入查询的变量。
由于PreparedStatement是预编译的,通过它可以将对应的SQL语句高效的执行多次。由于PreparedStatement自动对特殊字符转义,避免了SQL注入攻击,因此应当尽量使用它。
使用setNull方法把null值绑定到指定的变量上,setNull方法需要传入参数的所以及SQL字段的类型(i.e. java.sql.Types.VARCHAR)。
执行SQL查询语句,返回ResultSet(never null)。
执行insert,update,delete语句(DML),或者什么也不返回的DDL语句。
如果时DML语句的话,返回更新的条数;如果时DDL语句的话,返回0.
不能直接用它来执行in条件语句。
解决办法参见: http://www.journaldev.com/2521/jdbc-preparedstatement-in-clause-alternative-approaches#dynamic-prepared-statement
通过JDBC的CallbleStatement接口来在数据库中执行存储过程。
参考:http://www.journaldev.com/2502/jdbc-callablestatement-stored-procedure-in-out-oracle-struct-cursor-example-tutorial
JDBC提供了批处理特性,可以在一次数据库调用中执行多条查询语句。
JDBC通过Statement和PreparedStatement中的addBatch和executeBatch方法来支持批处理。
参考: http://www.journaldev.com/2494/jdbc-batch-processing-example-tutorial-with-insert-statements
在查询数据库后会返回一个ResultSet,它就像查询结果集的一张数据表。
ResultSet对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了ResultSet的next方法游标会下移一行,如果没有更多的数据了,next方法会返回false。可以在for循环中用它来遍历数据集。
默认的ResultSet是不能更新的,游标也只能往下移,也就是说只能从第一行到最后一行遍历一遍。不过也可以创建可以回滚或者可更新的ResultSet,例如:
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
可以通过ResultSet的getter方法,传入列名或者从1开始的序号来获取列数据。
根据创建 Statement时输入参数的不同,会对应不同类型的ResultSet,以支持不同的ResultSet和并发类型。
ResultSet有两种并发类型:
public interface RowSet extends ResultSet (javax.sql)
RowSet的特性:
RowSet分为:
四种不同类型的RowSet:
RowSet继承自ResultSet.RowSet一个最大的好处是它可以是离线的,这样使得它更轻量级,同时便于在网络间进行传输。
具体使用哪个取决于需求,不过如果操作ResultSet对象的事件较长的话,最好选择一个离线的RowSet,这样可以释放数据库连接。
默认情况下,创建的数据库连接(Connection),是在自动提交的模式下的。这意味着只要我们执行完一条查询语句,就会自动进行提交。因此我们的每条查询,实际上都是一个事物,如果我们执行的时DML或者DDL,每条语句完成的时候,数据库就已经完成修改了。
有时候我们希望又一组SQL查询组成一个事务,如果中途出现一场,可以进行回滚。
Connection的setAutoCommit方法,可以用来关闭自动提交的特性。应该在需要手动提交时才关闭这个特性。
数据库通过表锁来管理事务,这个操作非常消耗资源。因此应当完成操作后尽快的提交事务。
参考: http://www.journaldev.com/2483/jdbc-transaction-management-and-savepoint-example-tutorial
通过Connect的rollback方法可以回滚事务。它会回滚这次事务中的所有修改操作,并释放当前连接所持有的数据库锁。
有时候事务保存了一组语句,我们希望回滚到这个事务的某个特定的点。JDBC保存点可以用来生成事务的一个检查点,使得事务可以回滚到这个检查点。
一旦事务提交或者回滚了,它生成的任何保存点都会自动释放并失效。回滚事务到某个特定的保存点后,这个保存点后所有其他的保存点会自动释放并且失效。
参考: http://www.journaldev.com/2483/jdbc-transaction-management-and-savepoint-example-tutorial
是定义在javax.sql中的一个接口,跟DriverManager相比,它的功能要更强大。可以使用它来创建数据库连接,驱动的实现类会实际去完成这个工作。
除了创建连接外,它还提供了如下的特性:
JDBC DataSource的示例参考: http://www.journaldev.com/2509/jdbc-datasource-example-oracle-mysql-and-apache-dbcp-tutorial
参考:http://www.journaldev.com/2513/tomcat-datasource-jndi-example-for-servlet-web-application
如果用DataSource来获取连接的话,通常获取连接的代码和驱动特定的DataSource是紧耦合的。另外,除了选择DataSource的实现类,剩下的代码基本都是一样的。
Apache的DBCP(commons-pool)用来解决这些问题,它提供的DataSource实现成为了应用程序和不同JDBC驱动间的一个抽象层。
参考:http://www.journaldev.com/2509/jdbc-datasource-example-oracle-mysql-and-apache-dbcp-tutorial
事物隔离级别的前提是一个多用户,多线程,多进程的并发系统,在这个系统中为了保证数据的一致性和完整性,引入了事务隔离级别的概念。对一个单用户,单线程的应用不存在这个问题。
一个事务读到另一个事务还没有提交的数据,称之为脏读。
当我们使用事务时,有可能出现这样的情况,有一行数据刚更新,与此同时另一个查询读到了这个刚更新的值,这样就导致了脏读,因为更新的数据还没有进行持久化,更新这行数据的业务可能会进行回滚,这样这个数据就是无效的。
解决办法:如果在第一个事务提交前,任何其他事物不可读取其修改过的值,则可以避免该问题。
一个事务先后读取同一条记录,但两次读取的数据不同,我们称之为不可重复读。
解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。
一个事务先后读取一个范围的记录,但两次读取的记录数不同,称之为幻读。
解决办法:如果在操作事务完成数据处理之前,任何其他事务都不可以添加新数据,则可以避免该问题。
不可重复读的重点是修改:同样的提交,读取过的数据,再次读取出来发现值不一样了。
幻读的重点在于新增或者删除:同样的条件,第一次和第二次读出来的记录数不一样。
从控制的角度看:
不可重复读:只需要锁住满足条件的记录。
幻读:要锁住满足条件及其相近的记录。
参考:http://jianfulove.iteye.com/blog/1843963
当使用事务时,数据库系统用锁来防止别人访问事务中用到的数据。数据库通过锁来防止脏读,不可重复读及幻读的问题。
数据库使用JDBC设置的隔离级别来决定它使用何种锁机制。我们可以通过Connection的getTransactionIsolation和setTransactionIsolation方法来获取和设置数据库的隔离级别。
隔离级别 | 事务 | 脏读 | 不可重复读 | 幻读 |
TRANSACTION_NONE | 不支持 | 不可用 | 不可用 | 不可用 |
TRANSACTION_READ_COMMITTED | 支持 | 阻止 | 允许 | 允许 |
TRANSACTION_READ_UNCOMMITTED | 支持 | 允许 | 允许 | 允许 |
TRANSACTION_REPEATABLE_READ | 支持 | 阻止 | 阻止 | 允许 |
TRANSACTION_SERIALIZABLE | 支持 | 阻止 | 阻止 | 阻止 |
java.sql.Connection:
Modifier and Type | Field and Description |
---|---|
static int |
TRANSACTION_NONE
A constant indicating that transactions are not supported.
|
static int |
TRANSACTION_READ_COMMITTED
A constant indicating that dirty reads are prevented; non-repeatable reads and phantom reads can occur.
|
static int |
TRANSACTION_READ_UNCOMMITTED
A constant indicating that dirty reads, non-repeatable reads and phantom reads can occur.
|
static int |
TRANSACTION_REPEATABLE_READ
A constant indicating that dirty reads and non-repeatable reads are prevented; phantom reads can occur.
|
static int |
TRANSACTION_SERIALIZABLE
A constant indicating that dirty reads, non-repeatable reads and phantom reads are prevented.
|
SQLWarning是SQLException的自雷,通过Connection,Statement,ResultSet的getWarnings方法都可以获取到它。SQLWarning不会中断查询语句的执行,只是用来提示用户存在相关的警告信息。
public interface Clob (java.sql)
public interface Blob (java.sql)
public class Timestamp extends Date (java.sql)