买书的例子 程序应该将图书数量的操作和更新account用户余额的操作作为一个事务来处理,只有这两个操作都完成的情况下,才能提交事务,否则就回滚事务。
1 buy.html
- <html>
- <head>
- <title>购买图书</title>
- </head>
- <body>
- 购买《Servlet/JSP深入详解》<p>
- <form action="trade" method="post">
- 输入用户名: <input type="text" name="userid"><br>
- 输入购买数量:<input type="text" name="quantity"><p>
- <input type="reset" value="重填">
- <input type="submit" value="购买">
- </form>
- </body>
- </html>
2 TradeServlet.java
- package servlet;
- import javax.servlet.*;
- import java.io.*;
- import javax.servlet.http.*;
- import java.sql.*;
- public class TradeServlet extends HttpServlet
- {
- private String url;
- private String user;
- private String password;
-
- public void init() throws ServletException
- {
- ServletContext sc=getServletContext();
- 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 ServletException("加载数据库驱动失败!");
- }
- }
-
- public void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException,IOException
- {
- Connection conn=null;
- Statement stmt=null;
- PreparedStatement pstmt=null;
- ResultSet rs=null;
-
- 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("错误的请求参数");
- out.close();
- }
- else
- {
- try
- {
- conn=DriverManager.getConnection(url,user,password);
-
- conn.setAutoCommit(false);
- conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
-
- stmt=conn.createStatement();
- rs=stmt.executeQuery("select price,amount from bookinfo where id=3");
- rs.next();
- float price=rs.getFloat(1);
- int amount=rs.getInt(2);
-
- 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.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
- {
- conn.rollback();
- }
- catch(SQLException ***)
- {
- ***.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 ServletException,IOException
- {
- doGet(req,resp);
- }
- }
1 44、45行 调用请求对象的getParameter()方法得到用户名和购买图书的数量
2 60行 调用Connection对象的setAutoCommit()方法 传递 false参数 取消自动提交
3 61行 调用Connection对象的setTransactionIsolation()方法设置事务的隔离等级为Repeatable Read
4 99行 如果用户的余额不足 那么这次交易失败 调用Connection的rollback()方法,回到交易开始之前的状态,也就是回到bookinfo表中书的书目没发生改变的时候
注意: 如果在调用rollback()方法之前调用了commit()方法,那么只能回滚到上一次调用commit()方法之后所作的改变
5 104行 若果所有的操作都成功了 调用Connection对象的commit()方法提交事务,也就是向数据库提交所有的改变
6 在交易过程中,若果发生了异常 那么就在114行 调用Connection对象的rollback()方法回滚所有的改变
上面这个servlet用到了两种方式保证交易的正常进行
1 利用异常处理机制 一旦交易过程发生异常 就取消所有的改变
2 在交易的业务逻辑中进行判断 当用户的账户金额小于购买金额的时候 就取消所作的改变
阅读(24943) | 评论(0) | 转发(0) |