jsp+sql智能道路交通信息管理系统文献翻译.docx
《jsp+sql智能道路交通信息管理系统文献翻译.docx》由会员分享,可在线阅读,更多相关《jsp+sql智能道路交通信息管理系统文献翻译.docx(26页珍藏版)》请在冰豆网上搜索。
jsp+sql智能道路交通信息管理系统文献翻译
译文:
JDBC与JSP研究
1JDBC入门
本文阐述了JDBC(数据库连接)API(应用程序接口)的基本内容。
在这里,你将学到用基本的JDBCAPI去创建表单,插入数值,查询表单,检索结果,修改表单,创建动态语句,完成事务,捕捉异常和错误。
本文来自SUN公司关于JDBC基础内容的官方指南。
--概述
--建立连接
--第一个JDBC语句
--精制JDBC语句
--执行DDL语句
--执行查询语句
--结果集访问说明
--事务处理
--异常和错误处理
--简单的代码和编辑规则
1.1概述
JDBC的访问级接口是提供了SQL数据库操作和更新操作的编程接口。
他们通过带数据库接口的库程序允许在普通的程序中调用SQL。
特别的,Java提供了很多非常简单的基于JDBC的接口。
这里有一条简单的方法可也看到在访问级发生了什么:
你正在写一个简单的Java程序。
在程序的某处,你需要和数据库交换数据。
用标准的库程序,你就可也打开一个数据库的连接。
接下来,用JDBC来发送SQL代码给数据库,并且加工要返回的结果。
等到你结束工作,就关闭数据连接。
这样的方法需要和内嵌SQL的预编辑方法相比较。
后者含有一个预编辑过程,在这个过程中内嵌的SQL语句被转化为主机语言代码(C/C++)。
访问级的接口不要求预编辑过程就避免了内嵌SQL语句转化的过程。
这样在增加轻便性的同时使客户—服务的关系更清晰。
1.2建立连接
当然,最先要做的是在你的计算机上安装Java,JDBC和DBMS。
由于我们想要连接Oracle数据库,我们也就需要一个支持它的驱动程序。
幸运地是,我们有一个负责的主管他已经在Leland的机子上为我们做好了。
和前面说的一样,在一个数据库能被访问前,一个在程序(client)和数据库(server)之间的连接必须被打开。
这包括两步:
1、装载特定厂商的驱动程序
为什么需要这一步呢?
为了确保轻便和代码重用,API被尽可能地设计来不依赖于一个数据库的版本或厂家。
由于不同DBMS拥有不同的行为,我们就需要告诉驱动管理器我们想用那种DBMS,以便它能调用正确的驱动程序。
装载Oracle驱动程序可以用下面的代码:
Class.forName(“oracle.jdbc.driver.OracleDriver”)
2、建立连接
当驱动装载完成就可以建立连接,你建立一个实际的连接可以用:
Connectioncon=DriverManger.getConnection(“jdbc:
oracle:
thin:
@dbaprodl:
1544:
SHRI_PRD”,username,password);
现在,让我们看看这个语句是干什么的。
第一个字符串是关于数据库的URL,它包含了协议(JDBC),厂商(oracle),驱动(thin),服务器(dbaprodl),端口号(1521),和一个服务实例(SHRI_PRD)。
用户名和密码就是你过去输入SQLPLUS以进入你的帐户的用户名和密码。
这就是建立连接的步骤。
最后一步返回来的是一个打开的连接,我们将用它来向数据库传递SQL语句。
在上面的代码中,con是一个打开的连接,并且我们在后面还将用到它。
注意:
上面提到的价值在我们的环境中是用根据的。
他们在别的环境中有不同的价值。
1.3创建JDBC语句
JDBC语句对象是用来发送你的SQL语句到DBMS的,不是与SQL语句相混淆的。
JDBC语句是绑定在一个打开的连接上的,不只是一个简单的SQL语句。
你能把JDBC语句对象想象成嵌在连接上的一个信息通道,它能传递一个或多个你的SQL语句(那些你要执行的)到DBMS。
一个活动的连接要求创建一个Statement对象。
下面的小代码,就是用刚才的连接con,来为你实现Statement对象的:
Statementstmt=con.createStatement();
这样,一个Statement对象存在了,但是它没有向DBMS传递一个SQL语句。
我们将在下一节学习它。
1.4精制JDBC语句
有时,用精制的语句对象来向DBMS发送SQL语句能更方便或更有效。
它区别于其超类Statement的主要特征是,它不像Statement,在它被创建时就被给与了一个正确的SQL语句。
这个SQL语句接下来就以正确的方式发向DBMS,并且在那里得到编译。
因此,精制的语句实际上是连接的一个信道,并汇编有关SQL声明.
和用普通的语句在每次用的时候都要编译一次相比,它提供的优势是,当你需要用相同的或相似的带不同参数的查询多次,语句就可以被DBMS编译和优化,而在不同参数时,不再要求编译。
PreparedStatements也是用连接方法来创建的。
下面的小代码展示了怎么创建一个有三个输入参数的带参数SQL语句:
PreparedStatementsprepareUpdateprice=con.preparedStatements(
“UPDATESellsSETprice=?
wherebar=?
ANDbeer=?
”);
在执行一个PreparedStatement前,我们需要提供参数的值。
这可以调用定义在PreparedStatement类中的SETXXX方法来完成。
最常用的方法是setInt,setFloat,setDouble,setString等。
你可以设置参数的值在执行准备的语句前。
继续上面的例子,我们将写:
prepareUpdatePrice.setInt(1,3);
prepareUpdatePrice.setString(2,"BarOfFoo");
prepareUpdatePrice.setString(3,"BudLite");
1.5执行DDL语句
在JDBC中执行SQL语句用很多样式,他们依赖于SQL语句的目的。
DDL(数据定义语言)语句,象表的创建和删除语句,还有更新表的内容的语句都是通过executeupdate方法执行的。
注意到这些命令都改变数据库的状态,因此方法的名字包含”Update”。
下面的代码是executeupdate语句的例子:
Statementstmtcon.createStatement();
stmt.Executeupdate(“CREATETABLESells”+“(barVARCHAR2(40),beer
VARCHAR2(40),priceREAL)”);
stmt.Executeupdate(“INSERTINTOSells”+“VALUES(‘BarOf
Foo’,’BudLite’,2.00)”);
StringsqlString=“CREATETABLEBars”+“name
VARCHAR2(40),addressVARCHAR2(80),licenseINT”);
Stmt.Executeupdate(sqlString);
由于SQL语句不太适合在一行上显示,我们就把它打断成两个字符串,并且用加号连接起来以便它被编译。
特别注意“INSERTINTOSells”和“VALUES”之间的间隔。
也注意我们更愿意重用相同的Statement而不是重新创建一个。
在执行executeUpdate时常常是调用DDL语句,返回的结果一般是0,在数据修改语句执行时将返回一个大于或等于0的值,这个数据表明了其间的关系。
当使用PreparedStatement时,我们将执行这样的一个语句,它首先要设定参数的值(象上面所见的那样),接着调用executeUpdate.
intn=prepareUpdatePrice.executeUpdate();
1.6执行SQL语句
作为和前一节的语句相对的语句,一个查询希望得到一组记录来作为结果,并且不改变数据库的状态。
自然地,这里就有相应的方法叫做executeQuery,它返回一个ResultSet对象作为其结果。
Stringbar,beer;
floatprice;
ResultSetrs=stmt.executeQuery(“SELECT*FROMSells”);
While(rs.next()){
Bar=rs.getString(“bar”);
Beer=rs.getString(“beer”);
Price=rs.getFloat(“price”);
System.out.println(bar+“sells”+beer+“for”+price+“Dollars.”);
}
查询得到的结果集包含在一个变量rs中,rs是ResultSet的一个实例。
这样的组对我们没有太大的作用,除非我们能访问每一行和每行中的各个属性。
ResultSeta给我们提供了一个能让我们依次访问每行的游标。
游标仅仅是第一行的集。
每次调用next方法使它移动到下一行,如果下一行存在就返回真,如果没有剩余行就返回错。
我们可以用适当类型的getXXX方法去检索行的各个属性。
在前面的例子中,我们用了getDtring和getFloat两个方法来访问各列的值。
注意到我们用想得到的值得列的列名作为方法的参数。
同时也注意,VARCHAR2类型的bar,beer被转换为JavaString,REAL转换为Javafloat.
同样地,我们可以指定列号来代替列名,也能得到相同的结果。
这样,有关的语句就应该是:
Bar=rs.getString
(1);
Beer=rs.getString
(2);
Price=rs.getFloat(3);
当使用PreparedStatement工作时,我们应该执行一个设置好参数的查询,并且用它调用executeQuery方法。
ResultSetrs=prepareUpdatePrice.executeQuery();
1.7结果集访问说明
JDBC提供了一系列的方法来找出你在处理结果集的那个地方,方法包括:
getRow,isFirst,isBeforeFirst,isLast,isAfterLast.
他们提供可以任意访问结果集中各行的游标。
默认的,游标仅仅只能向前并且是只读的。
在为Connection创建Statement时,你可以改变ResultSet的类型,使它成为更方便查找和更新的模型:
Statementstmt=con.createStartment(
ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
ResultSetrs=stmt.executeQuery(“SELECT*FROMSells”);
不同的类型选项有:
TYPE_FORWARD_ONLY、TYPE_SCROLL_INSENSITIVE、和TYPE_SCROLL_SENSITIVE。
你可以利用CONCUR_READ_ONLY和CONCUR_UPDATABLE选项来选择是用只读的还是可更新的游标。
用默认的游标,你可以利用rs.next()来卷动游标。
用可卷动的游标你可设置更多的选项:
rs.absolute(3);//移动到第三tuple
rs.previous();//向后移动一个tuple(tuple2)
rs.relative
(2);//向后移动两个tuples(tuple4)
rs.relative(-3);//往回移动两个tuples(tuple1)
这里还有很多可卷动游标特征的细节。
可卷动游标,虽然在某些应用中很有用,但是它非常复杂,因此在使用时要小心和克制。
更多关于游标细节的操作技术可以在NewFeaturesintheJDBC2.0API上找到。
1.8事务处理
JDBC允许多个SQL语句嵌入到一个单一的事务中。
因而,我们用JDBC事务可以确保ACID(原子性、一致性、独立性、完整性)属性。
事务控制是通过连接对象完成的。
当连接建立时,它就默认是自动提交型。
这意味着每个SQL语句都被认为是一个单独得事务,并且只要它自身执行完成就马上提交。
(这样并不完全精确,并且在大多数情况下,我们可能被它蒙蔽而不知道这些细节。
)
我们能为连接关闭自动提交,用:
con.setAutoCommit(false);
也可以再打开,用:
con.setAutoCommit(ture);
一旦自动提交关闭,没有SQL语句能被提交(那不是说,数据库将永远得不到更新),直到你明确地调用commit()方法来告诉它提交。
Cmit();
在提交之前的任何地方,我们都可也调用rollback()来卷回事务,并恢复数据到上一次提交的地方(在尝试更新之前)。
下面是个融合了上面观点的例子。
con.setAutoCommit(false);
Statementstmt=con.createStatement();
Stmt.executeUpdate(“INSERTINTOSellsVALUES(‘barof
foo’,’budlite’,’1.00’)”);
con.rollback();
Stmt.executeUpdate(“INSERTINTOSellsVALUES(‘barof
joe’,’Miller’,’2.00’)”);
mit();
con.setAutoCommit(true);
让我们浏览这个例子理解几个方法的用法和作用。
我们首先看看自动提交关闭时,接下来的几条语句需要看成一个整体。
我们尝试在Sells表中插入记录(‘baroffoo’,’budlite’,’1.00’))。
然而,这个操作最终并没完成(committed).当我们调用rollback,我们取消了插入。
注意,Sells表现在仍和我们尝试插入之前一样。
接着我们尝试插入其他记录,并且这次,我们提交了事务。
现在Sells表就受到了永久的影响,并且多了一条新的记录。
最后,我们重新开启了自动提交。
我们同样可以按需要地设定事务的独立性。
例如,我们可以设定事务独立性为TRANSACTION_READ_COMMITTED,它不允许访问数据直到数据提交完毕,同时也不允许读脏数据。
在连接的接口中提供了5个独立性级别。
默认下,独立性级别是串行化。
JDBC允许查看数据库设定的独立性级别(用连接的getTransactionIsolation方法),也可以设定适当的级别(用连接的setTransactionIsolation方法)。
rollback常常和Java异常处理结合在一起来恢复不可预知的错误。
这样的结合提供了简单而优秀的处理数据完整性的机制。
我们将在下一节学习JDBC的异常处理。
1.9错误与异常处理
事实上,在软件项目中错误是常常发生的。
经常,数据库程序是一个危险的应用,并且温和地捕捉和处理错误是势在必行的。
程序应该能恢复并使数据库保持一致性的状态。
Rollback与Java异常处理机制协同工作是达到这一要求的一条清晰的道路。
客户端(程序)访问服务器(数据库)需要是否有错误从服务器返回。
JDBC通过两个不同级别的错误情况(SQLException和SQLWarning)来获取以上信息。
SQLExceptions是Java异常,假如不处理,会终止应用程序。
SQLWarnings是SQLException的子类,但它们描述不致命的错误或不预期的情况等,可以忽略。
在Java中,预计要抛出异常或警告的语句被包含在try语句块中。
如果在try语句块中的语句抛出了异常或警告,那么,在相应的catch语句中将被捕获。
每个catch语句都被指明准备捕获那个异常。
下面是一个捕捉异常,使用错误情况来卷回事务的例子:
try{
con.setAutoCommit(false);
stmt.executeUpdate(“CREATETABLESells(barVARCHAR2(40),”+”beerVARHAR2(40),priceREAL)”);
stmt.executeUpdate("INSERTINTOSellsVALUES"+
"('BarOfFoo','BudLite',2.00)");
mit();
con.setAutoCommit(true);
}catch(SQLExceptionex){
System.err.println("SQLException:
"+ex.getMessage());
con.rollback();
con.setAutoCommit(true);
}
既然这样,一个异常肯定被抛出,因为错误的书写导致了beer被定义为VARHAR2。
由于在DBMS中没有这样的类型,一个SQLException将被抛出。
这样输出就将是:
Message:
ORA-00902:
invaliddatatype
还有就是,如果你的数据类型正确,但万一你的你的数据库超过了空间限制并不能再创建一个新的表。
SQLWarning可以从Connection对象、Statement对象和ResultSet对象中找回来。
每一个仅仅存放着最近的SQLWarning。
因此,只要你用你的Statement对象执行其他的语句,那么以前的警告就将被丢弃。
下面的小代码举例说明了怎么使用SQLWarning:
ResultSetrs=stmt.executeQuery("SELECTbarFROMSells");
SQLWarningwarn=stmt.getWarnings();
if(warn!
=null)
System.out.println("Message:
"+warn.getMessage());
SQLWarningwarning=rs.getWarnings();
if(warning!
=null)
warning=warning.getNextWarning();
if(warning!
=null)
System.out.println("Message:
"+warn.getMessage());
SQLWarnings(相对于SQLExceptions)其实是相当难得,最多的就是数据连接切断的警告。
后面将要指出的是在读或写数据库是这里存在的一个问题。
1.11简单的代码和编辑规则
有望地,到现在你已经可以熟悉地用JDBC写复杂的代码了。
这里有一个简单的例子融合了上面多有的观点。
我们还有一些简单的为教育的目的由CraigJurney编写的代码。
你可以免费地使用这些代码来作为一个准则,或者在将来写代码是用作筐架,但是你要在你引用了代码的应用上做一个说明。
SQLBuilder.java-CreationofaRelation关系的创建
SQLLoader.java-InsertionofTuples插入记录
SQLRunner.java-ProcessesQueries查询过程
SQLUpdater.java-UpdatingTuples更新记录
SQLBatchUpdater.java-BatchUpdating批更新
SQLUtil.java-JDBCUtilityFunctionsJDBC的有用函数
不要忘记用source/usr/class/cs145/all.env,它将正确的设置你的classpath。
增加你的全局的classpath的简单命令:
elaine19:
~$javacSQLBuilder.java
elaine19:
~$javaSQLBuilder
替换成:
elaine19:
~$javacSQLBuilder.java
elaine19:
~$java–classpath
/usr/pubsw/apps/oracle/8.1.5/jdbc/lib/classes111.zip:
SQLBuilder
在java的用户名和密码文件中有固定的用户名和密码。
他们必须被改成你自己的用户名和密码,这样你才能访问数据库。
这篇文章最初由NathanFolkert在2000年春写给JenniferWidom教授的CS145班,在2000年秋,它又被MayankBawa出租给JeffUllman教授的CS145班。
JimZhuang在2005年夏作了一点小改动。
同时感谢MattLaue的排版改正。
2利用JSP和JDBC技术访问动态的WEB数据
这篇文章讨论用JSP和JDBC技术来整合WEB站点上的静态的、动态的和数据库的内容。
为了简单和举例的需要,这里的JSP页面用简短的脚本来揭示JSP开发者根本的JDBC观点而不是把它们隐藏在传统的标签下。
作者介绍了一种关键的设计途径就是整合JavaBeans组件和JDBC,就好像JSP技术已经运用了bean和HTTP一样。
他也提供代码来执行这种整合。
建立在JavaServlet技术上,JSP技术是生成动态内容的Java服务器端的核心。
一种动态内容的来源是关系数据库。
为了管理来自在线社团的电子商务事务,WEB站点用关系数据库来存储各种信息:
目录条款,图像,文本,注册用户的数据等等。
这篇文章讨论利用JDBC的JSP与关系数据库的应用。
JDBC的意思就是通过它,Java程序可以操作关系数据库。
为了能更好的学习这篇文章,你应该熟悉JDBC和SQL。
2.1JDBC基础
JDBC是连接Java和SQL数据库的桥梁。
首要的JDBC对象描述数据库的连接且语句的执行要依赖这个连接。
和关系数据库一起使用的两种基本的语句是查询和更新。
作为先决条件,你首先需要用java.sql.DriverManger类建立一个数据库连接。
连接的建立要花费很长的时间,因此,在强事务环境中,比如一个WEB服务器,只要可能你就想要重用连接。
这样的重用称为connectionpooling。
如果你的JDBC技术已经生疏了,在例子Listing1中代码片段说明了怎样建立数据库连接,用连接创建statement对象,发送SQL查询,处理结果,以及释放JDBC资源。
Listing1.SimpleJDBCcode
Connectionconnection=DriverManager.getConnection(URL,user,password);
Statementstatement=connection.createStatement();
ResultSetresults=statement.executeQuery(sqlQuery);
while(results.next())
{
...processqueryresults...
logSQLWarnings(results.getWarnings());
}
results.close();
statement.close();
connection.close();
在现实生活中,JDBC代码没有这么简单;异常和警告情况需要处理。
例子Listing2是相同的JDBC例子但是增加了JDBC异常和警告的处理。
在这个例子中,