一、JDBC技术
1、JDBC简介
JDBC是Java程序与数据库系统通信的标准API,它定义在JDK的API中,通过JDBC技术,Java程序可以非常方便地与各种数据库交互,JDBC在Java程序与数据库系统之间假期了一座桥梁。
JDBC由一组用Java语言编写的类和接口组成,它对数据库的操作提供了基本方法,但由于数据库种类跟多且多有不同,所以对数据库的细节操作由数据库厂商进行实现,且厂商需要提供数据库的驱动程序,下图为Java程序与数据库相交互的示意图:
2、JDBC连接数据库的过程
l 下载驱动包
在JDK中,不包含数据库的驱动程序,使用JDBC操作数据库需要实现下载数据库厂商提供的驱动包,并导入到开发环境中。
l 注册数据库驱动
连接数据库前,需要将数据库厂商提供的数据库驱动注册到JDBC的驱动管理器中,一般是通过将数据库驱动类加载到JVM来实现的,例如连接MYSQL数据库:
Class.forName(“com.mysql.jdbc.Driver”);
l 构建数据库连接URL
URL由数据库厂商制定,不同数据库它的URL有所区别,但都符合一个基本的格式,即“JDBC协议+IP地址或域名+端口+数据库名称”,例如MYSQL数据库为”jdbc:mysql://localhost:8080/test”。
前两步中不同数据库有所差别,不同数据库连接请参考这篇文章:
http://blog.csdn.net/zhai56565/article/details/8959184
l 获取Connection对象
通过驱动管理器获得数据库的连接Connection,只有创建此对象后才可以对数据库进行操作,方法如下:
DriverManager.getConnection(url , username , password);
下面是一个完整的连接数据库的例子:
- try {
- //加载数据库驱动,注册到去送管理器
- Class.forName("com.mysql.jdbc.Driver");
- String url = "jdbc:mysql://localhost:8080/test";
- String username = "admin";
- String password = "123456";
- Connection conn = DriverManager.getConnection(url , username , password);
- if (conn != null)
- System.out.println("数据库连接成功!");
- else
- System.out.println("数据库连接失败!");
- //完成后记得关闭数据库连接
- conn.close();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- }
二、JDBC API
JDBC是Java程序操作数据库的标准,它由一组用Java语言编写的类和接口组成,Java通过JDBC可以对多种关系数据库进行统一访问。下面介绍主要类和接口的作用,详细方法请参考J2SE的API。
1、 Connection接口
与特定数据库的连接会话,只有获得特定数据库的连接对象才能访问数据库,操作数据库中的数据表、视图和存储过程等。
方法声明 |
说明 |
Close() |
立即释放Connection对象的数据库连接占用的JDBC资源 |
Commit() |
提交事务,并释放Connection对象当前持有的所有数据库锁 |
createStatement() |
创建Statement对象来将SQL语句发送到数据库 |
PreparedStatement |
将参数化的SQL语句预编译并存储在PreparedStatement对象中 |
2、DriverManager类
主要作用与用户及驱动程序之间,它是JDBC中的管理层,通过它可以管理数据库厂商提供的驱动程序,并建立应用程序与数据库之间的连接。
方法声明 |
说明 |
getConnection(String url) |
根据指定数据库连接URL,建立Connection |
getConnection(String url , Properties info) |
根据指定数据库连接URL及数据库连接属性信息建立数据库连接Connection,参数info为数据库连接属性 |
getConnection(url,un,pwd) |
根据指定数据库连接URL,用户名和密码连接数据库 |
getDrivers() |
获取当前DriverManager中已加载的所有驱动程序 |
3、 Statement接口
Statement接口封装了执行SQL语句和获取查询接口的基本方法。
方法声明 |
说明 |
AddBatch(String sql) |
将SQL语句添加到Statement对象的当前命令列表中,用于SQL命令的批处理 |
clearBatch() |
清空Statement对喜爱那个的命令列表 |
Close() |
立即释放Statement对象的数据库和JDBC资源,而不是等待该对象自动关闭时执行 |
Execute(String sql) |
执行指定的SQL语句,若SQL返回结果,该方法返回true,否则返回false |
executeBatch() |
将一批SQL命令提交给数据库执行,返回更新计数组成的数据 |
executeQuery(String sql) |
执行查询类型的sql语句,该方法返回查询所获取的结果集ResultSet |
executeUpdate(String sql) |
执行SQL语句中DML类型(insert、update、delete)的SQL语句,返回更新所影响的行数 |
getConnection() |
获取生成Statement对喜爱那个的Connection对象 |
4、PreparedStatement接口
Statement接口封装了JDBC执行SQL语句的方法,但在实际开发过程中,SQL语句往往需要将程序中的变量做查询条件参数等。使用Statement接口进行操作过于繁琐且存在安全缺陷。而PreparedStatement接口继承与Statement接口,且对带有参数SQL语句的执行操作进行了扩展。应用于PreparedStatement接口中的SQL语句可以使用占位符”?”来代替SQL语句中的参数,然后再对其进行赋值。
方法声明 |
说明 |
setBinaryStream(int x , InputStream s) |
将输入流s作为SQL语句中的参数值,x为参数位置索引 |
setBoolean(int x , Boolean b) |
将布尔值b作为SQL语句中的参数值,x为参数位置索引 |
SetByte |
…… |
setInt |
…… |
等等。。。。。。 |
…… |
5、ResultSet接口
ResultSet对象封装了数据查询的结果集,它包含了符合SQL语句的所有行,针对Java中的数据类型提供了一套getXXX()的方法,通过这些方法可以获取每一行中的数据。ResultSet还提供了光标的功能,通过光标可以*定位到某一行中的数据。
方法声明 |
说明 |
Absolute(int row) |
光标移动到ReulstSet对象的给定行编号 |
afterLast() |
光标移动到最后一行后,如果结果集中不包含任何行,则该方法无效 |
beforFirst() |
立即释放ResultSet对喜爱那个的数据库和JDBC资源 |
deleteRow() |
删除当前行 |
First() |
光标移动到第一行 |
getString(String columnLable) |
以String的方式获取ResultSet对象当前行中指定列的值,参数为列名称 |
getBinaryStream(String colunmLable) |
你懂得 |
getInt(String columnLable) |
你懂得 |
isClosed() |
判断ResultSet对喜爱那个是否已关闭 |
Last() |
移动到最后一行 |
Next() |
移动到下一行,若新行无效则返回false |
Previous() |
移动到上一行,若新行无效则返回false |
三、JDBC操作数据库
上一篇介绍了JDBC API,之后就可以通过API来操作数据库,实现对数据库的CRUD操作了。
http://blog.csdn.net/zhai56565/article/details/9794225
下面仅以示例 的方式对数据库操作进行说明
1、 添加数据
使用PreparedStatement添加数据:
- String sql = "INSERT INTO tb_books(name,price,count,author)valuse(?,?,?,?)";
- PreparedStatement ps = conn.prepareStatement(sql);
- ps.setString(1, "西游记");
- ps.setDouble(2, 66.0);
- ps.setInt(3, 200);
- ps.setString(4, "吴承恩");
- int row = ps.executeUpdate();
- if(row > 0)
- System.out.println("成功添加了" + row + "条数据");
使用Statement添加数据:
- String sql = "INSERT INTO tb_books(name,price,count,author)valuse(" + "西游记" + "," + 66.0 + "," + 200 + "," + "吴承恩" + ")";
- ps.close();
- Statement ps = conn.createStatement();
- int row = ps.executeUpdate(sql);
- if(row > 0)
- System.out.println("成功添加了" + row + "条数据");
- ps.close();
2、查询数据
查询数据是通过一个Web项目来演示,通过JDBC查询图书信息表中的图书信息数据,并将其显示在JSP页面中:
创建Book类:
- package com;
- public class Book {
- private int id;
- private String name;
- private double price;
- private int count;
- private String author;
- public Book(int id , String name , double price , int count , String author) {
- this.id = id;
- this.name = name;
- this.price = price;
- this.count = count;
- this.author = author;
- }
- public int getId(){
- return id;
- }
- public void setId(int id){
- this.id = id;
- }
- public String getName(){
- return name;
- }
- public void setName(String name){
- this.name = name;
- }
- public double getPrice(){
- return price;
- }
- public void setPrice(double price){
- this.price = price;
- }
- public int getCount(){
- return count;
- }
- public void setCount(int count){
- this.count = count;
- }
- public String getAuthor(){
- return author;
- }
- public void setAuthor(String author){
- this.author = author;
- }
- }
创建Servlet对象FindServlet:
- @WebServlet("/FindServlet")
- public class FindServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- public FindServlet() {
- super();
- }
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- doPost(request, response);
- }
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- try {
- Class.forName("com.mysql.jdbc.Driver");
- String url = "jdbc:mysql://localhost:8080/db_test";
- String username = "admin";
- String password = "123456";
- Connection connection = DriverManager.getConnection(url, username, password);
- Statement statement = connection.createStatement();
- String sql = "SELECT * FROM tb_books";
- ResultSet rs = statement.executeQuery(sql);
- ArrayList<Book> list = new ArrayList<Book>();
- while (rs.next()) {
- Book book = new Book(rs.getInt("id") , rs.getString("name") ,
- rs.getDouble("price") , rs.getInt("count") , rs.getString("author"));
- list.add(book);
- }
- request.setAttribute("list", list);
- rs.close();
- statement.close();
- connection.close();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- //将请求转发到book_list.jsp
- request.getRequestDispatcher("book_list.jsp").forward(request, response);
- }
- }
创建book_list.jsp页面:
- <body>
- <table align="center" width="450" border="2">
- <tr>
- <td align="center" colspan="2"><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>
- <%
- //获取图书信息集合
- ArrayList<Book> list = (ArrayList<Book>)request.getAttribute("list");
- if(list == null || list.size() < 1)
- out.print("没有数据!");
- else{
- for(Book book : list){
- %>
- <tr align="center">
- <td><%= book.getId() %></td>
- <td><%= book.getName() %></td>
- <td><%= book.getPrice() %></td>
- <td><%= book.getCount() %></td>
- <td><%= book.getAuthor() %></td>
- </tr>
- <%
- }
- }
- %>
- </table>
- </body>
创建index.jsp页面:
- <body>
- <a href="FindServlet">查看所有图书</a>
- </body>
3、修改数据
修改数据的方法,除了SQL语句外其它都与添加数据相同,其SQL语句为:
UPDATE 表 SET 属性=xxx WHERE 属性=xxx
在实际开发中,通常都是由程序传递SQL语句中的参数,所以修改数据也需要使用PreparedStatement对象进行操作。
4、删除数据
修改数据的方法,除了SQL语句外其它都与添加数据相同,其SQL语句为:
DELETE FROM 表 WHERE 属性=xxx
在实际开发中,通常都是由程序传递SQL语句中的参数,所以删除数据也需要使用PreparedStatement对象进行操作。
5、批处理
JDBC中批处理的原理是将批量的SQL语句一次性发送到数据库中进行执行,从而解决多次与数据库连接所产生的速度瓶颈。下面是一个使用批处理添加数据的方法:
- public int saveBatch() {
- int row = 0;
- try {
- String sql = "INSERT INTO tb_books(id,name,price,count,anthor) VALUES(?,?,?,?,?)";
- PreparedStatement ps = connection.prepareStatement(sql);
- for (int i = 0; i < 10; i++) {
- ps.setInt(1, i);
- ps.setString(2, "书" + i);
- ps.setDouble(3, i*10.5);
- ps.setInt(4, i*20);
- ps.setString(5, "作者" + i);
- //添加批处理命令
- ps.addBatch();
- }
- //执行批处理操作并返回计数组成的数据
- int[] rows = ps.executeBatch();
- row = rows.length;
- ps.close();
- connection.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return row;
- }
6、调用存储过程
在JDBC API中提供了调用存储过程的方法,通过CallableStatement对象进行操作。CallableStatement对象位于java.sql包中,它继承于Statement对象,主要用于执行数据库中定义的存储过程,其调用方法如下:
{call <procedure-name>[(<arg1>,<arg2>,…)]}
其中arg1、arg2为存储过程中的参数,如果存储过程中需要传递参数,可以对其进行赋值操作。
存储过程是一个SQL语句和可选控制流语句的预编译集合。编译完成后存放在数据库中,这样就省去了执行SQL语句时对SQL语句进行编译所花费的时间。在执行存储过程时只需要将参数传递到数据库中,而不需要将整条SQL语句都提交给数据库,从而减少了网络传输的流量,提高了程序的运行速度。
各种数据库创建存储过程的方法并非一致,下面以SQL Server 2012调用存储过程的方法做讲解,其他数据库请参考其帮助文档:
首先打开 SQL Server Management Studio,依次打开实例、数据库、你的数据库、可编程性、存储过程,右键存储过程选择新建存储过程。这是会弹出文本窗口,内有许多文本,鉴于初学者,将文本内容全部删掉,以下面的代码代替之:
- USE [test]
- GO
- CREATE PROCEDURE findAllBooks
- AS
- BEGIN
- SELECT * from tb_books
- END
- GO
在程序中关键代码如下:
- CallableStatement cs = connection.prepareCall("{call findAllBook()}");
- ResultSet resultSet = cs.executeQuery();
-
前面介绍了JDBC技术和JDBC API及API的使用示例,下面详细介绍JDBC在Web中的应用。
四、JDBC在Java Web中的应用
通常情况下,Web程序操作数据库都是通过JDBC实现,即使目前数据库方面的开源框架有许多,但其底层实现都离不开JDBC API。
1、开发模式
在Java Web开发中使用JDBC,应遵循MVC的设计思想,从而使Web程序拥有一定的健壮性、可扩展性。每个Java Web程序员都应该深谙MVC的设计思想,下面对其简单介绍。
MVC(Model-View-Controller)是一种设计理念,该理念将软件分成3层结构,分别为模型层、视图层和控制层。
- 模型层泛指程序中的业务逻辑,用于处理真正的业务操作;
- 视图层是指程序与用户交互的界面,对用户呈现出视图,但不包括业务逻辑;
- 控制层是对用户各种请求的分发处理,将制定的请求分配给制定的业务逻辑进行处理。
JDBC应用于Java Web开发中,处于MVC中的模型层位置,如图所示:
客户端通过JSP页面与程序进行交互,对于数据的增、删、改、查请求由Servlet对其进行分发处理,如Servlet接收到添加数据请求,就会分发给增加数据的JavaBean对象,而真正的数据库操作是通过JDBC封装的JavaBean进行实现。
2、分页查询
分页查询用于在数据库量非常大,不适合将所有数据显示在一页中的情况。通过JDBC实现分页查询的方法有很多种,而且不同的数据库机制也提供了不同的分页方式,在这里介绍两种非常典型的分页方法:
1)、通过ResultSet的光标实现分页
ResultSet为查询结果集对象,在该对象中有一个“光标”的概念(可以参考第一篇中的JDBC API介绍),光标通过上下移动定位查询结果集中的行,从而获取数据。所以通过移动“光标”,可以设置ResultSet对象中记录的起始位置和结束为止,来实现数据的分页显示。
2)、通过数据库机制进行分页
很多数据库自身都提供了分页机制,如SQL Server中提供的top关键字,MySQL中提供的limit关键字,他们都可以设置数据返回的记录数。
下面是MYSQL数据库提供的分页机制,关键代码如下:
- String sql = "SELECT * FROM tb_book ORDER BY id DESC LIMIT ?,?";
- PreparedStatement ps = connection.prepareStatement(sql);
- ps.setInt(1, (page - 1)*Book.PAGE_SIZE);//page为页数
- ps.setInt(2, Book.PAGE_SIZE);
- ResultSet rs = ps.executeQuery();
Limit关键字能够控制查询数据结果集起始位置及返回记录的数量,它的两个参数分别用于指定查询记录的其实位置和所返回的记录数。而返回总记录数可以使用以下方法:
- int count = 0;
- String sql = "SELECT count(*) FROM tb_book";
- Statement statement = connection.createStatement();
- ResultSet resultSet = statement.executeQuery(sql);
- if (resultSet.next())
- count = resultSet.getInt(1);
下面是一个使用MySQL数据库实现分页查询的源码,可以参考下: