Franklyn 2012-04-17
JDBC
JavaDatabaseConnectivity(JDBC)是一个标准的JavaAPI,它由一组类和接口组成,Java应用程序开发人员使用它来访问数据库和执行SQL语句。WebLogicJDBC是JDBC规范的企业级实现,它为标准的JDBCAPI提供了大量的扩展
JDBC基础知识
一、采用JDBC访问数据库的基本步骤:
A.载入JDBC驱动程序
B.定义连接URL
C.建立连接
D.创建Statement对象
E.执行查询或更新
F.结果处理
G.关闭连接
二、载入JDBC驱动程序:
1.为了使代码尽可能地灵活,我们要避免对类名的引用进行硬编码(hard-coding),因此我们可以采用从Properties文件中载入驱动程序的方法,也可以使用在服务器中配置数据源(DataSource)的方法来避免在代码中硬编码
2.在开发过程中要保证CLASSPATH设定中包括驱动程序JAR文件所在的路径。在WEB服务
器上部署时要将JAR文件放在Web应用的WEB-INF/lib目录下。如果多个Web应用使用相同的数据库驱动程序可以将JAR文件放置在服务器使用的公共目录<%CATALINA_HOME%>\common\lib中
三、定义连接URL:
载入JDBC驱动程序之后,必须指定数据库服务器位置。指向数据库的URL所使用的协议是:
jdbc:子协议,并且载入服务器的主机名、端口、数据库名(或引用)。如:Oracle的连接URL:
jdbc:oracle:thin:@192.168.0.71:1521:UMV2
jdbc:oracle:采用Oracle驱动程序
thin:指连接服务器所采用的模式
@192.168.0.71:服务器的地址
1521:服务器的监听端口
UMV2:数据库名
四、建立连接:
1.一个数据库连接(Connection)可以通过其自身的getMetaData()来获取它的自身信息
2.默认情况下一个数据库的连接是自动提交模式的(auto-commit),也就是说每当一个SQL语句
被执行后其改变结果都会被自动提交,如果auto-commit模式被关闭,那么方法commit()必须被显式调用以提交改变结果,否则的话所有对数据库操作的结果都不会被保存
五、创建Statement对象:
在同一时间下,每个Statement对象只能打开一个ResultSet对象。所以,假如有两个同样结果的结果集在交叉访问,那么这两个结果集必定为两个不同的Statement对象所创建。如果在打开一个新的结果集的时候存在一个已经打开的结果集,则这个已经存在的结果集会被隐式的关闭
六、执行查询或更新:
在Statement对象中可以执行如下的操作:
A.查询操作:executeQuery(SQL语句)B.维护操作:executeUpdate(SQL语句)
C.批处理操作:executeBath()
七、结果处理:
1.ResultSet中行的第一列索引为1,而非0,访问ResultSet中的数据时要使用列名,而非索引
但要注意使用列名作为查询条件是大小写敏感的。
2.JDBC1.0中,我们只能在ResultSet中向前移动;在JDBC2.0中,我们可以在ResultSet中向
下(next)或向上(previous)移动,同样也可以移到特定的行(relative,absolute)
3.默认情况下ResultSet是不可更新的,且只能向前移动。下面的代码显示了如何创建一个可滚动的、对更新敏感的ResultSet
Statementstmt=con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSetrs=stmt.executeQuery("SELECTa,bFROMTABLE2");
//rswillbescrollable,willnotshowchangesmadebyothers,
//andwillbeupdatable
4.ResultSet和ResultSetMetaData没有直接提供方法返回查询所返回的行数。然而,在JDBC
2.0中,可以通过调用last()方法将游标定位到ResultSet的最后一行,然后调用getRow()方
法获取当前的行号。在JDBC1.0中,确定行数的惟一方式是重复调用ResultSet的next()方法,
直到它返回false为至
八、关闭连接:
在关闭数据库连接时应该以ResultSet、Statement、Connection的顺序进行
JDBC-PreparedStatement(预备语句)
一、PreparedStatement(预备语句)的创建:
首先按照标准的格式创建参数化语句,在实际使用之前发送参数到数据库进行编译。用问号表示语句中应该为具体的值所替换的位置。每次使用预备语句时,只需要使用相应的setXxx调用,替换语句中标记出来的参数。然后就可以和常规的语句一样,使用executeQuery或execute/executeUpdate修改表中的数据。例如:
Connectionconnection=DriverManager.getConnection(url,username,password);
//创建带问号的参数化语句
Stringtemplate="UPDATEmusicSETprice=?WHEREid=?";
PreparedStatementstatement=connection.prepareStatement(template);
floatnewPrices[]=getNewPrices();
intrecordingIDs=getIDs();
for(inti=0;i<recordingIDs.length;i++){
//用setXxx代替?
statement.setFloat(1,newPrices[i]);
statement.setInt(2,recordingIDs[i]);
//执行预备语句
statement.execute();}
二、使用PreparedStatement的好处:
1.依赖于服务器对预编译查询的支持,以及驱动程序处理原始查询的效率,预备语句在性能上的优势可能有很大的不同。
2.安全是预备语句的另外一个特点,我们推荐在通过HTML表单接受用户输入,然后对数据库进行更新时,一定要使用预备语句或存储过程。
3.预备语句还能够正确地处理嵌入在字符串中的引号以及处理非字符数据(比如向数据库发送序列化后的对象)
JDBC-CallableStatement(可调用语句)
一、使用CallableStatement(可调用语句)的优缺点:
1.优点:语法错误可以在编译时找出来,而非在运行期间;数据库存储过程的运行可能比常规的
SQL查询快得多;程序员只需知道输入和输出参数,不需了解表的结构。另外,由于数据库语言能够访问数据库本地的一下儿功能(序列,触发器,多重游标),因此用它来编写存储过程可能要比使用Java编程语言要简易一些。
2.缺点:存储过程的商业逻辑在数据库服务器上运行,而非客户机或Web服务器。而行业的发展趋势是尽可能多地将商业逻辑移出数据库,将它们放在JavaBean组件(或者在大型的系统中,EnterPriseJavaBean组件)中,在Web构架上采用这种方式的主要动机是:数据库访问和网络I/O常常是性能的瓶颈。
二、使用CallableStatement在JAVA中调用数据库存储过程:
1.定义对数据库过程的调用
A.无参数过程:{callprocedure_name}
B.仅有输入参数的过程:{callprocedure_name(?,?...)}
C.有一个输出参数的过程:{?Callprocedure_name}
D.既有输入参数又有输出参数的过程{?=callprocedure_name(?,?...)}
在过程的4种形式中要注意过程可能返回多个输出参数,并且参数的索引值从输出参数开始。因此前面最后例子中,第一个输入参数的索引值是2而不是1。
2.为过程准备CallableStatement
Stringprocedure=“{?=callprocedure_name(?,?)}”;
CallableStatementstatement=connection.prepareCall(procedure);
3.提供输入参数的值
在执行存储过程之前,我们需要调用与所要设置的项以及参数的类型相对应的setXxx,替换标记出来的输入参数
Statement.setString(2,”name”);
4.注册输出参数的类型
我们必须使用registerOutParameter注册每个输出参数的JDBC类型
Statement.registerOutParameter(n,type);
5.执行这个存储过程
Statement.execute();
6.访问返回的输出参数
可以通过调用getXxx访问每个对应的输出参数
例如:
Connectionconnection=DriverManager.getConnection(url,username,password);
Stringprocedure=“{?=callmyProc(?,?)}”;
CallableStatementstatement=connection.prepareCall(procedure);
statement.setString(2,×××);
statement.setFloat(3,×××);
statement.registerOutParameter(1,Types.INTEGER);
statement.execute();
introw=statement.getInt(1);
JDBC-Transation(事务处理)
一、Transation(事务处理)的概念:
在更新数据库时,默认情况下,更改是永久性写入到数据库。然而这种默认行为可以通过编写程序来关闭。在自动交付关闭的情况下,如果在更新时发生问题,则对数据库的每个更改都能够取消(或者说回退到最初的值)。如果更新成功,那么之后可以将这些更改永久性提交给数据库。这种方式也称为事务管理。
我们需要确保,要么所有的操作都发生,要么所有的操作都不发生。这就是事务管理的原则。
二、在JAVA中使用Transation(事务管理)保证数据库的完整性:
我们使用try-catch-finally块来正确地应对事务管理,首先,记录自动提交的当前状态。然后,在try块中,调用setAutoCommit(false)并执行一系列的查询或更新。如果发生故障,则在catch块中调用rollback;如果事务成功,则在try块的结尾调用commit。不管哪种方式,都在finally块中重置自动提交的状态。例如:
Connectionconnection=DriverManager.getConnection(url,username,password);
booleanautoCommit=connection.getAutoCommit();
Statementstatement;
try{
connection.setAutoCommit(false);//关闭数据库的自动提交
statement=connection.createStatement();
statement.execute(…);
statement.execute(..);
…
connection.commit();//如果所有语句执行成功则提交事务
}
catch(SQLExceptionsqle){
connection.rollback();//如果有异常发生则回滚所有的事务
}
finally{
if(statement!=null){statement.close();}
connection.setAutoCommit(autoCommit);//重置自动提交的状态
}
上面的代码中,从DriverManager获取连接的语句在try/catch块之外。这样除非成功获取连接,否则不会调用rollback。如果把获取连接的语句放在try/catch快之内,一旦在连接成功后发生异常,由于rollback的作用会把已经建立的连接断开。但是getConnection方法也会抛出SQLException异常这个异常要么被外围的方法重新抛出,要么在单独的try/catch块内捕获。
JDBC的常用API
一、Connection接口:
1.createStatement():创建数据库连接
2.prepareStatement(Stringsql):创建预处理语句
3.prepareCall(Stringsql):创建可调用语句
4.getAutoCommit():获取自动提交的模式
5.setAutoCommit():设置自动提交的模式
6.commit():提交所执行的SQL语句
7.rollback():回滚所执行的SQL语句
8.getMetaData():获取一个DatabaseMetaData对象,该对象包含了有关数据库的基本信息
9.close():关闭数据库连接
10.isClose():判断数据库连接是否超时或被显示关闭
二、Statement接口:
1.execute(Stringsql):执行SQL语句,如果返回值是结果集则为true,否则为false
2.executeQuery(Stringsql):执行SQL语句,返回值为ResultSet
3.executeUpdate(Stringsql):执行SQL语句,返回值为所影响的行数
4.addBatch(Stringsql):向当前Statement对象的命令列表中添加新的批处理SQL语句
5.clearBatch():清空当前Statement对象的命令列表
6.executeBatch():执行当前Statement对象的批处理语句,返回值为每个语句所影响的函数数组
7.getConnection():返回创建了该Statement对象的Connection对象
8.getQueryTimeout():获取等待处理结果的时间
9.setQueryTimeout():设置等待处理结果的时间
三、ResultSet接口:
1.first()/beforeFirst():将游标移动到ResultSet中第一条记录(的前面)
2.last()/afterLast():将游标移动到ResultSet中最后一条记录(的后面)
3.absolute(intcolumn):将游标移动到相对于第一行的指定行,负数则为相对于最后一条记录
4.relative(introws):将游标移动到相对于当前行的第几行,正为向下,负为向上
5.next():将游标下移一行
6.previous():将游标上移一行
7.insertRow():向当前ResultSet和数据库中被插入行处插入一条记录
8.deleteRow():将当前ResultSet中的当前行和数据库中对应的记录删除
9.updateRow():用当前ResultSet中已更新的记录更新数据库中对应的记录
10.cancelUpdate():取消当前对ResultSet和数据库中所做的操作
11.findColumn(StringcolumnName):返回当前ResultSet中与指定列名对应的索引
12.getRow():返回ResultSet中的当前行号
13.refreshRow():更新当前ResultSet中的所有记录
14.getMetaData():返回描述ResultSet的ResultSetMetaData对象
15.isAfterLast():是否到了结尾
16.isBeforeFirst():是否到了开头
17.isFirst():是否第一条记录
18.isLast():是否最后一条记录
19.wasNull():检查列值是否为NULL值,如果列的类型为基本类型,且数据库中的值为0,那么
这项检查就很重要。由于数据库NULL也返回0,所以0值和数据库的NULL不能区分。如果列的类型为对象,可以简单地将返回值与null比较
20.close():关闭当前ResultSet
四、ResultSetMetaData接口:
1.getColumnCount():返回ResultSet中列的数目
2.getColumnName():返回列在数据库中的名称
3.getColumnType():返回列的SQL类型
4.isReadOnly():表示该数据项是否为只读值
5.isNullable():表示该列是否可以存储NULL