`
fulerbakesi
  • 浏览: 561558 次
文章分类
社区版块
存档分类
最新评论

java基础教程-JDBC数据库访问技术

 
阅读更多
JDBC数据库访问技术
JDBC封装了与底层数据库的通信细节,提供了与数据库相关的类和接口,为数据库开发人员提供了一种面向应用的开发平台。
第一节JDBC概述
数据库是用于存储和处理数据的工具,数据库是构成了许多公司的重要基础。当前,由于数据库产品缤纷复杂,一个公司里经常出现同时使用多种数据库的现象。使用Java进行数据库开发时通过JDBC技术,可以一致性地访问不同的数据库,不用分别为不同平台的不同数据库编写各自不同的应用程序。
1、 JDBC的概念
JDBC(Java Data Base ConnectivityJava数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。同时,JDBC也是个商标名。
JDBC向应用程序开发者提供了独立于数据库的、统一的API,这个API提供了编写的标准,并考虑了所有不同应用程序设计的标准,其关键是一组由驱动程序实现的Java接口。驱动程序负责标准的JDBC调用,当应用程序被移植到不同的平台或数据库系统,应用程序不变,改变的是驱动程序,驱动程序扮演了多层数据库设计中的中间层的角色。如下图所示:

应用程序
JDBC
Oracle
驱动程序
Sybase
驱动程序
DB2
驱动程序
Informix
驱动程序
……
驱动程序

Java具有坚固、安全、易于使用、易于理解和可从网络上自动下载等特征,是编写数据库应用程序的杰出语言,所需要的只是Java应用程序与各种不同数据库之间进行对话的方法,而JDBC正是作为此种用途的机制。
随着越来越多的使用Java编程语言,对从Java中便捷的访问数据库的要求也在日益增加。对于服务器端的数据库应用,JDBC往往与RMICORBAJSPServletEJB等技术混合使用,用于实现多层结构的应用系统。
2、 数据库驱动程序
数据库厂商一般会提供一组API访问数据库。流行的数据库如OracleSQL ServerSybaseInformix都为客户提供了专用的API。有四种类型的数据库驱动程序,它们分别是:
u JDBCODBC
u 部分Java、部分本机驱动程序
u 中间数据访问服务器
u Java驱动程序
以下分别介绍。
JDBCODBC
JDBCODBC桥是一个JDBC驱动程序,它通过将JDBC操作转换为ODBC操作来实现JDBC操作。对ODBC,它像是通常的应用程序,桥为所有对ODBC可用的数据库实现JDBC。它作为sun.jdbc.odbc包实现,其中包含一个用来访问ODBC的本地库。桥是由IntersolvJavaSoft联合开发的。由于ODBC被广泛地使用,该桥地优点是让JDBC能够访问几乎所有地数据库。
通过odbc子协议,使用URL打开JDBC连接即可使用桥。建立连接前,必须将桥驱动程序类sun.jdbd.odbc.JdbcOdbcDriver添加到名为jdbc.driversjava.lang.System属性中,或用Java类加载器将其显示的加载。可以用如下方式显示加载:
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”)
加载时,ODBC驱动程序将创建自己的实例,同时在JDBC驱动程序管理器中进行注册。
桥驱动程序使用odbc子协议。该子协议的URL为以下的形式:
jdbc:odbc:<data-dource-name>[<attribute-name>=<attribute-value>]*
JDBCODBC桥在JDBC APIODBC API之间提供了一个桥梁,这个桥把标准的JDBC调用翻译成对应的ODBC调用,然后通过ODBC库把它们发送到ODBC数据源,如图所示:

JDBC
API
ODBC
API
JDBC-ODBC桥
ODBC层
数据源
Java应用程序

这种方式有一个明显的缺点就是效率相对低下,所以不推荐使用这种桥驱动程序,但它可以减少开发人员进行企业开发的麻烦。
部分Java、部分本机驱动程序
这种驱动使用Java实现与数据库厂商专有API的混和形式来提供数据访问。它比前一种方式要快。JDBC驱动将标准的JDBC调用转变为对数据库API的本地调用,该类型的驱动程序是本地部分Java技术性能的本机API驱动程序,如下图所示:

JDBC
API
厂商专有API
JDBC驱动程序
数据源
Java应用程序

在这种方式里,驱动程序和厂商专有的API必须在每个运行Java应用程序的客户端安装。
现在大多数的数据库厂商都在其数据库产品中提供驱动程序,这种使用方式比前一种有效。
中间数据访问服务器
这种方式使用一个中间数据访问服务器,通过这种服务器,它可以把Java客户端连接到多个数据库服务器上,如下图所示:

JDBC
API
JDBC驱动程序
本机驱动程序
数据源
Java应用程序
JDBC驱动程序

这种方式不需要客户端的数据库驱动,而是使用网络-服务器中间层来访问一个数据库。该类型的驱动程序是网络协议完全Java技术性能的驱动程序,它为Java应用程序提供了一种进行JDBC调用的机制。
使用该类型的驱动程序是平台无关的,并且不需要客户端的安装和管理,因此很适合做Internet的应用。
Java驱动程序
这种方式使用厂商专有的网络协议把JDBC API调用转换成直接的网络调用,这种方式的本质是使用套接字(Socket)进行编程。纯Java驱动运行在客户端,并且直接访问数据库,因此运行这个模式要使用一个两层的体系,如下图所示:

JDBC
API
JDBC驱动程序
数据源
Java应用程序

该类型的驱动程序是本地协议完全Java技术性能的驱动程序,同时它的使用也比较简单,客户端不需要安装任何中间件或者运行库。现在大部分厂商都提供第四类驱动程序的支持。
3、 JDBC的用途
Ø 与数据库建立连接
Ø 发送SQL语句
Ø 处理结果
4、 JDBC URL
JDBC URL的概念
JDBC URL提供了一种标识数据库的方法,可以使相应的驱动程序能识别该数据库并与之建立连接。JDBC的作用是提供某些约定,驱动程序编程员在构造它们的JDBC URL时应该遵循这些约定。
u 由于JDBC URL要与各种不同的驱动程序一起使用,因此,这些约定应非常灵活。首先,它们应允许不同的驱动程序使用不同的方案来命名数据库。
u JDBC URL应允许驱动程序编程员将一切所需的信息编入其中。
u JDBC URL应允许某种程度的间接性。即:JDBC URL可指向逻辑主机或数据库名,而这种逻辑主机或数据库名将由网络命名系统动态的转换为实际的名称。
JDBC URL的语法格式
JDBC URL的标准语法如下所示。它由三部分组成,各部分之间用冒号分割。
jdbd:<子协议>:<子名称>
JDBC URL的三个部分可分解如下:
Ø jdbc:协议,JDBC URL中的协议总是jdbc
Ø <子协议>:驱动程序名或数据库连接机制的名称。
Ø <子名称>:标识数据库的方法。子名称可以依不同的子协议而变化,使用子名称的目的是为定位数据库提供足够的信息。如果数据库是通过Internet来访问的,则在JDBC URL中应将网络地址作为子名称的一部分包括进去,且必须遵循如下所示的标准URL命名约定:
//主机名:端口/子协议
对于不同的数据库,厂商提供的驱动程序和连接的URL都不同,几个主要的数据库厂商与其对应的驱动程序和连接的URL如下所示:
数据库驱动程序和URL
数据库名
驱动程序
URL
MS SQL Server 2000
com.microsoft.jdbc.sqlserver.SQLServerDriver
Jdbc:Microsoft:sqlserver://[ip]:[port];user=[user];password=[password]
JDBC-ODBC
sun.jdbc.odbc.JdbcOdbcDriver
jdbc:odbc:[odbcsource]
Oracle oci8
orcle.jdbc.driver.OracleDriver
jdbc.oracle:oci8:@[sid]
Oracle thin Driver
oracle.jdbc.driver.OracleDriver
jdbd:oracle:thin:@[ip]:[port]:[sid]
Cloudscape
com.cloudscape.core.JDBCDriver
jdbc:cloudscape:database
MySQL
org.gjt.mm.mysql.Driver
jdbc:mysql:/ip/database,user,password
5、 ODBC子协议
子协议odbc是一种特殊情况。它是为指定ODBC风格的数据资源的URL而保留的,并允许在子名称后面指定任意多个属性值。
odbc子协议的完整语法为:
jdbcodbc<数据资源名称>[;<属性名>=<属性值>]*
例如:
jdbc:odbc:test
jdbc:odbc:test;UID=uid;PWD=pwd
6、事务
事务就是将一些SQL语句作为一个整体来执行,要么所有语句全部完成,要么一条语句都不执行。当调用方法commitrollback时,当前事务即告结束,另一个事务谁即开始。
缺省情况下,新连接处于自动提交模式,也就是说,当执行完语句后,将自动对那个语句调用commit方法。这种情况下,由于每个语句都是被单独提交的,因此,一个事务只由一个语句组成。如果禁用自动提交模式,事务将要等到commitrollback方法被显示调用时才结束,因此,它将包括上一次调用commitrollback方法以来所有执行过的语句。对于第二种情况,事务中的所有语句将作为组来提交或还原。
方法commit使SQL语句对数据库所做的任何更改成为永久性的,它还将释放事务持有的全部锁,而方法rollback将放弃那些更改。

第二节JDBC核心类和接口
Driver接口
每个数据库驱动程序必须实现Driver接口。我们在编程中要连接数据库,必须先装载特定厂商提供的数据库驱动程序(Driver),驱动程序的装载方法如下:
Class.forName(“<driver_class_name”>);
DriverManager
对于简单的应用程序,仅需要使用该类的方法getConnection,该方法将建立与数据库的连接。JDBC允许用户调用DriverManager类的方法getDrivergetDriversregisterDriverDriver类的方法connect,但在多数情况下,最好让DriverManager类管理建立连接的细节。
DriverManager类是JDBC的管理层,作用于用户和驱动程序之间,用于管理JDBC驱动程序。它跟踪可用的驱动程序,并在数据库和相应的驱动程序之间建立连接,另外,DriverManager类也处理诸如驱动程序登录时间限制及登录和跟踪消息的显示等事务。
作为初始化的一部分,DriverManager将试图装载系统属性“jdbc.drivers”所指的驱动程序类,这可以让用户定制在它们的应用程序中使用的JDBC驱动程序。例如,在WindowsHOME目录的/.hotjava/properties文件中,可以指定:
Jdbc.drivers=<驱动程序>
另外,程序还可以显示的装载JDBC驱动程序。例如:下述代码用于装载my.sql.Driver
Class.forName(“my.sql.Driver”);
DriverManager中有一个非常重要的方法,就是getConnection(parameter),通过这个方法可以获得一个连接。
getConnection
public static synchronized Connection getConnection(String url)
尝试建立一个和给定的URL的数据库连接,调用此方法时,DriverManager将在已注册的驱动中选择恰当的驱动来建立连接。
public static synchronized Connection getConnection(String url, Properties info)
与上类似,不过提供了一些属性,这些属性连接特定的数据库需要,至少包含userpassword属性。
public static synchronized Connection getConnection(String url, String user,String password)
连接到指定URL的数据库,使用用户名为user,密码为password
Connection接口
Connection对象代表与数据库的连接,也就是在已经加载的Driver和数据库之间建立连接。
连接过程包括所执行的SQL语句和在该连接上所返回的结果。一个应用程序可与单个数据库有一个或多个连接,或者可与许多数据库有连接。
close
public void close()
关闭到数据库的连接,在使用完连接之后必须关闭,否则连接会保持一段比较长的时间,直到超时。
commit
public void commit()
提交对数据库的更改,使更改生效。这个方法只有调用了setAutoCommit(false)方法后才有效,否则对数据库的更改会自动提交到数据库。
createStatement
public Statement createStatement()
throws SQLException
public Statement createStatement(intresultSetType, intresultSetConcurrency)
throws SQLException
public Statement createStatement(intresultSetType,
intresultSetConcurrency,
intresultSetHoldability)
throws SQLException
创建一个StatementStatement用于执行SQL语句。
prepareStatement
public PreparedStatement prepareStatement(Stringsql)
throws SQLException
public PreparedStatement prepareStatement(Stringsql,
intautoGeneratedKeys)
throws SQLException
public PreparedStatement prepareStatement(Stringsql,
int[]columnIndexes)
throws SQLException
public PreparedStatement prepareStatement(Stringsql,
String[]columnNames)
throws SQLException
public PreparedStatement prepareStatement(Stringsql,
intresultSetType,
intresultSetConcurrency)
throws SQLException
public PreparedStatement prepareStatement(Stringsql,
intresultSetType,
intresultSetConcurrency,
intresultSetHoldability)
throws SQLException
public PreparedStatement prepareStatement(Stringsql,
String[]columnNames)
throws SQLException
使用指定的SQL语句创建一个预处理语句,sql参数中往往包含一个或者多个“?”占位符。
Statement接口
一个Statement对象仅能有一个ResultSet对象。当完成对表的操作之后,必须重新得到另一个Statement对象,才能进行其他表的操作。
Statement对象可以用于执行一个静态的SQL语句,并得到SQL语句执行后的结果。
execute
public boolean execute(Stringsql)
throws SQLException
运行语句,返回是否有结果集。
executeQuery
public ResultSet executeQuery(Stringsql)
throws SQLException
运行查询语句,返回ResultSet对象。
executeUpdate
public int executeUpdate(Stringsql)
throws SQLException
运行更新操作,返回更新的行数。
PreparedStatement接口
PreparedStatement对象可以代表一个预编译的SQL语句,它从Statement接口继承而来,并与之有如下两方面的不同:
u PreparedStatement实例包含已编译的SQL语句。
u 包含于PreparedStatement对象中的SQL语句可具有一个或多个IN参数。IN参数的值在SQL语句创建时未被指定。相反的,该语句为每个IN参数保留一个问号(“?”)作为占位符。每个问号的值必须在该语句执行之前,通过适当的setXXX方法来提供。
由于PreparedStatement对象已经预编译过,所以其执行速度要快于Statement对象。因此,需要多次执行的SQL语句经常创建为PreparedStatement对象,以提供效率。
作为Statement的子类,PreparedStatement继承了Statement的所有功能。另外它还添加了一整套方法,用于设置发送给数据库以取代IN参数占位符的值。
另外,Statement接口中的三种方法executeexecuteQueryexecuteUpdate已经被更改,使之不再需要参数。
所有的setXXX方法的原型如下,其中XXX是与该参数相应的类型。例如,如果参数具有Java类型long,则使用的方法就是setLongsetXXX方法的第一个参数parameterIndex为要设置的参数的序数位置,第二个参数是设置给该参数的值。
setXXX
public void setXXX(intparameterIndex, XXXx)
throws SQLException
设定指定位置的参数值。
execute
public boolean execute()
throws SQLException
运行语句,返回是否有结果集。
executeQuery
public ResultSet executeQuery()
throws SQLException
运行查询语句,返回ResultSet对象。
executeUpdate
public int executeUpdate()
throws SQLException
运行更新操作,返回更新的行数。
ResultSet接口
ResultSet提供了对数据库中表的访问,一个ResultSet对象通常由执行一个Statement而生成。
ResultSet对象维护了一个光标指针,用来描述当前记录的位置,最初,光标指向第一个记录的位置之前,next方法将光标移到到下一个记录,其方法的原型如下。
boolean next() throws SQLException
getXXX方法得到当前记录的字段的值,可以使用字段名或其索引得到自动的值,一般来说,使用字段的索引效率更高,字段的编号从1开始,1为当前记录的第一个字段,2为第二个字段,以此类推。
ResultSet接口中,还有一系列的updateXXX方法,可以用来更新当前记录的字段值。
getXXX
public XXXgetXXX(intparameterIndex)
throws SQLException
public XXXgetXXX(String columnName)
throws SQLException
获取指定位置或者指定列的查询结果值。
第三节JDBC编程实例
基本步骤
Ø 输入java.sql
在程序的开头,必须加入下面的代码:
Import java.sql.*;
Ø 声明变量
在代码中,一般要声明三个相关的变量。Stmt用于SELECT语句,pstmt用于UPDATE语句,rs用于SELECT的结果集。
Statement stmt
PreparedStatement pstmt
ResultSet rs
Ø 加载jdbc驱动程序
Class.forName(“<jabc驱动程序>”);
Ø 定义JDBC URL
String url = “jdbc:odbc:oracle:thin@10.10.10.1:db9”;
Ø 连接数据库
Connection conn = DriverManager.getConnection(url);
Ø 进行相应的数据操作
根据需要创建StatementPreparedStatement实例,执行SELECT操作或UPDATE操作。
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table2");
Ø 关闭数据库连接
conn.close();
查询记录信息
Vector data = new Vector();
ResultSet rs = null;
Statement stmt = null;
Connection conn = null;
//注册驱动器
try
{
//加载驱动程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//Class.forName("oracle.jdbc.driver.OracleDriver");
//得到数据库联接
conn= DriverManager.getConnection("jdbc:oracle:thin:@192.168.110.52:1521:edu","study","study");
//执行sql语句
stmt = conn.createStatement();
//返回数据集合
rs = stmt.executeQuery("select * from book where bookid=‘0007’");
while (rs.next())
{
DataObject dataObject = new DataObject();
dataObject.setBookId(rs.getString("bookid"));
dataObject.setBookName(rs.getString("bookname"));
dataObject.setBookNumber(rs.getString("booknumber"));
data.addElement(dataObject);
}
}
catch (SQLException e1)
{
e1.printStackTrace();
}
catch (ClassNotFoundException e)
{
System.out.println("Driver not found");
}
//关闭联接
finally
{
try
{
rs.close();
stmt.close();
conn.close();
}
catch (SQLException e2)
{
e2.printStackTrace();
}
}
插入记录信息
String sql;
Connection conn = null;
PreparedStatement ps=null;
//注册驱动器
try
{
//加载驱动程序
Class.forName("oracle.jdbc.driver.OracleDriver");
// 得到数据库联接
conn= DriverManager.getConnection("jdbc:oracle:thin:@192.168.110.52:1521:edu","study","study");
// 执行sql语句
sql="insert into book ( bookid,bookname,booknumber) values (?,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "0021");
ps.setString(2, "数据库概论");
ps.setInt(3, 11);
ps.executeUpdate();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
catch (ClassNotFoundException e)
{
System.out.println("Driver not found");
}
// 关闭联接
finally
{
try
{
ps.close();
conn.close();
}
catch (SQLException e2)
{
e2.printStackTrace();
}
}
更新记录信息
int state;
Statement stmt = null;
Connection conn = null;
//注册驱动器
try
{
//加载驱动程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//Class.forName("oracle.jdbc.driver.OracleDriver");
//得到数据库联接
conn= DriverManager.getConnection("jdbc:oracle:thin:@192.168.110.52:1521:edu","study","study");
//执行sql语句
stmt = conn.createStatement();
//返回数据集合
state=stmt.executeUpdate("update book set booknumber=9 where bookname='java编程思想'");
if(state>0)
{
System.out.println("更新成功");
}
else
{
System.out.println("更新失败");
}
}
catch(SQLException e1)
{
e1.printStackTrace();
}
catch(ClassNotFoundException e)
{
System.out.println("Driver not found");
}
//关闭联接
finally
{
try
{
stmt.close();
conn.close();
}
catch(SQLException e2)
{
e2.printStackTrace();
}
}
删除记录信息
boolean state=false;
Statement stmt = null;
Connection conn = null;
//注册驱动器
try
{
//加载驱动程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//Class.forName("oracle.jdbc.driver.OracleDriver");
//得到数据库联接
conn= DriverManager.getConnection("jdbc:oracle:thin:@192.168.110.52:1521:edu","study","study");
//执行sql语句
stmt = conn.createStatement();
//返回数据集合
state=stmt.execute("delete from book where bookid='0007'");
if(state)
{
System.out.println("删除成功");
}
else
{
System.out.println("删除失败");
}
}
catch (SQLException e1)
{
e1.printStackTrace();
}
catch(ClassNotFoundException e)
{
System.out.println("Driver not found");
}
//关闭联接
finally
{
try
{
stmt.close();
conn.close();
}
catch (SQLException e2)
{
e2.printStackTrace();
}
}
第四节JDBC数据库连接池
在实际应用开发中,特别是在Web应用系统中,如果JSPServletEJB使用JDBC直接访问数据库中的数据,每一次数据访问请求都必须经历建立数据库连接、打开数据库、存取数据和关闭数据库连接等过程,而连接并打开数据库是一件既消耗资源又费时的工作,如果频繁的发生这种数据库操作,系统的性能必然会急剧的下降,甚至会导致系统崩溃。数据库连接池技术是解决这个问题最常用的方法,在许多应用程序服务器中,基本都提供了这项技术,无需自己编程。
数据库连接池技术的思想非常简单,将数据库连接作为对象存储在一个vector对象中,一旦数据库连接建立后,不同的数据库访问请求就可以共享这些连接,这样,通过复用这些已建立的数据库连接,可以克服上述缺点,极大的节省了系统资源和时间。
数据库连接池的主要操作如下:
Ø 建立数据库连接池对象
Ø 按照事先指定的参数创建初始数量的数据库连接
Ø 对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大,创建一个新的数据库连接
Ø 存取数据库
关闭数据库,释放所有数据库连接。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics