收藏 分销(赏)

JDBC技术基础(完结版).doc

上传人:仙人****88 文档编号:11225305 上传时间:2025-07-08 格式:DOC 页数:22 大小:215KB 下载积分:10 金币
下载 相关 举报
JDBC技术基础(完结版).doc_第1页
第1页 / 共22页
JDBC技术基础(完结版).doc_第2页
第2页 / 共22页


点击查看更多>>
资源描述
第八章 JDBC技术 往往实际的项目中都需要用到主流的关系型数据库,因此掌握JDBC技术是非常重要的。本章主要介绍JDBC技术的基本原理,重点介绍JDBC技术体系中的常用接口和类,并通过实例来说明用JDBC操作数据库的过程。本章的基础前提就是读者已经学过关于数据库方面的知识,并且熟悉常用的SQL语句。 8.1 JDBC 原理概述 8.1.1 JDBC 基本概念 JDBC,全称为Java DataBase Connectivity(Java 数据库连接)。 它由一组用Java语言编写的类和接口组成,是Java开发人员和数据库厂商达成的协议,也就是由Sun公司定义的一组接口,由数据库厂商来实现,并规定了Java开发人员访问数据库所使用的方法的规范。通过它可访问各类关系数据库。JDBC也是Java核心类库的组成部分。 JDBC的最大特点是它独立于具体的关系数据库。与ODBC (Open Database Connectivity)类似,JDBC API 中定义了一些Java类和接口,分别用来实现与数据库的连接(connections)、发送SQL语句(SQL statements)、获取结果集(result sets)以及其它的数据库对象,使得Java程序能方便地与数据库交互并处理所得的结果。JDBC的API在java.sql、javax.sql等包中。 Java程序应用JDBC,一般由以下步骤。 l 注册加载一个数据库驱动程序。 l 创建数据库连接(Connection)。 l 创建一个Statement(发送sql)。 l 数据库执行sql语句。 l 用户程序处理执行sql语句的结果(包括结果集ResultSet)。 l 关闭连接(Connection)等资源。 由于数据库不同,驱动程序的形式和内容也不相同,主要体现在获得连接的方式和相关参数的不同。为了说明问题,本章采用的数据库为 SQLServer 2005,测试数据库名为jdbc_demo,库中只有一张表person,如下图所示。 图 8-1 person表示意图 其中id为自增长主键,name(String)、age(int)和sex(String)为字段。 8.1.2 JDBC驱动程序及安装 JDBC驱动程序是用于特定数据库的一套实现了JDBC接口的类集。要通过JDBC来存取某一特定的数据库,必须有相应的该数据库的JDBC驱动程序,它往往是由生产数据库的厂家提供,是连接JDBC API与具体数据库之间的桥梁。目前,主流的数据库系统如Oracle、SQLServer、Sybase、Informix等都为客户提供了相应的驱动程序。 由于历史和厂商的原因,从驱动程序工作原理分析,通常有四种类型。分别是:JDBC-ODBC桥、部分Java、部分本机驱动程序、中间数据访问服务器和纯Java驱动程序。分别说明如下。 1、JDBC-ODBC桥,全称是“JDBC-ODBC bridge driver”。由于历史原因,ODBC技术比JDBC更早或更成熟,所以通过该种方式访问一个ODBC数据库,是一个不错的选择。 这种方法主要原理是:提供了一种把JDBC调用映射为ODBC调用的方法。因此,需要在客户机安装一个ODBC驱动。这种方式由于需要中间的转换过程导致执行效率低,目前比较少用。实际上微软的数据库系统(如SQLServer和Access)仍然保留了该种技术的支持。 2、第二种类型的全称是“native-API, partly Java driver”。这一类型的驱动程序是直接将JDBC调用转换为特定的数据库调用,而不经过ODBC了,执行效率比第一种高。但该种方法也存在转换的问题,且这类驱动程序与第一种驱动程序类型一样,也要求客户端的机器安装相应的二进制代码(驱动程序和厂商专有的API)。所以这类驱动程序应用存在限制,如不太适合用于Applet等。 3、第三种类型的全称是“JDBC-Net pure Java driver”。 它的原理是将JDBC的调用转换为独立于数据库的网络协议,并完全通过Java驱动。这种类型的驱动程序不需要客户端的安装和管理,所以特别适合于具有中间件(middle tier)的分布式应用,但目前这类驱动程序的产品不多。 4、第四种类型又称为 “native protocol, pure Java driver”。它能将JDBC调用转换为特定数据库直接使用的网络协议,不需要安装客户端软件,是百分之百的Java程序。这种方式的本质是使用Java sockets来连接数据库,所以它特别适合于通过网络使用后台数据库的Applet及Web应用,后面介绍的JDBC应用主要使用该类型的驱动程序。目前,大部分数据库厂商提供了该类驱动程序的支持。 用户开发JDBC应用系统,首先需要安装数据库的驱动程序。以Microsoft SQLServer 2005为例,第一步是下载它的JDBC驱动jar包(如sqljdbc.jar),可以去微软官方下载。第二步,对于普通的Java Application 应用程序,只需要将JDBC驱动包复制到CLASSPATH所指向的目录下就可以了,这和普通的Java 类没什么区别。而对于Web应用,通常将JDBC驱动包放置在WEB-INF/lib目录下即可。对于其它数据库,可采用类似方法。 8.1.3 一个简单JDBC例子 以下为一个最简单的JDBC应用代码。 JdbcExample.java import java.sql.*;//导入包 public class JdbcExample{ public static void main(String arg[]){ String driver=null;// 驱动程序名称 //指定连接的数据库url String url="jdbc:sqlserver://localhost:1433;databasename=jdbc_demo"; try { //加载驱动程序,此处为第四种类型驱动程序; driver="com.microsoft.sqlserver.jdbc.SQLServerDriver" Class.forName(driver); //通过驱动程序管理器建立与数据库的连接 Connection con = DriverManager.getConnection(url); //创建执行查询的Statement对象 Statement stmt = con.createStatement(); //SQL语句,用于查询学生表中的姓名、年龄、和姓别 String sql = "SELECT name,age,sex FROM person"; //执行查询,查询结果放在ResultSet的对象中 ResultSet rs = stmt.executeQuery( sql ); String name,sex; int age; //打印出查询结果。 while(rs.next()){ //获得每一行中每一列的数据 name = rs.getString(1); age = rs.getInt(2); sex = rs.getString(3); System.out.println(name + ", " + age+", " +sex); } } //找不到驱动程序,捕捉异常。如发生该错误, //请检查JDK版本是不是在1.1以上 catch(ClassNotFoundException e){ System.out.println("错误:" + e); } catch(SQLException e){ System.out.println("错误:" + e); } finally{ try{ rs.close(); stmt.close(); con.close(); } catch(SQLException e}{} } } 上面代码,清晰地表达了应用JDBC技术的基本步骤。需要说明的是: l 所有与JDBC相关的操作代码必须用try{}处理。一方面,JDBC中绝大多数方法都被定义为抛出SQLExecption异常,该类异常属于必须捕捉的异常,否则,编译通不过。另一方面,如果在一处发生异常,应用程序就没有必要进行下去了。如连接数据库失败,就没必要产生Statement的实例了。 l JDBC应用中,一次数据库会话结束,必须关闭数据库连接资源,该资源是宝贵的,会话期间,由用户程序独占,结束后,必须释放。 l 结果集(ResultSet)对象是一种数据容器,存放着满足SQL查询条件的数据库记录。通过next()方法,可以遍历所有记录,通过getXxx()可以得到指定行中的列值。关于结果集的全面介绍在下面章节中进行。 8.2 JDBC常用接口、类介绍 JDBC中,定义了许多接口和类,但经常使用的不是很多。以下介绍的是最常用的接口和类,使初学者能够尽快掌握JDBC技术。 8.2.1 Driver接口 Driver接口在java.sql包中定义,每种数据库的驱动程序都提供一个实现该接口的类,简称Driver类,应用程序必须首先加载它。加载的目的就是创建自己的实例并向java.sql.DriverManager类注册该实例,以便驱动程序管理类(DriverManager)对数据库驱动程序的管理。 通常情况下,通过java.lang.Class类的静态方法forName(String className),加载欲连接的数据库驱动程序类,该方法的入口参数为欲加载的数据库驱动程序完整类名。对于每种驱动程序,其完整类名的定义也不一样,以下做简单说明。 如果使用第一种类型驱动程序(JDBC-ODBC),则其加载方法: Class.forName("sun.jdbc.odbc.jdbcOdbcDriver")。 如果使用第四种类型驱动程序,则其加载方法: Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"),这是SQLServer2005的驱动程序加载方法,且如果版本不一样,驱动程序名也会不同。 同样,其它数据库(如MySQL、Oracle)的驱动程序加载方法也类同,这里不再说明。 若加载成功,系统会将驱动程序注册到DriverManager类中。如果加载失败,将抛出ClassNotFoundException异常。以下是加载驱动程序的代码。 try { Class.forName(driverName);//加载JDBC驱动器 } catch (ClassNotFoundException ex) { ex.printStackTrace(); } 需要注意的是,加载驱动程序行为属于单例模式,也就是说,整个数据库应用中,只加载一次就可以了。 8.2.1 DriverManager类 数据库驱动程序加载成功后,接下来就由DriverManager 类来处理了,所以是该类是JDBC的管理层,作用于用户和驱动程序之间。它跟踪可用的驱动程序,并在数据库和相应驱动程序之间建立连接。 另外,DriverManager类也处理诸如驱动程序登录时间、登录管理和消息跟踪等事务。 DriverManager类的主要作用是管理用户程序与特定数据库(驱动程序)的连接。一般情况下,DriverManager类可以管理多个数据库驱动程序。当然,对于中小规模应用项目,可能只用到一种数据库。JDBC允许用户通过调用 DriverManager的getDriver、getDrivers和registerDriver等方法,实现对驱动程序的管理,进一步,通过这些方法实现对数据库连接的管理。但多数情况下,不建议采用上述方法,如果没有特殊要求,对于一般应用项目,建议让DriverManager类自动管理。 DriverManager类是用静态方法getConnection来获得用户与特定数据库连接。在建立连接过程中,DriverManager将检查注册表中的每个驱动程序,查看它是否可以建立连接,有时,可能有多个JDBC驱动程序可以和给定数据库建立连接。例如,与给定远程数据库连接时,可以使用JDBC-ODBC桥驱动程序、JDBC到通用网络协议驱动程序或数据库厂商提供的驱动程序。在这种情况下,加载驱动程序的顺序至关重要,因为 DriverManager将使用它找到的第一个可以成功连接到给定的数据库驱动程序进行连接。 用DriverManager建立连接,主要由以下几种方法。 l static Connection getConnection(String url),url实际上标识给定数据库(驱动程序),它由三部分组成,用“:”分隔。格式为:jdbc:子协议名:子名称。其中jdbc是唯一的,JDBC只有这种协议;子协议名主要用于识别数据库驱动程序的,不同的数据库有不同的子协议名,如SQLServer2005为“sqlserver”,子名称为属于专门驱动程序的,对于SQLServer2005,指的是数据库的名、服务端口号等信息,例如:“//localhost:1433;databasename=jdbc_demo”。 l static Connection getConnection(String url, String userName, String password),与第一种相比,多了数据库服务的登录名和密码,这个容易理解。 8.2.2 Connection接口 Connection对象代表数据库连接,只有建立了连接,用户程序才能操作数据库。连接是JDBC中最重要的接口之一,使用频度高,读者必须掌握。 Connection接口的实例是由驱动程序管理类的静态方法getConnection产生,数据库连接实例是宝贵的资源,它类似电话连接一样,在一个会话期内,是由用户程序独占的,且需要耗费内存的,因此,每个数据库的最大连接数是受限的。所以,用户程序访问数据库结束后,必须及时关闭连接,以方便其它用户使用该资源。Connection接口的主要功能(或方法)是获得各种发送SQL语句的运载类(以下会介绍),以下简要列出该接口的主要方法。 l close()方法:关闭到数据库的连接,在使用完连接后必须关闭,否则连接会保持一段比较长的时间,直到超时。 l commit()方法:提交对数据库的更改,使更改生效。这个方法只有调用了setAutoCommit(false)方法后才有效,否则对数据库的更改会自动提交到数据库。 l createStatement()方法:创建一个Statement,Statement 用于执行SQL 语句。 l createStatement(int resultSetType, int resultSetConcurrency)方法:创建一个Statement,并且产生指定类型的结果集(ResultSet)。关于相关参数的介绍在下面章节中会详细介绍。 l getAutoCommit()方法:为这个连接对象,获取当前auto-commit模式。 l getMetaData()方法:获得一个DatabaseMetaData对象,其中包含了关于数据库的元数据。 l isClosed()方法:判断连接是否关闭。 l prepareStatement(String sql)方法:使用指定的SQL语句创建一个预处理语句,SQL 参数中往往包含一个或者多个“?”占位符。 l rollback()方法:回滚当前执行的操作,只有调用了setAutoCommit(false)才可以使用。 l setAutoCommit(boolean autoCommit)方法:设置操作是否自动提交到数据库,默认情况下是true。 由于数据库不同,驱动程序的形式和内容也不相同,主要体现在获得连接的方式和相关参数的不同。因此,在JDBC项目,根据面向对象的设计思想(封装变化),一般把连接管理设计成为一个类:连接管理器类,主要负责连接的获得和关闭。 以下是连接管理器DBConnection.class的代码。 package DAO; import java.sql.*; public class DBConnection { //数据库的url private static String url ="jdbc:sqlserver://localhost:1433;databasename =jdbc_demo"; private static String userName = "sa";//数据库用户名 private static String password = "123456";//数据库密码 //jdbc驱动器名称 private static String driverName = "com.microsoft.sqlserver. jdbc.SQLServerDriver"; static { try { Class.forName(driverName);//加载JDBC驱动器 } catch (Exception ex) { ex.printStackTrace(); } } public static Connection getConn() { try { Connection conn = DriverManager getConnection(url,userName, password); System.out.println("连接数据库成功"); return conn; } catch (SQLException ex) { System.out.println("连接数据库失败"); ex.printStackTrace(); return null; } } public static void close(Connection conn, Statement stm ResultSet rs) { try{ if (rs != null) rs.close(); if(stm!=null) stm.close(); if (conn != null){ conn.close(); System.out.println("数据库连接成功释放"); } } catch (SQLException ex) {} } } 以下为测试代码。 public class TestJDBC{ public static void main(String[] args) { DBConnection.getConn(); DBConnection.close(); } } 控制台打印出“连接数据库成功”、“数据库连接成功释放”的语句,说明JDBC连接数据库已经成功。从上面的代码可以看出,主要有两个操作,首先使用Class.forName方法加载驱动器,接着使用DriverManager.getConnection方法得到数据库连接。由于加载驱动器,在整个应用系统中,只有一次,所以采用static程序块技术来实现。 8.2.3 Statement Statement、PreparedStatement和CallableStatement,这3个接口都是用来执行SQL语句的,都由Connction中的相关方法产生,但它们有所不同。Statement接口用于执行静态SQL语句并返回它所生成结果集对象;PreparedStatement表示带IN或不带IN的预编译SQL语句对象,SQL语句被预编译并存储在PreparedStatement对象中;CallableStatement用于执行SQL存储过程的接口。下面分别介绍着3个接口的使用。 1、Statement接口 因为Statement是一个接口,它没用构造函数,所以不能直接创建一个实例。创建一个Statement对象必须通过Connection接口提供的createStatement方法进行创建。其代码片段如下: Statement statement=connection.createStatement(); 创建完Statement对象后,用户程序就可以根据需要调用它的常用方法,如executeQuery、executeUpdate、execute、executeBatch等方法。 executeQuery方法 该方法用于执行产生单个结果集的SQL语句,如Select语句,该方法返回一个结果集ResultSet对象。完整的方法声明如下: ResultSet executeQuery(String sql) throws SQLException 下面给出一个实例,使用executeQuery方法执行查询person表的SQL语句,并返回结果集。 JDBCTest.java import DAO.*; import sql.*; public class JDBCTest{ public static void main(String[] args) { Connection connection = DBConnection.getConn(); Statement statement = null; ResultSet resultSet = null; try { statement = connection.createStatement(); String sql = "select name,age,sex from person"; resultSet = statement.executeQuery(sql); while(resultSet.next()){ System.out.println("name:"+resultSet.getString("name")); System.out.println("age:"+resultSet.getString("age")); System.out.println("sex:"+resultSet.getString("sex")); } } catch (SQLException e) { e.printStackTrace(); }finally{ DBConnection.close(connection, statement, resultSet); } } } 以上代码中,用到了连接管理器类DBConnection。 executeUpdate方法 该方法执行给定SQL语句,该语句可能为INSERT、UPDATE或DELETE语句,或者不返回任何内容的SQL 语句(如 SQL DDL 语句)。完整的方法声明如下: int executeUpdate(String sql) throws SQLException 对于SQL数据操作语言(DML) 语句,返回行计数;对于什么都不返回的SQL语句,返回正数0。下面给出一个实例,使用executeUpdate方法执行插入SQL语句。 public static void main(String[] args) { Connection connection = DBConnection.getConn(); Statement statement = null; ResultSet resultSet = null; int rowCount ; try { statement = connection.createStatement(); String sql = "insert into person(name,age,sex) values('tom',15,'男')"; rowCount = statement.executeUpdate(sql); System.out.println("插入所影响的行数为"+rowCount+"行"); } catch (SQLException e) { e.printStackTrace(); }finally{ DBConnection.close(connection, statement, resultSet); } } } execute方法 执行给定的SQL 语句,该语句可能返回多个结果。在某些(不常见)情形下,单个 SQL 语句可能返回多个结果集和或更新记录数,这一点通常可以忽略,除非正在执行已知可能返回多个结果的存储过程或者动态执行未知 SQL 字符串。一般情况下,execute 方法执行 SQL语句并返回第一个结果的形式。然后,用户程序必须使用方法getResultSet 或 getUpdateCount来获取结果,使用 getMoreResults 来移动后续结果。该方法的完整声明如下: boolean execute(String sql) throws SQLException 该方法是一个通用方法,既可以执行查询语句,也可以执行修改语句,该方法可以用来处理动态的未知的SQL语句。下面的实例使用execute方法执行一个用户输入的SQL语句,并返回结果。 public static void main(String[] args) { Connection connection = DBConnection.getConn(); Statement statement = null; ResultSet resultSet = null; int rowCount; boolean isResultSet; try { statement = connection.createStatement(); String sql = JOptionPane.showInputDialog("请输入一个SQL语句:"); isResultSet = statement.execute(sql); if(isResultSet ){ resultSet = statement.getResultSet(); while(resultSet.next()){ System.out.println("name:"+resultSet.getString("name")); System.out.println("age:"+resultSet.getString("age")); System.out.println("sex:"+resultSet.getString("sex")); } }else{ rowCount = statement.getUpdateCount(); System.out.println("所更新的行数为"+rowCount+"行"); } } catch (SQLException e) { e.printStackTrace(); }finally{ DBConnection.close(connection, statement, resultSet); } } 对于以上代码,读者可以自行编写一个测试类。 executeBatch方法 将一批命令提交给数据库来执行,如果全部命令执行成功,则返回一个和添加命令时顺序一样的整型数组,数组元素的排序对应于批中的命令,批中的命令根据被添加到批中的顺序排序,数组中的元素的值可能为以下值之一: l 大于等于0的数,指示成功处理了命令,其值为执行命令所影响数据库中行数的更新计数。 l SUCCESS_NO_INFO,指示成功执行了命令,但受影响的行数是未知的。如果批量更新中的命令之一无法正确执行,方法则抛出BatchUpdateException,并且JDBC驱动程序可能继续处理批处理中的剩余命令,也可能不执行。无论如何,驱动程序的行为必须与特定的DBMS一致,要么始终继续处理命令,要么永远不继续处理命令。 l EXECUTE_FAILED ,指示未能成功执行命令,仅当命令失败后,驱动程序继续处理命令时出现。 该方法完整的声明如下:int[] executeBatch() throws SQLException 对于批处理操作,另外还有两个辅助方法:addBatch,向批处理中加入一个更新语句;clearBatch,清空批处理中的更新语句。在下面的实例中使用executeBatch方法来执行多个INSERT语句向person数据表插入多条记录,并显示返回的更新计数数组。 public static void main(String[] args) { Connection connection = DBConnection.getConn(); Statement statement = null; ResultSet resultSet = null; int[] rowCount ; try { statement = connection.createStatement(); String sql1 = "insert into person(name,age,sex) values('kobe1',32,'男')"; String sql2 = "insert into person(name,age,sex) values('kobe2',32,'男')"; String sql3 = "insert into person(name,age,sex) values('kobe3',32,'男')"; statement.addBatch(sql1); statement.addBatch(sql2); statement.addBatch(sql3); rowCount = statement.executeBatch(); for(int i=0;i<rowCount.length;i++){ System.out.println("第"+(i+1)+"条语句执行影响的行数为 "+rowCount[i]+"行"); } } catch (SQLException e) { e.printStackTrace(); }finally{ DBConnection.close(connection, statement, resultSet); } } 2、PreparedStatement PreparedStatement是Statement的子接口,PreparedStatement的实例已经包含编译的SQL语句,所以它的执行速度快于Statement。PreparedStatement的对象创建同样需要Connection接口提供的方法prepareStatement方法,同时需要制定SQL语句。核心代码如下: Connection connection = DBConnection.getConn(); String sql = "delete from person where name = ?"; PreparedStatement pstm = connection.prepareStatement(sql); 上面的SQL语句中有“?”号,指的是SQL语句中的占位符,表示SQL语句中的可替换参数,也称作IN参数,在执行前必须赋值。因此PreparedStatement 还添加了一些设置IN参数的方法。同时,execute、executeQuery和executeUpdate方法也变了,无需再传入SQL语句,因为前面已经指定了SQL语句。下面给出的是PreparedStatement执行SQL的一个实例: public static void main(String[] args) { Connection connection = DBConnection.getConn(); PreparedStatement preparedStatement = null; ResultSet resultSet = null; int isResultSet; try { String sql = "delete from person where name = ?"; preparedStatement=connection.prepareStatement(sql); preparedStatement.setString(1, "alex"); isResultSet = preparedStatement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally{ DBConnection.close(connection, preparedStatement, resultSet); } } 从上述例子分析,用PreparedStatement来代替Statement会使代码多出几行,但代码的可读性和可维护性提高了,为了说明问题,下面再举一个例子。 … stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values (‘"+var1+"‘,‘"+var2+"‘,"+var3+",‘"+var4+"‘)"); perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)"); perstmt.setString(1,var1); perstmt.setString(2,var2); perstmt.setString(3,var3); perstmt.setStr
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服