一篇好文章,特摘抄下來分享
http://topic.csdn.net/t/20040824/13/3304228.html
JDBC基础
还是先一起来回顾一下接口吧:从下向上,接口是对 "案例 "的抽象,由一个案例抽象出一些规则.
反过来,从上向下,被抽象出来的接口是对案例的一种承诺和约束.
也就是说,只要你实现我规定的接口,你的类就已经具有了接口对外承诺的方法,只要 "客户 "会
操作接口,不需要重新学习就会操作实现了该接口的新类!
好了,用行话来说:
1.通过接口可以实现不相关的类的相同行为.
2.通过接口可以指明多个类需要实现的方法.
3.通过接口可以了解对象的交互方法而不需要了解对象所对应的类蓝本.
这几句话很明白吧?好象有一本什么模式的书把这段话用了30多页写出来,结果别人看了还不如
我这几句话明白,不过我明白了为什么有些人要写书了.
搞懂了以上这东西,JDBC就好明白了.
为了通用,JAVA中要求有一种机制,在操作不同厂商数据库时有相同的方法去操作,而不是每接
触一种数据库就要学习新的方法.完成这种机制的 "东西 "就叫 "JDBC "了.
简单地分,JDBC有两部分组成,JDBC API和JDBC Driver Interface.
JDBC API就是提供给 "客户 "(就是象你我这种菜鸟级程序员来用的,如果是高手都自己写JDBC了,
哈哈)的一组独立于数据库的API,对任何数据库的操作,都可以用这组API来进行.那么要把这些通用的API
翻译成特定数据库能懂的 "指令 ",就要由JDBC Driver Interface来实现了,所以这部份是面向JDBC驱动程
序开发商的编程接口,它会把我们通过JDBC API发给数据库的通用指令翻译给他们自己的数据库.
还是通过实际操作来看看JDBC如何工作的吧.
因为JDBC API是通用接口,那么程序是如何知道我要连结的是哪种数据库呢?
所以在和数据库连结时先要加载(或注册可用的Driver),其实就是JDBC签名.加载驱动程序有好多方法,最常用的就是先把驱
动程序类溶解到内存中,作为 "当前 "驱动程序.注意 "当前 "是说内存中可以有多个驱动程序,但只有现在加载的这个作为首选连结的驱动程序.
Class.forName( "org.gjt.mm.mysql.Driver ");
Class.forName方法是先在内存中溶解签名为 "org.gjt.mm.mysql.Driver "的Driver类,Driver类就会把相应的实现类对应到JDBC API的接口中.比如把org.gjt.mm.mysql.Connection的实例对象赋给java.sql.Connection接口句柄,以便 "客户 "能通过操作java.sql.Connection句柄来调用实际的org.gjt.mm.mysql.Connection中的方法.之于它们是如果映射的,这是厂商编程的, "客户 "只要调用Class.forName( "org.gjt.mm.mysql.Driver ");方法就可以顺利地操作JDBC API了.
一个普通数据库的连结过程为:
1.加载驱动程序.
2.通过DriverManager到得一个与数据库连结的句柄.
3.通过连结句柄绑定要执行的语句.
4.接收执行结果.
5.可选的对结果的处理.
6.必要的关闭和数据库的连结.
前面说是,注册驱动程序有多方法,Class.forName();是一种显式地加载.当一个驱动程序类被Classloader装载后,在溶解的过程中,DriverManager会注册这个驱动类的实例.这个调用是自动发生的,也就是说DriverManager.registerDriver()方法被自动调用了,当然我们也可以直接调用DriverManager.registerDriver()来注册驱动程序,但是,以我的经验.MS的浏览中APPLET在调用这个方法时不能成功,也就是说MS在浏览器中内置的JVM对该方法的实现是无效的.
另外我们还可以利用系统属性jdbc.drivers来加载多个驱动程序:
System.setProperty( "jdbc.drivers ", "driver1:driver2:.....:drivern ");多个驱动程序之间用 ": "隔开,这样在连结时JDBC会按顺序搜索,直到找到第一个能成功连结指定的URL的驱动程序.在基础篇里我们先不介绍DataSource这些高级特性.
在成功注册驱动程序后,我们就可以用DriverManager的静态方法getConnection来得到和数据库连结的引用:
Connection conn = DriverManager.getConnection(url);
如果连结是成功的,则返回Connection对象conn,如果为null或抛出异常,则说明没有和数据库建立连结.
对于getConnection()方法有三个重载的方法,一种是最简单的只给出数据源即:getConnection(url),另一种是同时给出一些数据源信息即getConnection(url,Properties),另外一种就是给出数据源,用户名和密码:getConnection(url,user,passwod),对于数据源信息.
如果我们想在连结时给出更多的信息可以把这些信息压入到一个Properties,当然可以直接压入用户名密码,别外还可以压入指定字符集,编码方式或默认操作等一些其它信息.
在得到一个连结后,也就是有了和数据库找交道的通道.我们就可以做我们想要的操作了.
还是先来介绍一些一般性的操作:
如果我们要对数据库中的表进行操作,要先缘故绑定一个语句:
Statement stmt = conn.createStatement();
然后利用这个语句来执行操作.根本操作目的,可以有两种结果返回,如果执行的查询操作,返回为结果集ResultSet,如果执行更新操作,则返回操作的记录数int.
注意,SQL操作严格区分只有两个,一种就是读操作(查询操作),另一种就是写操作(更新操作),所以,create,insert,update,drop,delete等对数据有改写行为的操作都是更新操作.
ResultSet rs = stmt.executeQuery( "select * from table where xxxxx ");
int x = stmt.executeUpdate( "delete from table where ...... ");
如果你硬要用executeQuery执行一个更新操作是可以的,但不要把它赋给一个句柄,
当然稍微有些经验的程序员是不会这么做的.至于对结果集的处理,我们放在下一节讨论,因为它是可操作的可选项,只有查询操作才返回结果集,对于一次操作过程的完成,一个非常必要的步骤是关闭数据库连结,在你没有了解更多的JDBC知识这前,你先把这一步骤作为JDBC操作中最最重要的一步,在以后的介绍中我会不断地提醒你去关闭数据库连结!
按上面介绍的步骤,一个完成的例子是这样的:(注意,为了按上面的步骤介绍,这个例子不是最好的)
try
{
Class.forName( "org.gjt.mm.mysql.Driver ");
}
catch(Exception e)
{
System.out.println( "没有成功加载驱动程序: "+e.toString());
return;
}//对于象我这样的经验,可以直接从e.toString()的简单的几个字判断出异常原因,
//如果你是一个新手应该选捕获它的子类,如何知道要捕获哪几个异常呢?一个简单
//的方法就是先不加try{},直接Class.forName( "org.gjt.mm.mysql.Driver ");,编
//译器就会告诉你要你捕获哪几个异常了,当然这是偷机取巧的方法,最好还是自己
//去看JDK文档,它会告诉你每个方法有哪些异常要你捕获.
Connection conn = null;
try
{
conn = DriverManager.getConnection( "jdbc:mysql://host:3306/mysql ", "user ", "passwd ");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery( "select * from table ");
//rs 处理
[rs.close();]
[stmt.close();]
}
catch(Exception e)
{
System.out.println( "数据库操作出现异常: "+e.toString());
}
finally
{
try{conn.close();}catch(Exception){}
}//不管你以前是学习到的关于数据库流程是如何操作的,如果你相信我,从现在开始,请你一定要把数据库关闭的代码写到finally块中,切切!
关于Statement对象:
前面说过,Statement对象是用来绑定要执行的操作的,在它上面有三种执行方法:
即用来执行查询操作的executeQuery(),用来执行更新操作的executeUpdate()和用来执行动态的未知的操作的execute().
JDBC在编译时并不对要执行的SQL语句检测,只是把它看着一个String,只有在驱动程序执行SQL语句时才知道正确与否.
一个Statement对象同时只能有一个结果集在活动.这是宽容性的,就是说即使没有调用ResultSet的close()方法,只要打开第二个结果集就隐含着对上一个结果集的关闭.所以如果你想同时对多个结果集操作,就要创建多个Statement对象,如果不需要同时操作,那么可以在一个Statement对象上须序操作多个结果集.
这里我不得不特别说明一下,很多人会用一个Statement进行嵌套查询,然后就来问我说为什么不能循环?道理上面已经说清楚了.我们来详细分析一下嵌套查询:
Connection conn = null;
Statement stmt = null;
conn = .......;
stmt = conm.createStatement(xxxxxx);
ResultSet rs = stmt.executeQuery(sql1);
while(rs.next())
{
str = rs.getString(xxxxx);
ResultSet rs1 = stmt.executeQuery( "select * from 表 where 字段=str ");
}
当stmt.executeQuery( "select * from 表 where 字段=str ");赋给rs1时,这时隐含的操作是已经关闭了rs,你还能循环下去吗?
所以如果要同时操作多个结果集一定要让它他绑定到不同的Statement对象上.好在一个connection对象可以创建任意多个Statement对象,而不需要你重新获取连结.
关于获取和设置Statement的选项:只要看看它的getXXX方法和setXXX方法就明白了,这儿作为基础知识只提一下以下几个:
setQueryTimeout,设置一个SQL执行的超时限制.
setMaxRows,设置结果集能容纳的行数.
setEscapeProcessing,如果参数为true,则驱动程序在把SQL语句发给数据库前进行转义替换,否则让数据库自己处理,当然这些默认值都可以通过get方法查询.
Statement的两个子类:
PreparedStatement:对于同一条语句的多次执行,Statement每次都要把SQL语句发送给数据库,这样做效率明显不高,而如果数据库支持预编译,PreparedStatement可以先把要执行的语句一次发给它,然后每次执行而不必发送相同的语句,效率当然提高,当然如果数据库不支持预编译,PreparedStatement会象Statement一样工作,只是效率不高而不需要用户工手干预.另外PreparedStatement还支持接收参数.在预编译后只要传输不同的参数就可以执行,大大提高了性能.
PreparedStatement ps = conn.prepareStatement( "select * from 表 where 字段=? ");
ps.setString(1,参数);
ResultSet rs = ps.executeQuery();
CallableStatement:是PreparedStatement的子类,它只是用来执行存储过程的.
CallableStatement sc = conn.prepareCall( "{call query()} ");
ResultSet rs = cs.executeQuery();
作为基础知识的最后部分,我们来说一说结果集的处理,当然是说对一般结果集的处理.至于存储过程返回的多结果集,我们仍然放在高级应用中介绍.
SQL语句如何执行的是查询操作,那就要返回一个ResultSet对象,要想把查询结果最后明白地显示给用户,必须对ResultSet进行处理.ResultSet返回的是一个表中符合条件的记录,对ResultSet的处理要逐行处理,而对于每一行的列的处理,则可以按任意顺序(注意,这只是JDBC规范的要求,有些JDBC实现时对于列的处理仍然要求用户按顺序处理,但这是极少数的).事实上,虽然你可以在处理列的时候可以按任意顺序,但如果你按从左到右的顺序则可以得到较高的性能.
这儿从底层来讲解一下ResultSet对象,在任何介绍JDBC的书上你是不会获得这样的知识的,因为那是数据库厂商的事.ResultSet对象实际维护的是一个二维指针,第一维是指向当前行,最初它指向的是结果集的第一行之前,所以如果要访问第一行,就要先next(),以后每一行都要先next()才能访问,然后第二维的指针指向列,只要当你去rs.getXXX(列)时,才通过Connection再去数据库把真实的数据取出来,否则没有什么机器能真的把要取的数据都放在内存中.
所以,千万要记住,如果Connection已经关闭,那是不可能再从ResultSet中取到数据的.
有很多人问我,我可不可以取到一个ResultSet把它写到Session中然后关闭Connection,这样就不要每次都连结了.我只能告诉你,你的想法非常好,但,是错误的!当然在javax.sql包中JDBC高级应用中有CacheRow和WebCacheRow可以把结果集缓存下来,但那和我们自己开一个数据结构把ResultSet的行集中所有值一次取出来保存起来没有什么两样.访问行中的列,可以按字段名或索引来访问.下面是一个简单的检索结果的程序:
ResultSet rs = stmt.executeQuery( "select a1,a2,a3 from table ");
while(rs.next())
{
int i = rs.getInt(1);
String a = rs.getString( "a2 ");
..............
}
对于用来显示的结果集,用while来进行next()是最普通的,如果next()返回false,则说明已经没有可用的行了.但有时我们可能连一行都没有,而如果有记录又不知道是多少行,这时如果要对有记录和没有记录进行不同的处理,应该用以下流程进行判断:
if(rs.next())
{
//因为已经先next()了,所经对记录应该用do{}while();来处理
do
{
int i = rs.getInt(1);
String a = rs.getString( "a2 ");
}while(rs.next());
}
esle
{
System.out.println( "没有取得符合条件的记录! ");
}
类型转换:
ResultSet的getXXX方法将努力把结果集中的SQL数据类型转换为JAVA的数据类型,事实大多数类型是可以转换的,但仍然有不少糊弄是不能转换的,如你不能将一个SQL的float转换成JAVA的DATE,你无法将 VARCHAR "我们 "转换成JAVA的Int.
较大的值:
对于大于Statement中getMaxFieldSize返回值的值,用普通的getBytes()或getString()是不能读取的,好在JAVA提供了读取输入流的方法,对于大对象,我们可以通过rs.getXXXStream()来得到一个InputStream,XXX的类型包括Ascii,Binay,Unicode.根据你存储的字段类型来使用不同的流类型,一般来说,二进制文件用getBinayStream(),文本文件用getAsciiStyream(),对于Unicode字符的文本文件用getUnicodeStream(),相对应的数据库字段类型应该为:Blob,Clob和Nlob.
获取结果集的信息:
大多数情况下编程人员对数据库结构是了解的,可以知道结果集中各列的情况,但有时并不知道结果集中有哪些列,是什么类型.这时可以通过getMetaData()来获取结果集的情况:
ResulSetMetaData rsmd = rs.getMetaData();
rsmd.getColumnCount()返回列的个数.
getColumnLabel(int)返回该int所对应的列的显示标题
getColumnName(int)返回该int所对应的列的在数据库中的名称.
getColumnType(int)返回该int所对应的列的在数据库中的数据类型.
getColumnTypeName(int)返回该int所对应的列的数据类型在数据源中的名称.
isReadOnly(int)返回该int所对应的列是否只读.
isNullable(int)返回该int所对应的列是否可以为空
分享到:
相关推荐
JDBC基础JDBC基础JDBC基础JDBC基础JDBC基础JDBC基础JDBC基础JDBC基础JDBC基础
JDBC基础.chmJDBC基础.chm
"jdbc 基础的详解与总结" jdbc 是一套协议,由 Sun 公司定义的一组接口,由数据库厂商来实现,并规定了 Java 开发人员访问数据库所使用的方法的调用规范。jdbc 的实现是由数据库厂商提供,以驱动程序形式提供。jdbc...
了解JDBC的概念及必要性 了解JDBC驱动程序类型 理解JDBC 程序的结构 运用JDBC进行数据库编程
**JDBC基础知识** Java Database Connectivity (JDBC)是Java编程语言中用于标准地访问数据库的API。它由一组Java类和接口组成,允许Java应用程序连接到各种类型的数据库系统,包括Oracle、MySQL、SQL Server等。...
**JDBC基础知识详解** Java Database Connectivity (JDBC) 是Java平台上的一个标准API,用于与关系型数据库进行交互。它是Java开发者访问数据库的唯一、统一的接口,由Sun Microsystems(现已被Oracle收购)定义,...
**JDBC基础学习目标:** 1. **理解Java中的数据库连接**:了解Java如何通过JDBC API与各种类型的数据库(如关系型、面向对象关系型和面向对象数据库)建立连接。 2. **掌握JDBC API**:熟悉java.sql包中的核心类和...
**JDBC基础入门详解** Java Database Connectivity(JDBC)是Java平台中用于与数据库交互的一组接口和类,它是Java标准API的一部分,使得Java开发者能够访问各种类型的数据库系统。本篇将详细介绍JDBC的基础知识,...
jdbc基础篇教程md版:这份markdown格式的教程详细介绍了jdbc的基础概念、配置方法以及如何通过jdbc进行数据库的增删改查(crud)操作。教程内容涵盖了jdbc驱动的加载、数据库连接的建立、sql语句的执行以及结果集的...
JDBC 的相关基础知识,知识点很全面,简单易懂。
【jdbc基础知识详解】 Java Database Connectivity (JDBC) 是Java编程语言中用来规范应用程序如何访问数据库的应用程序接口(API)。它是Java SE的一部分,允许Java开发者连接到各种类型的数据库,执行SQL语句,...
JDBC基础.html
JDBC(Java Database Connectivity)是Java编程语言中...JDBC是Java开发数据库应用程序的基础,通过熟练掌握JDBC,开发者可以编写高效、安全、跨平台的数据库应用。理解并实践上述知识点,对于Java数据库编程至关重要。
**JDBC基础DEMO详解** Java Database Connectivity (JDBC) 是Java编程语言中用于与数据库交互的一组接口和类。这个“JDBC基础demo”旨在为初学者提供一个直观的起点,了解如何在Java应用程序中连接到数据库、执行...
JavaEE应用开发教程课件03JDBC基础.pdfJavaEE应用开发教程课件03JDBC基础.pdfJavaEE应用开发教程课件03JDBC基础.pdfJavaEE应用开发教程课件03JDBC基础.pdfJavaEE应用开发教程课件03JDBC基础.pdfJavaEE应用开发教程...
JDBC 基础 连接数据库,编操作系统的第一步
JDBC基础资源详解 。
Java-JDBC基础讲义参考
连接对象(`Connection`)是执行SQL语句的基础。 4. **SQL语句执行**:通过`Statement`或`PreparedStatement`接口,开发者可以发送SQL查询或命令给数据库。`PreparedStatement`更安全,因为可以防止SQL注入攻击。 5....
本篇文章将深入探讨JDBC的基础知识,包括其作用、类型、驱动程序以及如何使用JDBC连接数据库。 1. JDBC的作用: JDBC作为Java中的数据库访问机制,主要负责在Java应用程序和数据库之间建立桥梁,提供了一种标准化的...