JDBC编程ITJOB深圳市计算机行业协会JAVA组2007.4本章的主要内容–对数据库进行SQL语句进行基本操作–预编译语句–使用事务–事务的级别控制–使用存储过程–操作元数据–可滚动的和可更新的结果集–批处理更新–字符大对象CLOB–二进制大对象BLOB–RowSet新特性使用DDL,DML语言对数据库进行基本操作•创建表并插入数据及修改数据•查询数据库里的数据通过ResultSet接口来对结果集操作.操作的用法类似于Iterator的用法.每行记录又是由多列组成的,按从左至右的顺序对各列进行处理可以获得较高的执行效率。ResultSet接口的getXXX()方法可以从某列中获得结果,XXX表示JDBC的数据类型。预编译语句(PreparedStatement)Statement对象在每次执行SQL语句时都将该语句传给数据库,在多次执行同一语句时,这样做效率较低。这时可以使用PreparedStatement对象.PreparedStatement对象的SQL语句还可以接受参数。在语句中指出需要接受哪些参数,然后进行预编译。在每一次执行时,可以给SQL语句传输不同的参数,这样就大大提高了灵活性。PreparedStatement接口是Statement接口派生的子接口,因此它可以使用Statement接口中的方法。使用事务如果事务中所有命令都能正确执行,就可以提交这个事务;否则,如果事务中有一个命令出现错误,回滚这个事务,并返回到提交之前的状态,好像什么也没有发生。把命令组合成事务的主要原因是保证数据库的完整性。对于一个事务而言,要么事务中语句全部得到正确执行,事务就可被提交了,要么它中间出现错误。后一种情况,可以调用rollback()方法,数据库将自动放弃上一次提交事务以来的全部变化。一个数据库连接的缺省模式是autocommit模式,每个SQL命令一执行就会提交给数据库。一旦某个命令已提交,就不能把它回退。可以用Connection接口的getAutocommit()方法,检验数据库的目前自动提交模式设置。用命令con.setAutoCommit(false)方法关闭自动提交模式。用con.commit()命令提交事务。用con.rollback()回滚一个事务。事务的级别控制•脏读:当应用程序使用了被另一个应用程序修改过的数据,而这个数据处于未提交状态时,就会发生脏读。第二个应用程序随后会请求回滚被其修改的数据。第一个事务使用的数据就会被损坏,或者变脏。•不可重复的读:当一个事务获得了数据,而该数据随后被一个单独的事务所更改时,若第一个事务再次读取更改后的数据,就会发生不可重复的读。这样,第一个事务进行了一个不可重复的读。•虚读:当事务通过某种查询获取了数据,另一个事务修改了部分该数据,原来的事务第二次获取该数据时,就会发生虚读。第一个事务现在会有不同的结果集,它可能包含虚读。事务的级别控制–TRANSACTION_NONE说明不支持事务–TRANSACTION_READ_UNCOMMITTED说明在提交前一个事务可以看到另一个事务的变化。这样脏读,不可重复的读和虚读都是允许的。–TRANSACTION_READ_COMMITTED说明读取未提交的数据是不允许的。这个级别仍然允许不可重复的读和虚读产生。–TRANSACTION_REPEATABLE_READ说明事务保证能够再次读取相同的数据而不会失败,但虚读仍然会出现。–TRANSACTION_SERIALIZABLE是最高的事务级别,它防止脏读,不可重复读和虚读。事务的级别控制为什么不是所有事务都运行在TRANSACTION_SERIALIZABLE模式以保证最高程度的数据完整性呢?问题在于,和处理多线程编程有关的问题相似,事务保护的级别越高,性能损失就越大。假定您的数据库和JDBC驱动程序支持这个特性,则给定一个Connection对象,您可以明确地设置想要的事务级别:con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);使用存储过程•随着Java语言日趋流行,几个数据库厂商---Oracle(Oracle数据库)和IBM(db2数据库)都起用了Java语言创建存储过程,还可以在不同数据库之间移动存储过程。•存储过程可以支持三种类型的参数:IN,OUT和INOUT,这对于存储过程在数据库内部真正能做什么来说,带来了很大的灵活性。不管存储过程是用什么语言编写的,它都能以一种标准的方式从Java应用程序调用。使用存储过程您需要创建一个CallableStatement对象。为了标识存储过程和过程需要的参数的类型和数量,还要允许使用三种类型的调用。下面的清单说明了这三种类型(假定我们正在调用一个名为StudentList的存储过程):–{callStudentList}如果过程不需要参数–{callStudentList(?,?)}如果过程需要两个参数–{?=callStudentList(?,?)}如果参数需要两个参数并返回一个(函数的调用)如:cs.registerOutParameter(2,Types.CHAR);操作元数据JDBCMetaData(元数据)----描述数据的数据。它的接口有:•DatabaseMetaData(数据库元数据)•ResultSetMetaData(结果集元数据)数据库的一些常用信息可通过DatabaseMetaData对象的下列方法获得。–getURL()//返回一个String对象,代表数据库的URL.–getUserName()//返回此连接使用的数据库的用户名–isReadOnly()//返回一个boolean值,指示数据库是否只允许读操作。–getDatabaseProduceName()//返回数据库的产品名称可滚动的和可更新的结果集•可滚动的结果集表示在结果集中前后滚动显示数据。可更新的结果集表示可以通过结果集来更新数据库里的数据。•可滚动的ResultSet可以使用以下方法:–absolute()–afterLast()–beforeFirst()–first()–getRow()–isAfterLast()–isBeforeFirst()–isFirst()–isLast()–last()–moveToCurrentRow()//仅对可更新的ResultSet有效–previous()–relative(introws)//将游标移动相对量的行,或者正方向或者负方向可滚动的和可更新的结果集为了让查询返回可滚动的结果集,你必须用Statementstmt=con.createStatement(type,concurrency);得到一个不同的Statement对象。对于PreparedStatement,调用PreparedStatementstmt=con.preparedStatement(command,type,concurrency);可滚动的和可更新的结果集•ResultSet类型值–TYPE_FORWARD_ONLY结果集不可滚动–TYPE_SCROLL_INSENSITIVE结果集可滚动,但不反映数据库的变化–TYPE_SCROLL_SENSITIVE结果集可滚动,并反映数据库的变化•ResultSet同步值–CONCUR_READ_ONLY不能用结果集更新数据库–CONCUR_UPDATABLE可以用结果集更新数据库可滚动的和可更新的结果集JDBC2.0为每个数据类型提供了与它相应的updateXxx()方法,updateDouble(),updateString()等等updateXxx()方法只能改变当前光标的记录值,而不能改变数据库中数据。调用updateRow()方法把修改后的数据保存到数据库中。如果移动到另一行之前,没有调用updateRow()方法,本行中所有的更新将被撤消。也可以调用cancelRowUpdates()方法,撤消本行中的所有修改。例如:Stringquery=select*fromstudent;ResultSetrs=stmt.executeQuery(query);while(rs.next()){doubleage=rs.getInt(age);rs.updateInt(age,age+1);rs.updateRow();可滚动的和可更新的结果集往数据库中添加一个新记录:首先用moveToInsertRow()方法把光标移动到指定位置(它称为插入行)。接着,调用updateXxx()方法,在插入位置创建一个新行。最后,调用insertRow()方法,把这个新行发送给数据库。插入完成后,调用moveToCourrentRow()方法把光标移回调用moveToInsertRow()方法以前的位置。例:rs.moveToInsertRow();rs.updateString(name,李雨春);rs.updateInt(age,21);rs.insertRow();rs.moveToCurrentRow();调用下面的方法,可以删除位于光标下面的一行:rs.deleteRow();deleteRow()方法会立即把这行从结果集和数据库中删除。批处理更新•批处理更新功能可以一次向数据库提交多个更新操作,要求数据库进行处理。一起提交多个更新(而非一个一个单独地提交更新)在某些情况下将大大提高性能。•可以利用Statement,PreparedStatement,CallableStatement对象来提交批处理更新。如:stmt.addBatch(insertintostudentvalues('刘德华',51));stmt.addBatch(insertintostudentvalues('猪八戒',128));int[]updateCounts=stmt.executeBatch();字符大对象CLOB在mssqlserver2000里面并没有字符大对象这个数据类型,但是可以通过nchar类型来代替字符大对象数据,但是只能存放3k字符以下的。在ORACLE数据库里面存在字符大对象CLOB数据类型。该数据类型用来存放文本类型的数据。SQL代码:ORACLE的实现,在运行该例子之前,首先把ORACLE的驱动文件classes12.jar加到classpath里面。然后打开ORACLE数据库,建立一张表。SQL语句如下:CREATETABLEMESSAGES(IDVARCHAR2(20),TITLEVARCHAR2(30),AUTHORVARCHAR(20),MESSAGECLOB);)字符大对象CLOB下面看下MSSQLSERVER数据库的实现(首先在查询分析器里面运行下列SQL语句:CREATETABLEmessages(idchar(30),titlechar(40),authorchar(20),messagentext)二进制大对象BLOB该数据类型是用来存放图片文件的。在MSSQLSERVER2000没有该数据类型,那么可以用binary数据类型代替,但是该数据只能存放小7k的图片。在ORACLE数据库里,有BLOB数据类型,来直接存放图片文件,直接操作该数据类型。对不支持BLOB数据类型的MSSQLSERVER2000数据库,我们可以用二进制流进行读取图片文件。ORACLE的实现:SQL语句:CREATETABLEAUTHORS(AUTHORVARCHAR2(40),PHOTOBLOB);二进制大对象BLOBMSSQLSERVER2000的实现SQL语句:CREATETABLEauthors(authorchar(50),photoimageNOTNULL)RowSet新特性Java5在JavaDatabaseConnectivity(JDBC)方面加强了支持,其中加入了新的包javax.sql.rowset,javax.sql.rowset.serial,jav