简单使用范例
下面是一个打印表中的书名的JSP页面源文件:
<%@标签lib uri="http://jakarta.apache.org/taglibs/dbtags" prefix="sql" %><%-- open a database connection --%><sql:connection id="conn1"> <sql:url>jdbc:mysql://localhost/test</sql:url> <sql:driver>org.gjt.mm.mysql.Driver</sql:driver></sql:connection><%-- open a database query --%><table><sql:statement id="stmt1" conn="conn1"> <sql:query> select id, name, description from test_books order by 1 </sql:query> <%-- loop through the rows of your query --%> <sql:resultSet id="rset2"> <tr> <td><sql:getColumn position="1"/></td> <td><sql:getColumn position="2"/></td> <td><sql:getColumn position="3"/> <sql:wasNull>[no description]</sql:wasNull></td> </tr> </sql:resultSet></sql:statement></table><%-- close a database connection --%><sql:closeConnection conn="conn1"/>
标签详细介绍
下面是DBTags标签库的总体描述,标签的某些细节,例如connection, statement, resultSet, 和 preparedStatement 标签的所有可能的属性,在这里没有讨论。 Tag Reference 列出了所有的细节。
Connection标签
打开连接
有三种方式打开一个数据库连接:
1. 使用数据库 URL
connection标签可以接受一个数据库URL通过Driver Manager获得一个Connection:
<%-- open a database connection --%><sql:connection id="conn1"> <%-- required --%> <sql:url>jdbc:mysql://localhost/test</sql:url> <%-- optional --%> <sql:driver>org.gjt.mm.mysql.Driver</sql:driver> <%-- optional --%> <sql:userId>root</sql:userId> <%-- optional --%> <sql:password>notVerySecure</sql:password></sql:connection>
"id"属性是必须的。在结束标签后,一个java.sql.Connection 对象被加为一个pageContext属性,可以被包括statement, preparedStatement, 和 closeConnection的其它的标签使用。
不在标签体内包含数据库URL, 驱动器名,用户id,或者口令,你可以使用可选属性"initParameter":
<%-- store your connection info in the web.xml file --%><sql:connection id="conn1"> <sql:url initParameter="dbURL"/> <sql:driver initParameter="mysqlDriver"/> <sql:userId initParameter="dbUserId"/> <sql:password initParameter="dbPassword"/></sql:connection>
2. 使用数据源
connection也可以接受一个指向Servlet属性的javax.sql.DataSource对象的引用。(这个属性是通过PageContext的findAttribute()方法得到的。):
<%-- open a database connection --%><sql:connection id="conn1" dataSource="ds1"> <%-- optional --%> <sql:userId>root</sql:userId> <%-- optional --%> <sql:password>notVerySecure</sql:password></sql:connection>
3. 使用JNDI命名的JDBC数据源
Connection也可以接受一个使用JNDI命名的JDBC数据源。
<%-- open a database connection --%><sql:connection id="conn1" jndiName="java:/comp/jdbc/test"/>
关闭连接
将一个connection的引用传递到"closeConnection" 标签关闭一个连接:
<%-- 除非你使用自己的连接池,否则总应该关闭连接 --%><sql:closeConnection conn="conn1"/>
Statement标签
"Statements"是向数据库提交查询的一种方法。(另一个是使用 "preparedStatement"。)基于statement查询的语法对任何知道SQL的人都是不陌生的。为了查询数据库,打开一个"statement"标签,传递给它一个sql "query", 然后要么对inserts, updates, 和deletes "execute"申明,或者调用resultSet 标签在一个select申明的结果上循环执行。下面是一个简单的insert:
<%-- 向数据库插入一行 --%><sql:statement id="stmt1" conn="conn1"> <%-- 设置SQL查询 --%> <sql:query> insert into test_books (id, name) values (3, '<sql:escapeSql><%=request.getParameter("book_title")%></sql:escapeSql>') </sql:query> <%-- 执行查询 --%> <sql:execute/></sql:statement>
转义SQL
"escapeSql"标签用在一个SQL查询里面转义输入的值里面可能的单引号。
错误处理
缺省情况下,SQL查询的执行导致的错误(例如主键violations(违例),残缺的SQL申明)将导致JSP页面的失败,你可以选择性的设置"execute"标签的"ignoreErrors"属性为"true",这将使SQL错误打印到标准输出而不会终止页面:
<sql:statement id="stmt1" conn="conn1"> <%-- 这个SQL查询是残缺的 --%> <sql:query>delete * from test_books</sql:query> <%-- 查询将失败,但是页面会继续 --%> <sql:execute ignoreErrors="true"/> </sql:statement>
空白处理
所有的statement和preparedStatement自动的去除空白。
PreparedStatement标签
"Prepared statements"是产生SQL查询的比较高级的形式。它不是直接将值插入SQL申明中,而是在需要设置值得地方放入一个'?'符号,然后使用一组独立的标签实际设置那些值。下面是statement中使用的范例的preparedstatement版本:
<%-- 向数据库插入一行 --%><sql:preparedStatement id="stmt1" conn="conn1"> <%-- 设置SQL查询。注意"name"值上缺少引号 --%> <sql:query> insert into test_books (id, name) values (?, ?) </sql:query> <sql:execute> <sql:setColumn position="1">3</sql:setColumn> <sql:setColumn position="2"><%=request.getParameter("book_title")%></sql:setColumn> </sql:execute> </sql:preparedStatement>
prepared statements的一个优点就是你不需要在文本上执行sql转义。然而,记住标准的statements对于那些没有连接池和prepared statements的数据库和驱动器在性能上更好。
setColumn标签
你可以将prepared statements的setColumn标签放置在execute或者 resultset标签的前面, 或者是execute标签的里面。execute标签永远不会输出它的内容(body),因此将setColumn标签放置在里面可以防止不必要的空白。
ResultSet标签
Resultset是一个select申明的结果。resultSet标签自动循环,每次一行。使用 "getColumn"标签从每行中提取值然后要么显示他们,要么将他们存为字符串:
<%--在一个HTML表格里面打印行 --%><table><sql:statement id="stmt1" conn="conn1"> <sql:query> select id, name, description from test_books order by 1 </sql:query> <%-- 循环提取查询结果中的行 --%> <sql:resultSet id="rset2"> <tr> <td><sql:getColumn position="1"/></td> <td><sql:getColumn position="2"/></td> <td><sql:getColumn position="3"/> <%-- 如果书没有说明则打印一个注释 --%> <sql:wasNull>[no description]</sql:wasNull></td> </tr> </sql:resultSet> </sql:statement></table>
"wasNull"和"wasNotNull"标签
"wasNull"标签只有在前面的"getColumn"标签遇到一个数据库中的空值(null)时执行它的体中的内容。你只能在一个resultset内并且"getColumn"标签已经被执行时使用"wasNull"标签。"wasNotNull"标签在它前面的getColumn标签没有产生一个空值(null)使执行它的体中的内容。参看Tag参考获得范例。
"getColumn"标签
getColumn标签执行两个中的一个功能。你可以:
-
直接向JSP输出列值(缺省行为)
<%-- 向JSP输出值 --%><sql:getColumn position="1"/>
, 或者
-
将值作为一个String对象写为页面的一个属性,通过"to"属性。如果你愿意,你也可以为"scope"属性分配一个不同于"page"的值。如果数据库中该列的值为null, getColumn标签 将不会创建属性。下面是一个使用getColumn标签产生一个整型的请求属性:
<%-- 注意请求的属性将是一个String --%><sql:getColumn position="1" to="someId" scope="request"/>
"getNumber"标签
如果你想对数字格式有更多的控制,使用getNumber标签。
"format"属性可以是DecimalFormat构造方法可以接受的模式或者是下面的类型: "CURRENCY", "PERCENT" 或者 "NUMBER"。
"locale"属性可以有一到三个部分,也就是Locale构造方法可以接受的形式: 语言,国家 和 变量。它们使用"_"分割。例如:
<%-- 格式化数据库值为英国货币形式 --%><sql:getNumber colName="id" format="CURRENCY" locale="en_GB"/>
如果format和locale属性都没有设置,输出将和getColumn一样。
time标签
有几个标签是设计用来显示时间相关的数据的: getTime, getTimestamp 和 getDate。
"format"属性可以是被SimpleDateFormat接受的形式或者是一个类型: "FULL","LONG", "MEDIUM" 或 "SHORT"。这个属性是可选的。
"locale"属性可以有一到三个部分,也就是Locale构造方法可以接受的形式: 语言,国家 和 变量。它们使用"_"分割。
禁止循环
缺省情况下resultset标签对ResultSet中的每行循环执行。通过设置可选属性"loop"为"false"就可以禁止这个特性然后手工操作ResultSet对象或者将它传递给另外的自定义标签。
<sql:statement id="stmt1" conn="conn1"> <sql:query> select id, name, description from test_books order by 1 </sql:query> <%-- 禁止resultset标签的循环 --%> <sql:resultSet id="rset2" loop="false"> <% ResultSet rset = (ResultSet) pageContext.getAttribute("rset2"); // 手工操作 %> </sql:resultSet> </sql:statement>
使用RowSets
你也可以用一个RowSet对象使用resultSet标签。通过设置选项"name",resultSet标签将查找一个ResultSet对象(包括RowSets)并将它以该名字存储在page, request, 或者session上下文上。通过设置可选属性"scope",你可以指定上下文来包含你的ResultSet/RowSet。注意当你从一个属性中读取一个ResultSet/RowSet,resultSet标签可以不在statement标签内。
<%-- 循环执行ResultSet/RowSet的每行,无论它来自何处 --%> <sql:resultSet id="rset1" name="rsetAtt"> <tr> <td><sql:getColumn position="1"/></td> <td><sql:getColumn position="2"/></td> <td><sql:getColumn position="3"/> <%-- 如果书没有说明则打印一个注释 --%> <sql:wasNull>[no description]</sql:wasNull></td> </tr> </sql:resultSet>
"wasEmpty"和"wasNotEmpty"标签
"wasEmpty"标签只有在上一个ResultSet标签从数据库中得到0行时执行它的体内的内容。它必须放在一个resultSet标签后否则将出错。"wasNotEmpty"标签在上一个ResultSet从数据库中得到了多于 0 行时执行体内的内容。参看Tag参考得到使用范例。
"rowCount"标签
"rowCount"标签打印数据库返回的行数。可以在ResultSet标签内使用它提供一个运行计数,或者在ResultSet标签后面使用打印总数。参看Tag 参考得到使用范例。在ResultSet前使用该标签将产生一个错误。