JDBC在Java Web中的应用
JDBC在Java Web中的应用
制作人:全心全意
在Java Web开发中,JDBC的应用十分广泛。通常情况下,Web程序操作数据库都是通过JDBC实现,即使目前数据库方面的开源框架层出不穷,但其底层实现也离不开JDBC API。
开发模式
在Java Web开发中使用JDBC,应遵循MVC的设计思想,从而使Web程序拥有一定的健壮性、可扩展性。
MVC(Model-View-Conntroller)是一种程序设计理念,该理念将软件分成3层结构,分别为模型层、视图层和控制层。其中模型层泛指程序中的业务逻辑,用于处理真正的业务操作;视图层是指程序与用户交互的页面,对用户呈现出视图,但不包含业务逻辑;控制层是对用户各种请求的分发处理,将指定的请求分配给指定的业务逻辑进行处理。
JDBC应用于Java Web开发中,处于MVC中的模型层位置,如下图所示。
客户端通过JSP页面与程序进行交互,对于数据的增、删、改、查请求由Servlet对其进行分发处理,如Servlet接收到添加数据请求,就会分发给增加数据的JavaBean对象,而真正的数据库操作是通过JDBC封装的JavaBean进行实现。
分页查询
分页查询是Java Web开发中常用的技术。在数据库量非常大的情况下,不适合将所有数据显示到一个页面中,既给查看带来方便,又占用了程序及数据库的资源,此时就需要对数据进行分页查询。
通过JDBC实现分页查询的方法有很多种,而且不同的数据库机制也提供了不同的分页方式,下面介绍两种典型的分页方法。
- 通过ResultSet的光标实现分页
ResultSet是JDBC API中封装的查询结果集对象,通过该对象可以实现数据的分页显示。在ResultSet对象中,有一个“光标”的概念,光标通过上下移动定位查询结果集中的行,从而获取数据。所以通过ResultSet的移动“光标”,可以设置ResultSet对象中记录的起始位置和结束位置,来实现数据的分页显示。
通过ResultSet的光标实现分页,优点是在各种数据库上通用,缺点是占用大量资源,不适合数据量大的情况。
- 通过数据库机制进行分页
很多数据库自身都提供了分页机制,如SQL Server中提供的top关键字,MySQL数据库中提供的limit关键字,它们都可以设置数据返回的记录数。
通过各种数据库提供的分页机制实现分页查询,其优点是减少数据库资源的开销,提供程序的性能;缺点是只针对某一种数据库通用。
说明:由于通过ResultSet的光标实现数据分页存在性能方面的缺陷,所以,在实际开发中,很多情况下都是采用数据库提供的分页机制来实现分页查询功能。
示例一:通过MySQL数据库提供的分页机制,实现商品信息的分页查询功能,将分页数据显示在JSP页面中
示例一建表语句:
CREATE TABLE `tb_product` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, `num` int(11) DEFAULT NULL, `price` double DEFAULT NULL, `unit` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Product类:封装商品信息,该类是商品信息的JavaBean
package com.zq; public class Product { public static int PAGE_SIZE = 2; // 每页记录数 private int id;// 编号 private String name;// 名称 private double price;// 价格 private int num;// 数量 private String unit;// 单位 public int getId() { return id; } public void setId(int id) { this.id = id; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public String getUnit() { return unit; } public void setUnit(String unit) { this.unit = unit; } }
在Product类中,主要封装了商品对象的基本信息。除此之外,Product类还定义了分页中的每页记录数。
ProductDao类:封装商品对象的数据库相关操作
package com.zq; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; public class ProductDao { // 获取数据库连接 public Connection getConnection() { Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8"; String username = "root"; String password = ""; conn = DriverManager.getConnection(url, username, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return conn; } // 分页查询所有商品信息 public List<Product> find(int page) { List<Product> list = new ArrayList<Product>(); Connection conn = getConnection(); String sql = "select * from tb_product order by id desc limit ?,?"; try { PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, (page - 1) * Product.PAGE_SIZE); ps.setInt(2, Product.PAGE_SIZE); ResultSet rs = ps.executeQuery(); while (rs.next()) { Product p = new Product(); p.setId(rs.getInt("id")); p.setName(rs.getString("name")); p.setNum(rs.getInt("num")); p.setPrice(rs.getDouble("price")); p.setUnit(rs.getString("unit")); list.add(p); } rs.close(); ps.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } return list; } // 查询总记录数 public int findCount() { int count = 0; Connection conn = getConnection(); String sql = "select count(*) from tb_product"; try { Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); if (rs.next()) { count = rs.getInt(1); } rs.close(); stmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } return count; } }
FindServlet类:分页查询商品信息的Servlet对象
package com.zq; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/FindServlet") public class FindServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int currPage = 1; if (request.getParameter("page") != null) { currPage = Integer.parseInt(request.getParameter("page")); } ProductDao dao = new ProductDao(); List<Product> list = dao.find(currPage); request.setAttribute("list", list); int pages; int count = dao.findCount(); if (count % Product.PAGE_SIZE == 0) { pages = count / Product.PAGE_SIZE; } else { pages = count / Product.PAGE_SIZE + 1; } StringBuffer sb = new StringBuffer(); for (int i = 1; i < pages + 1; i++) { if (i == currPage) { sb.append("『" + i + "』"); } else { sb.append("<a href='FindServlet?page=" + i + "'>" + i + "</a>"); } sb.append(" "); } request.setAttribute("bar", sb.toString()); System.out.println(sb.toString()); request.getRequestDispatcher("product_list.jsp").forward(request, response); } }
FindServlet类的doGet()方法主要做了两件事,分别为获取分页查询结果集及构造分页条对象。其中获取分页查询结果非常简单,通过调用ProductDao类的find()方法,并传递所要查询的页码就可以获取;分页条对象是JSP页面中的分页条,用于显示商品信息的页码,程序中主要通过创建页码的超链接,然后组合字符串进行构造
product_list.jsp页面:通过获取查询结果集List与分页条来分页显示商品信息数据
<%@page import="com.zq.Product"%> <%@page import="java.util.List"%> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>主页</title> </head> <body> <table align="center" width="450" border="1"> <tr> <td align="center" colspan="5"> <h2>所有商品信息</h2> </td> </tr> <tr align="center"> <td><b>ID</b></td> <td><b>商品名称</b></td> <td><b>价格</b></td> <td><b>数量</b></td> <td><b>单位</b></td> </tr> <% List<Product> list = (List<Product>) request.getAttribute("list"); int i = 1; if (request.getParameter("page") != null) { i = Integer.parseInt(request.getParameter("page")) * 2 - 1; } for (Product p : list) { %> <tr> <td><%=i++%></td> <td><%=p.getName()%></td> <td><%=p.getPrice()%></td> <td><%=p.getNum()%></td> <td><%=p.getUnit()%></td> </tr> <% } %> <tr> <td align="center" colspan="5"><%=request.getAttribute("bar")%> </td> </tr> </table> </body> </html>
index.jsp页面:程序主页面
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>首页</title> </head> <body> <a href="FindServlet">查看所有商品信息</a> </body> </html>