Java事务处理-JDBC事务例子

买书的例子 程序应该将图书数量的操作和更新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 在交易的业务逻辑中进行判断 当用户的账户金额小于购买金额的时候 就取消所作的改变


原文地址:http://blog.chinaunix.net/uid-26284395-id-3037410.html

你可能感兴趣的:(事务)