免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1031 | 回复: 0
打印 上一主题 下一主题

JDBC中的事务处理学习笔记 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-03-16 12:38 |只看该作者 |倒序浏览
              事务处理保证所有的事务都作为一个工作单元来执行,即使出现了硬件故障或系统失灵,都不能改变这种执行方式.当在一个事务中执行多个操作时,要么所有的操作都被提交(commit),要么整个事务回滚(rollback)到最初状态.
            当一个连接被创建时,默认情况下是设置为自动提交事务,这意味着每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,也就不能回滚了.为了将所个SQL语句作为一个事务执行,可以调用Connection对象的setAutoCommit()方法,传入false来取消自动提交事务,然后在所有的SQL语句成功执行后,调用Connection对象的commit()方法提交事务,或者在执行出错时,调用Connection对象的rollback()方法来回滚事务

           下面这个例子中,用户选定购买的图书和数量后,提交订单,程序把更新bookinfo表中的图书数量的操作和更新account表中的余额的操作作为一个事务处理,只有在两个操作都完成的情况下,才提交事务,否则,回滚事务.

1, 编写buy.html文件


    购买图书
    购买《MySQL数据库编程》
   
       用户名  :
       购买数量:
       重填">
       购买">
   





2, 编写TradeServlet:
    TradeServlet负责完成用户购买图书的交易操作
   


package cn.apache.pl;

import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class TradeServlet extends HttpServlet
{
    private String url;
    private String user;
    private String password;
   
    public void init() throws ServletException
    {
       ServletContext sc = getServletContext();
      
       //从web.xml文件中的中获取以下参数值
       String driverClass  = sc.getInitParameter("driverClass");
       url = sc.getInitParameter("url");
       user = sc.getInitParameter("user");
       password = sc.getInitParameter("password");
      
       try
       {
           Class.forName(driverClass);
       }catch(ClassNotFoundException ce)
       {
           throw new UnavailableException("数据库驱动加载失败");
       }
    }
   
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
       throws IOException, ServletException
    {
       Connection conn = null;
       Statement stmt = null;
       PreparedStatement pstmt = null;
       ResultSet rs = null;
      
       //设置响应页面的MIME类型及字符编码
       resp.setContentType("text/html; charset=gb2312");
       PrintWriter out = resp.getWriter();
      
       //设置请求页面的字符编码
       req.setCharacterEncoding("GB2312");
      
       //从提交的表单中获取用户名和购买数量
       String userid = req.getParameter("userid");
       String quantity = req.getParameter("quantity");
      
       if(null == userid || userid.equals("") || null == quantity || quantity.equals(""))
       {
           out.println("Error: 请输入用户名和购买数量!");
           out.close();
       }
       else
       {
           try
           {
              conn = DriverManager.getConnection(url, user, password);
              
              //调用Connection对象的setAutoCommit()方法,传入false参数取消自动提交事务
              conn.setAutoCommit(false);
              
              stmt = conn.createStatement();
              
              rs = stmt.executeQuery("select price,amount from bookinfo where id=3");
              /*
                  mysql> select price,amount from bookinfo where id=3;
                  +-------+--------+
                  | price | amount |
                  +-------+--------+
                  | 78.00 |     10 |
                  +-------+--------+
              */
              
              rs.next();
              
              //获取图书的价格和库存量
              float price = rs.getFloat(1);   //相当于rs.getFloat("price");
              int amount = rs.getInt(2);      //相当于rs.getInt("amount");
              
              int num = Integer.parseInt(quantity);
              
              //如果库存量大于用户购买的数量,则更新库存量
              if(amount >= num)
              {
                  pstmt = conn.prepareStatement("update bookinfo set amount=? where id=3");
                  pstmt.setInt(1,amount-num);
                  pstmt.executeUpdate();
              }
              else
              {
                  out.println("您所购买的图书库存量不足");
                  out.close();
                  return;
              }
              
              //查询该用户帐户余额
              pstmt = conn.prepareStatement("select balance from account where userid=?");
              /*
               *先将上面这句错写成"pstmt = ...where user=?");",执行servlet时Tomcat控制台报
               *java.sql.SQLException: Unknown column 'user' in 'where clause'
               *检查后,发现"where"子句中的"user"应该为"userid",
               *即buy.html文件中表单中的用户名为userid,而不是user
               */
               
              pstmt.setString(1,userid);
              rs = pstmt.executeQuery();
              
              rs.next();
              float balance = rs.getFloat(1);
              
              //总金额=图书价格*购买数量
              float totalPrice = price*num;
              
              //如果帐户余额大于总金额,则更新帐户余额(帐户余额-总金额)
              if(balance >= totalPrice)
              {
                  pstmt = conn.prepareStatement("Update account set balance=? where userid=?");
                  pstmt.setFloat(1,balance-totalPrice);
                  pstmt.setString(2,userid);
                  pstmt.executeUpdate();
              }
              //否则执行回滚,返回到购买前状态(图书数量未发生改变)
              else
              {
                  conn.rollback();
                  out.println("您的余额不足");
                  out.close();
                  return;
              }
               
              //提交事务,执行购买
              conn.commit();
              out.println("交易成功");
              out.close();
           }catch(SQLException se)
           {
              if(conn != null)
              {
                  try
                  {   
                     //如果购买过程中出现异常,则调用Connection对象的rollback()方法回滚所有改变
                     conn.rollback();
                  }catch(SQLException sex)
                  {
                     sex.printStackTrace();
                  }
              }
              se.printStackTrace();
           }finally
           {
              if(rs != null)                  //注意各对象的关闭顺序
              {
                  try
                  {
                     rs.close();
                  }catch(SQLException se)
                  {
                     se.printStackTrace();
                  }
                  rs = null;
              }
              
              if(stmt != null)
              {
                  try
                  {
                     stmt.close();
                  }catch(SQLException se)
                  {
                     se.printStackTrace();
                  }
                  stmt = null;
              }
              
              if(pstmt != null)
              {
                  try
                  {
                     pstmt.close();
                  }catch(SQLException se)
                  {
                     se.printStackTrace();
                  }
                  pstmt = null;
              }
              
              if(conn != null)
              {
                  try
                  {
                     conn.close();
                  }catch(SQLException se)
                  {
                     se.printStackTrace();
                  }
                  conn = null;
              }
           }   
       }
    }
   
    public void doPost(HttpServletRequest req, HttpServletResponse resp)
       throws IOException, ServletException
    {
       doGet(req, resp);
    }
}


3,部署Servlet:



    driverClass
    com.mysql.jdbc.Driver

    url
    jdbc:mysql://localhost:3306/bookstore

    user
    pl

    password
    123


    TradeServlet
    cn.apache.pl.TradeServlet

    TradeServlet
    /trade



4,运行GetDBInfoServlet
1,启动Tomact服务器,在浏览器中打开:
http://localhost:8080/ch08/buy.html

2,购买之前,我们先查看用户”彭磊”的帐户余额和《MySQL数据库编程》的库存量:

mysql> select * from account;
+--------+---------+
| userid | balance |
+--------+---------+
| 彭磊   |  588.00 |
| 徐璐   | 1000.50 |
+--------+---------+

mysql> select * from bookinfo;
+----+------------------+--------+----------------+--------------+-------+--------+------
| id | title            | author | bookconcern    | publish_date | price | amount | remark |
+----+------------------+--------+----------------+--------------+-------+--------+------
|  1 | JAVA从入门到精通 | 孙卫琴 | 电子工业出版社 | 2004-06-01   | 34.00 |     35 | NULL   |
|  2 | JSP应用开发详解  | 刘小华 | 清华大学出版社 | 2005-10-03   | 56.00 |     20 | NULL   |
|  3 | MySQL数据库编程  | 孙鑫   | 人民邮电出版社 | 2006-06-29   | 78.00 |     56 | NULL   |
|  4 | JAVA 国际认证    | SCJP   | 清华大学出版社 | 2005-02-03   | 46.00 |     55 | NULL   |
|  5 | JAVA编程思想     | Sun    | 电子工业出版社 | 2004-11-16   | 56.00 |     55 | NULL   |
+----+------------------+--------+----------------+--------------+-------+--------+------

3,输入用户名”彭磊”,购买数量”4”后,点”购买”,


页面显示: 交易成功

4,此时,再次查看用户”彭磊”的帐户余额和《MySQL数据库编程》的库存量:

mysql> select * from account;
+--------+---------+
| userid | balance |
+--------+---------+
| 彭磊   |  276.00 |
| 徐璐   | 1000.50 |
+--------+---------+

mysql> select * from bookinfo;
+----+------------------+--------+----------------+--------------+-------+--------+------
| id | title            | author | bookconcern    | publish_date | price | amount | remark |
+----+------------------+--------+----------------+--------------+-------+--------+------
|  1 | JAVA从入门到精通 | 孙卫琴 | 电子工业出版社 | 2004-06-01   | 34.00 |     35 | NULL   |
|  2 | JSP应用开发详解  | 刘小华 | 清华大学出版社 | 2005-10-03   | 56.00 |     20 | NULL   |
|  3 | MySQL数据库编程  | 孙鑫   | 人民邮电出版社 | 2006-06-29   | 78.00 |     52 | NULL   |
|  4 | JAVA 国际认证    | SCJP   | 清华大学出版社 | 2005-02-03   | 46.00 |     55 | NULL   |
|  5 | JAVA编程思想     | Sun    | 电子工业出版社 | 2004-11-16   | 56.00 |     55 | NULL   |
+----+------------------+--------+----------------+--------------+-------+--------+------

余额为276.00(购买前的余额588-图书价格78*购买数量4=276.00),
库存量为52(购买前库存量56-购买数量4=52),说明图书购买后,更新数据库成功!


5,异常测试:
1, 输入用户名”彭磊”,购买数量”412”后,点”购买”,

    页面输出: 您所购买的图书库存量不足

2,    仅仅输入用户名”彭磊”, 点”购买”,

       页面输出: Error: 请输入用户名和购买数量!

3,    输入用户名”彭磊”, 购买数量”52”后,点”购买”,

       页面输出:您的余额不足



仙尘(QQ:584059034)于08年3月16日




本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/63095/showart_497516.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP