Java Web应用与数据库的通信一般通过JDBC连接来实现,不同的数据库厂商通常都会提供与其产品相对应的JDBC驱动程序,以满足Java Web应用对数据库的访问。
JDBC是Java数据库连接(Java Data base Connectivity)技术的缩写。JDBC为Java程序提供了一套操作各种数据库的统一接口,使得我们在使用JDBC API编写程序时无须关心所操作的各种数据库产品。
Java程序与JDBC及各种数据库产品的关系如图4-1所示。
常用的JDBC API封装在java.sql这个包中,下面我们简单介绍java.sql中的一些接口和类。
1.Driver接口与DriverManager类
通过图4-1 不难看出,Java程序在对具体的数据库进行操作之前,都必须将与之对应的JDBC驱动程序加入到classpath中。在基于Java EE的Web应用实际开发过程中,通常要将目标数据库产品的JDBC驱动复制到WEB-INF/lib下。
所有的JDBC驱动程序都必须实现Driver接口,DriverManager类主要负责管理这些JDBC驱动,以及为我们提供建立在这些驱动之上的数据库连接Connection。
DriverManager的常用方法见表4-1。
表4-1 DriverManager类的常用方法
图4-1 Java程序与JDBC及各种数据库产品的关系
2.Connection接口
一个应用程序可与单个数据库有一个或多个连接,或者可与许多数据库有连接。通过DriverManager的getConnection()方法来建立与数据库的连接并返回Connection,此时的Connection其实就代表了与数据库的连接,然后通过Connection提供的一些方法进行有关的操作。
Connection的常用方法见表4-2。
表4-2 Connection接口的常用方法
3.Statement接口
建立了与数据库的连接以后,对于一些静态(不需要动态替换SQL参数)的SQL语句,我们就可以用Statement对象来执行。Statement对象可通过Connection对象的createStatement()方法取得。
Statement的常用方法见表4-3。
表4-3 Statement接口的常用方法
4.PreparedStatement接口
建立了与数据库的连接以后,对于一些动态(需要动态替换SQL参数)的SQL语句,可以用PreparedStatement对象来执行。PreparedStatement对象可通过Connection对象的prepareStatement ()方法取得。
使用PreparedStatement一般分为以下3个步骤。
(1)使用Connection对象的prepareStatement(String sql)方法建立一个PreparedStatement对象。
(2)使用PreparedStatement对象的setXXX方法为参数赋值。
(3)使用PreparedStatement对象的executeQuery()执行SQL语句并得到ResultSet对象。
PreparedStatement的常用方法见表4-4。
表4-4 PreparedStatement接口的常用方法
5.ResultSet接口
查询数据库的最终目的是想得到一个满足条件的结果记录集,然后再对该记录集中的数据进行操作。通过前面所讲的Statement对象和PreparedStatement对象来执行指定的查询SQL语句后将返回代表结果记录集的ResultSet对象,该ResultSet对象除了包含查询结果记录集外,还维护着一个指向当前数据行的游标,通过改变游标的位置来达到操作不同记录的目的。
ResultSet的常用方法见表4-5。
表4-5 ResultSet接口的常用方法
(续表)
注:ResultSet对象中的记录号和字段号都从1开始。
在Java程序中通过JDBC操作数据库一般分为以下几个步骤。
(1)将数据库的JDBC驱动加载到classpath中,在基于Java EE的Web应用实际开发过程中,通常要把目标数据库产品的JDBC驱动复制到WEB-INF/lib下。
(2)加载JDBC驱动,并将其注册到DriverManager中。下面是一些主流数据库的JDBC驱动加载注册的代码:
// Oracle8/8i/9i数据库(thin模式)
Class.forName('oracle.jdbc.driver.OracleDriver').newInstance();
// Sql Server7.0/2000 数据库
Class.forName('com.microsoft.jdbc.sqlserver.SQLServerDriver').newInstance();
// DB2 数据库
Class.forName('com.ibm.db2.jdbc.app.DB2Driver ').newInstance();
// Informix数据库
Class.forName('com.informix.jdbc.IfxDriver').newInstance();
// Sybase数据库
Class.forName('com.sybase.jdbc.SybDriver').newInstance();
// MySQL数据库
Class.forName('com.mysql.jdbc.Driver').newInstance();
// PostgreSQL数据库
Class.forName('org.postgresql.Driver').newInstance();
(3)建立数据库连接,取得Connection对象。例如:
(4)建立Statement对象或PreparedStatement对象。例如:
//建立Statement对象
Statement stmt=conn.createStatement();
//建立PreparedStatement对象
String sql='select * from users where userName=? and password=?' ;
PreparedStatement pstmt=conn.prepareStatement(sql);
pstmt.setString(1, 'admin');
pstmt.setString(2, 'liubin');
(5)执行SQL语句。例如:
//执行静态SQL查询
String sql='select * from users';
ResultSet rs = stmt.executeQuery(sql);
//执行动态SQL查询
ResultSet rs = pstmt.executeQuery();
//执行insert、update、delete等语句,先定义SQL
stmt.executeUpdate(sql);
(6)访问结果记录集ResultSet对象。例如:
(7)依次将ResultSet、Statement、PreparedStatement、Connection对象关闭,释放所占用的资源。例如:
rs.close();
stmt.close();
pstmt.close();
con.close();
到目前为止,虽然已经可以在JSP或Servlet中使用JDBC访问数据库了,但是还是觉得每次使用之前要建立连接、用完后又要关闭有点麻烦,况且用户数量较多时,单耗在建立连接与销毁连接上的资源就不少,严重地降低了系统的性能。
如果有这么一个对象,专门负责建立和管理与数据库的连接,把数据库连接当做一种共享资源供所有需要访问数据库的组件使用,则不仅提高了系统的性能,而且也减轻了Java程序员的负担和提高了应用程序的可移植性。这就是下面要讲到的数据源和连接池。
数据库连接池在应用程序启动时就创建足够多的数据库连接,在Java程序需要访问数据库时就可以通过数据源取得一个空闲连接,用完后再还回池中。
下面以Tomcat 6.0 + MySQL 5.5 为例讲解数据源和连接池的配置。
(1)将数据库的JDBC驱动程序复制到<CATALINA_HOME>/common/lib 目录下。
(2)在<CATALINA_HOME>/conf/server.xml中配置数据源和连接池。例如:
(3)在web.xml中配置对数据源连接池的引用,例如:
(4)在JSP或Servlet程序中通过数据源访问数据库,例如:
本实例通过商品浏览页面index.jsp(见例程4-1)、购物车页面cart.jsp(见例程4-2)与处理用户请求的页面buy.jsp(见例程4-3)实现一个简单的购物车系统,所有JDBC的数据库操作代码全部放置在相应的JSP页面中,这里只是为了演示JDBC在JSP中的用法而已,在实际开发中并不推荐这样使用。
本实例的视频教程请参考配套光盘的“视频教程”部分。
1.数据字典
用于存放所有商品数据的商品架shop表见表4-6。
表4-6 商品架shop表
购物车cart表见表4-7。
表4-7 购物车cart表
例程4-1 商品浏览页面index.jsp
例程4-2 购物车页面cart.jsp
例程4-3 处理用户请求的页面buy.jsp
2.运行效果
商品浏览页面index.jsp的运行效果如图4-2所示。
图4-2 index.jsp的运行效果
购物车页面cart.jsp的运行效果如图4-3所示。
图4-3 cart.jsp的运行效果
本实例的完整源代码请参考配套光盘的“源代码”部分。