CHAPTER 第5章 数据库访问 大多数 Web应用需要将数据保存在数据库中。本书数据库示例都是在 MySQL数据 库管理系统下完成的。MySQL是最流行的开源关系数据库管理系统,其社区版虽然是免 费的,但是性能卓越,可以满足中小网站的需求。 5.1 创建 MySQL数据库 从官方网 站 http://www.mysql.com 下 载 MySQL 社 区 安 装 版,在 本 地 安 装 成 功 后, MySQL会自动启动。MySQL命 令 提 示 行 控 制 台 是 纯 字 符 命 令 操 作,命 令 繁 多 且 容 易 出 错。现在有很多开源的图形界面管理工具,如 MySQL-Front、phpMyAdmin等。本节介绍 利用 MySQL-Front数据库管理工具创建数据库。 5.1.1 创建数据库 使用 MySQL-Front创建数据库包括连接数据库实例、创建数据库、在数据库中新建表 等步骤。 1.创建数据库实例 安装好客户端 MySQL-Front后,打开客户端时,需要连接到指定的数据库实例。如果 第一次访问 MySQL-Front,则需要创建一个数据库实例,步骤如下。 (1)打开 MySQL-Front客户端,在图5.1所示的“打开登录信息”对话框中单击“新建”按钮。 (2)在 Host文本框中输入连接的服务器,本机为localhost,如图5.2所示。“端口”设 图5.1 打开登录信息 图5.2 设置连接属性 视频 94 JSP程序设计(第2版) 置为 MySQL安装时设置的端口号,默认值为 3306。输入用户名和密码,用户必须已经存 在且具有足够 权 限,这 里 在 “用 户 ”文 本 框 中 输 入 root,在 “密 码 ”文 本 框 中 输 入 123456 (MySQL安装过程中设置的密码)。然后单击“数据库”文本框右侧的浏览按钮,在“选择数 据库”对话框中选择当前存在的任一数据库实例。此时选择 MySQL提供的测试数据库实 例test(创建数据库后应选择自建数据库),单击“确定”按钮。 2.创建数据库 (1)在图5.3所示的窗口左侧列表框中右击连接地址,此处连接的地址是localhost,在 弹出的快捷菜单中选择“新建”→“数据库”选项。 图5.3 MySQL-Front窗口 图5.4 新建数据库 (2)在打开的“新建的数据库”对话框中输入数据 库名称geotest,选 择 数 据 库 的 编 码 方 式 为 UTF8,然 后单 击 “确 定 ”按 钮,完 成 数 据 库 的 创 建,如 图 5.4 所示。 3.新建数据库表 (1)在 MySQL-Front窗 口 的 左 侧 列 表 框 中 右 击 新建的数 据 库 名 geotest,在 弹 出 的 快 捷 菜 单 中 选 择 “新建”→“表格”选项,打开图 5.5所 示 的“添 加 表 格” 对话框,在“名称”文本框中输入表名 users。 (2)单击“字段”选项卡,单击“添加字段”图标,或 者右击字段列表空白区,选择“新建”选项,进入“添加 字段”对话框,如图5.6所示。按表5.1设置字段,然后 单击“确定”按钮。 第5章 数据库访问 95 图5.5 添加表格 图5.6 添加字段 表5.1 users表结构 字段名称 类 型 备 注 字段名称 类 型 备 注 userName varchar(20) 主键 interest varchar(20) 默认值为 null passWord varchar(20) 默认值为 null testGrade int 默认值为0 realName varchar(20) 默认值为 null testTime datetime pId varchar(18) 默认值为 null memo text 默认值为 null sex char(8) 默认值为 null 5.1.2 常用 DML语句 DML(DataManipulationLanguage,数据操纵语 言)命 令 使 用 户 能 够 查 询 数 据 库 以 及 操作已有数据库中的数据,包 括 查 询 数 据(select语 句)、插 入 数 据(insert语 句)、修 改 数 据 (update语句)、删除数据(delete语句)等。由于 DML 非常复杂,因此本节只列出后面章节 涉及的语句部分。 1.select语句 select语句主要用于查询数据库的操作,包括选择满足特定条件的记录、选择特定列、 计算列、设置列的别名、排序、分组等。select语句的功能非常强大,语法复杂。例如: select userName, realName,pId from users //列出 users 表用户名、真实姓名、身份证号 select * from users where userName="u1" //查找用户 u1 select count(*) from users //统计 users 表中记录个数 select * from users limit 20,10 //列出第 20 条之后的 10 条记录 select * from users where userName="u1" and password="1234" //根据用户名和密码查找 select * from users where realName like "王%" //查找姓王的用户 视频 96 JSP程序设计(第2版) 2.insert语句 使用insertinto语句可以实现向数据表中增加数据。语法格式如下: insert into tablename [(column1,column2,…)] values (value1,value2,…) 其中,insertinto是关键 字,表 示 向 数 据 库 表 中 插 入 数 据;tablename表 示 数 据 库 表 名 称;columnl、column2表 示 指 定 的 列 名,是 可 选 的 (插 入 数 据 列 数 等 于 数 据 表 总 列 数 时 可 选),多个列名之间用 逗 号 隔 开;values是 关 键 字,表 示 插 入 的 数 据,后 面 括 号 中 的 valuel、 value2表示向数据库表插入的数据值。例如: insert into users (userName,passWord,testGrade) values ("u1","123456",0) 3.update语句 如果需要修改数据库表中的数据,可以使用 update语句。语法格式如下: update tablename set column1=value1,column2=value2, … where conditions update和set是表示在数据库表中修改数据的关键字;tablename表示表的名称;关键 字set后面紧跟的是要修改的列名以及列名对应的值,多个列之间用逗号隔开;where子句 用来指定要修改的条件,如果不指定条件,会修改表中指定列的所有值。 例如下面修改表 users中用户 u1的性别和考试类型: update users set sex="female", testGrade=1 where username="u1" 4.delete语句 使用delete语句可以在数据库表中删除数据。delete语句可以删除数据库表中满足条 件的数据,也可以删除满足子查询指定条件的数据。 1)删除满足条件的数据 使用delete语句可以在数据库表中删除满足条件的数据记录,语法格式如下: delete from tablename where conditions deletefrom 是表示从数据库表中删除数据的关键字;tablename表示表名称;where子 句后面的condition是指定删除条件。例如,从 users表中删除用户名为 u1的用户: delete from users where userName="u1" 在使用delete语句执行删除操作时,不需要指定数据的列名,因为delete语句执行的操 作是删除数据库表中的行记录,而不是删除某一单独的列数据。 2)删除有外键约束的数据 在定义了外键约束的表中删除数据时,删除的数据要满足外键约束条件。例如,假设在 答题表tests中存 在 userName字 段,并 且 将 其 设 置 为 外 键。如 果 删 除 users表 中 的 用 户 u1,tests表中与 u1相关的数据将查不到用户 u1的其他信息,删除时将出现错误。此时,需 要先删除tests表中与 u1相关的数据,然后才能删除 users表中的用户 u1。 5.2 JDBC应用概述 JDBC的全称是JavaDataBaseConnectivity,即Java数据库连接。JDBC提供一套访问 关系数据库的标准 API,可以在Java应用程序中与关系数据库建立连接并执行相关操作。 第5章 数据库访问 97 目前主流的数据库都支持JDBC。通过JDBCAPI,可以使用完全相同的Java语法访问大量 各种各样的 SQL数据库。 利用JDBC查询数据库需要经过如下7个标准步骤: (1)载入JDBC驱动程序。 如果要载入驱动程序,只需要在 Class.forName()方法中指定数据库驱动程序的类名。 这样做就自动创建了驱动程序的实例,并注册到JDBC驱动程序管理器。 (2)定义连接 URL。 在JDBC中,连接 URL指定服务器的主机名、端口以及希望与之建立连接的数据库名。 (3)建立连接。 有了连接 URL、用户名和密码,可以建立到数据库的网络连接。连接建立之后,可以执 行数据库查询,直到连接关闭为止。 (4)创建 Statement对象。 创建 Statement对象才能向数据库发送查询和命令。 (5)执行查询或更新。 有了Statement对象,可以使用execute、executeQuery、executeUpdate或executeBatch 方法发送 SQL语句到数据库。 (6)结果处理。 数据库查询执行完毕之后,返回一个查询结果(ResultSet对象)。ResultSet表示一系 列的行和列,可以调用 next和各种get()方法对查询结果进行处理。 (7)关闭连接。 在执行完查询且处理完结果之后,应该关闭连接,释放与数据库相关联的资源。 5.2.1 载入JDBC驱动程序 由于厂商不一样,各种数据库产品的连接方式也会有差别。JDBC为不同数据库提供 了不同的驱动程序,通过驱动程序,JDBC屏蔽了各种数据库之间的差异。所以,驱动程序 是指导如何与实际的数据库服务器进行会话的软件部件。如果要载入驱动程序,只需要载 入相应的类。驱动程序类自身的一个static代码块自动生成驱动程序的实例,并将其注册 到JDBC驱动程序管理器。 常见数据库的驱动程序类名如下。 . Oracle驱动程序类:oracle.jdbc.driver.OracleDriver。 . SQLServer驱动程序类:com.microsoft.jdbc.sqlserver.SQLServerDriver。 . MySQL驱动程序类:com.mysql.jdbc.Driver。 不同版本的 MySQL使用的驱动程序并不相同,可以在 MySQL的官方网站下载最新 版的数 据 库 驱 动 程 序 (http://www.mysql.com)。然 后,将 mysql-connector-java-5.1.37- bin.jar文件(或其他版本的驱动程序)复制到 Tomcat安装目录的common\lib目录下,或将 其复制到网站的 WEB-INF\lib目录中。 加载过程是使用 Class.forName()方法将驱动加载到运行环境中。加载时,驱动程序会 自动在驱动程序管理器中完成注册。加载过程中,如果未找到驱动程序或驱动程序版本不 匹配,会产生 一 个 ClassNotFoundException错 误,因 而 必 须 将 Class.forName()方 法 放 在 视频 98 JSP程序设计(第2版) try…catch块中(如代码清单5-1所示)。 代码清单5-1 加载 MySQL驱动程序 String driverName="com.mysql.jdbc.Driver"; try{ Class.forName(driverName); }catch(ClassNotFoundException e){ e.printStackTrace(); } 5.2.2 定义连接 URL 指向数据库的 URL所使用的标准规范是JDBC,连同服务器主机名、端口和数据库名 (或引用名)一起构成 URL。不同类型数据库对应的 URL并不相同,常见的访问本机 URL 如下:. MySQL的 URL为jdbc:mysql://127.0.0.1:3306/geotest。 . Oracle的 URL为jdbc:oracle:thin:@127.0.0.1:1521:geotest。 . SQLServer的 URL为jdbc:sqlserver://127.0.0.1:1433;DatabaseName=geotest。 . MSAccess(已建立 ODBC数据库连接名geotest)的 URL为jdbc:odbc:geotest。 5.2.3 建立连接 像使用 MySQL-Front一样,在 操 作 数 据 库 之 前 建 立 连 接 时 需 要 提 供 用 户 名 和 密 码。 建立实际的网络连接时,需要将 URL、数据库用 户 名 和 数 据 库 密 码 传 递 给 DriverManager 类的getConnection()方法。如果不能建立连接,getConnection()方 法 会 抛 出 SQLException 异常,因此需要使用try…catch(如代码清单5-2所示)。 代码清单5-2 连接 MySQL数据库 String url="jdbc:mysql://127.0.0.1:3306/geotest"; String username="root"; String password="123456"; try{ Connection con=DriverManager.getConnection(url,username,password); }catch(SQLException e){ e.printStackTrace(); } getConnection()方法也提供只接收一个参数的连接形式,此时需要将用户名和密码等 参数用连接字符串的形式附加在 URL后(如代码清单5-3所示)。 在建立连接时,JDBC会使用默认的字符编码。在前面建立数据库的过程中,因为选择 的是 UTF-8编码,与默认的字符编码不一致,所以在操作数据 库 的 过 程 中,中 文 会 出 现 乱 码。因此,在建立连接时,需要向getConnection()方法传递编码方式。 代码 视频 代码 第5章 数据库访问 99 代码清单5-3 另一种连接 MySQL数据库的方式 String url =" jdbc: mysql://127. 0. 0. 1: 3306/geotest? user = root&password = 123456&characterEncoding=UTF-8"; try{ Connection con=DriverManager.getConnection(url); }catch(SQLException e){ e.printStackTrace(); } JDBC定义了数据库的连接、SQL语句的执行以及查询结果集的遍历等。这些操作类 位于包java.sql的下面,如java.sql.Connection、java.sql.Statement、java.sql.ResultSet等,各 个数据库提供商在自己的JDBC驱动中实现了这些接口。在JSP页面中使用这些 API前 需要在page指令中设置import属性: <% page import="java.sql.*" %> 5.2.4 创建 Statement对象 Statement对象用来向数据库发送查询和命令。它由 Connection的createStatement() 方法创建,如代码清单5-4所示。 代码清单5-4 创建 Statement Statement statement=con.createStatement(); 5.2.5 执行查询或更新 有了 Statement对象之后,可以使用它的executeQuery()方法发送 SQL查询,或者使 用executeUpdate()方法执行插入、更新等命令。 通常使用 Statement对象的3个基本方法来执行 SQL命令。 1.executeQuery()方法 executeQuery()方法主要用来执行查询命令,返回一个 ResultSet对象。ResultSet可 能为空,但不会是 null。例如,查询 users表的所有数据: String sql="select * from users"; ResultSet rs=statement.executeQuery(sql); 2.executeUpdate()方法 executeUpdate()方法主要用来执行插入、删除及修改记录操作,返回一个int值,此整 型值是被更新的行数,可以为0。executeUpdate()方法也支持createtable等命令。例如, 向 users表中插入一行记录: String sql ="insert into users(userName,passWord) values ( 'u2', '123456') " ; int n=statement.executeUpdate (sql); 代码 代码 1 00 JSP程序设计(第2版) 3.execute()方法 execute()方法主要用来执行一般的 SQL命令,包括增删改查以及数据定义,返回一个 布尔值,显示是否返回一个 ResultSet对象。例如,查询 user表中的所有数据: String sql="select * from users"; Boolean value=statement.execute(sql); 如果value变量取真,则表明返回一个结果集对象,然后再通过statement.getResultSet 方法获取一个 ResultSet对象(如代码清单5-5所示)。 代码清单5-5 执行查询 String sql="select userName,realName,pId,testGrade from users"; ResultSet rs=statement.executeQuery(sql); 5.2.6 结果处理 ResultSet对象的每条 记 录 结 果 代 表 一 个 数 据 表 行。处 理 结 果 最 简 单 的 方 式 是 使 用 ResultSet的 next()方法在表中移动,每次一行。 在一行内,ResultSet提供各种getXxx()方法,它们都以列名或列索引为参数,以各种不同 的Java类型返回结果。例如,下面前两行代码都可以取到当前行的userName字段值: String un=rs.getString("userName"); String un=rs.getString(1); //列索引从 1 开始(遵循 SQL 的约定) int tg=rs.getInt("testGrade"); 以列索引为参数的get()方法的代码可读性差,容易出错,不易维护,应尽量避免使用。 代码清单5-6为显示查询结果。 代码清单5-6 显示查询结果 while(rs.next()){ String un=rs.getString("userName"); String rn=rs.getString("realName"); String pid=rs.getString("pId"); int tg=rs.getInt("testGrade"); out.println("username="+un+"realname="+rn+"person id="+pid+"testgrade="+tg); } JDBC使用Java技术来访问数据库数据。数据库数据类型和Java数据类型不同,所以 使用JDBC时,需要将Java数据类型与数据库数据类型进行转换。数据库数据类型和Java 数据类型的对照如表5.2所示。 表5.2 数据库数据类型和Java数据类型的对照 数据库数据类型 Java数据类型 数据库数据类型 Java数据类型 char String integer int varchar String bigint long 代码 代码 续表 第5章 数据库访问 1 01 数据库数据类型 Java数据类型 数据库数据类型 Java数据类型 longvarchar String real float numeric bigDecimal float float decimal bigDecimal double double bit boolean binary byte[] tinyint byte date Java.sql.Date smallint short time Java.sql.Time 5.2.7 关闭连接 关闭连接使用如下语句: con.close(); 关闭连接还会关闭对应的 Statement和 ResultSet对象。 下面综合 上 述 各 步,完 成 对 users表 的 显 示。在 GeoTest项 目 网 站 根 目 录 下 创 建 userlist.jsp,内容如代码清单5-7所示。 代码清单5-7 显示 users表的部分字段(userlist.jsp) <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= "UTF-8"%> <%@ page import="java.sql.*" %>