JDBC中的事務-Transaction


事務-Transaction

某些情況下我們希望對數據庫的某一操作要么整體成功,要么整體失敗,經典的例子就是支付寶提現。例如我們發起了支付寶到銀行卡的100元提現申請,我們希望的結果是支付寶余額減少100元,銀行卡余額增加100元,而不是支付寶的100元被扣除,而銀行卡的100元卻沒收到。也就是說,要么100元從支付寶扣除的同時銀行卡也會多出一百元,要么這次提現失敗支付寶的100元還在,銀行卡也沒有收到錢。支付寶扣錢和銀行卡收錢,這兩件事要么都成功要么都失敗。

 

 

事物的ACID特性:

滿足ACID特性的操作,我們可以說它是一個事物。

  1. 原子性:該操作是最小邏輯單元整體,已經不可分隔。
  2. 一致性:要么所有都執行,要么所有都不執行。
  3. 隔離性:多個事務相互隔離,互不影響。
  4. 持久性:事物的執行結果永久生效。

 

 

對事物的控制:

在JDBC中可以調用Connection對象的setAutoCommit(false)這個接口,將commit()之前的所有操作都看成是一個事物。同時,如果事務執行過程中發生異常,可以調用rollback()接口進行回滾到事務開始之前的狀態。

 

 

示例代碼:

下面代碼演示了將cjk的100元轉賬到ly的賬戶上:

package org.lyk.main;

 

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import org.apache.commons.dbcp2.BasicDataSource;

 

 

 

public class Main

{

       public static String DBDRIVER = "com.mysql.jdbc.Driver";

       public static String DB_URL = "jdbc:mysql://localhost:3306/mldn";

       public static String USERNAME = "root";

       public static String PASSWORD = "admin";

       public static BasicDataSource bds = null;

 

       public static void main(String[] args)

       {

              dbPoolInit();

              transferAmount();

              System.out.println("///Done~~~");

       }

 

       public static void dbPoolInit()

       {

              bds = new BasicDataSource();

              bds.setDriverClassName(DBDRIVER);

              bds.setUrl(DB_URL);

              bds.setUsername(USERNAME);

              bds.setPassword(PASSWORD);

       }

      

       public static boolean transferAmount()

       {

              boolean retVal = true;

             

              String sql = "UPDATE user SET amount=? WHERE userid=?";

              Connection conn = null;

              PreparedStatement stmt = null;

              ResultSet rs = null;

             

             

              try

              {

                     conn = bds.getConnection();

                     conn.setAutoCommit(false);

                     stmt = conn.prepareStatement(sql);

                     stmt.setInt(1, 0);

                     stmt.setString(2, "cjk");

                     stmt.execute();

                     stmt.setInt(1, 100);

                     stmt.setString(2, "ly");

                     stmt.execute();

                     conn.commit();

              } catch (SQLException e)

              {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

                     try

                     {

                           conn.rollback();

                     } catch (SQLException e1)

                     {

                           // TODO Auto-generated catch block

                           e1.printStackTrace();

                     }

              }

              finally

              {

                     try

                     {

                           if(conn != null)

                                  conn.close();

                           if(stmt != null)

                                  stmt.close();

                           if(rs != null)

                                  rs.close();

                     }

                     catch(Exception e)

                     {

                           //ignore all exceptions when closing...

                     }

              }

             

             

              return retVal;

       }

}

 

 

事務斷點(Savepoint):

某些時候,我們對一個事物操作失敗,我們並不像回滾到最初狀態,而是回滾到事務開始后的某一個地方,這時我們可以使用斷點的方式讓事物回滾到指定的斷點(Savepoint)上.

示例代碼:

下面的代碼演示了如果cjk的100元轉賬到ly失敗的話,我們將這100元轉到cyx的賬戶上。(其中用手動跑出異常的方式模擬cjk到ly的轉賬失敗)

package org.lyk.main;

 

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Savepoint;

 

import org.apache.commons.dbcp2.BasicDataSource;

 

 

 

public class Main

{

      public static String DBDRIVER = "com.mysql.jdbc.Driver";

      public static String DB_URL = "jdbc:mysql://localhost:3306/mldn";

      public static String USERNAME = "root";

      public static String PASSWORD = "admin";

      public static BasicDataSource bds = null;

 

      public static void main(String[] args)

      {

            dbPoolInit();

            transferAmount();

            System.out.println("///Done~~~");

      }

 

      public static void dbPoolInit()

      {

            bds = new BasicDataSource();

            bds.setDriverClassName(DBDRIVER);

            bds.setUrl(DB_URL);

            bds.setUsername(USERNAME);

            bds.setPassword(PASSWORD);

      }

     

      public static boolean transferAmount()

      {

            boolean retVal = true;

           

            String sql = "UPDATE user SET amount=? WHERE userid=?";

            Connection conn = null;

            PreparedStatement stmt = null;

            ResultSet rs = null;

            Savepoint sp = null;

           

            try

            {

                  conn = bds.getConnection();

                 

                  conn.setAutoCommit(false);

                  stmt = conn.prepareStatement(sql);

                  stmt.setInt(1, 0);

                  stmt.setString(2, "cjk");

                  stmt.execute();

                  sp = conn.setSavepoint();

                 

                  stmt.setInt(1, 100);

                  stmt.setString(2, "ly");

                  stmt.execute();

                  throw new Exception();

            }

            catch (Exception e)

            {

                  e.printStackTrace();

                  try

                  {

                        conn.rollback(sp);

                        stmt.setInt(1, 100);

                        stmt.setString(2, "cyx");

                        stmt.execute();

                        conn.commit();

                  } catch (SQLException e1)

                  {

                        // TODO Auto-generated catch block

                        e1.printStackTrace();

                  }

            }

            finally

            {

                  try

                  {

                        if(conn != null)

                              conn.close();

                        if(stmt != null)

                              stmt.close();

                        if(rs != null)

                              rs.close();

                  }

                  catch(Exception e)

                  {

                        //ignore all exceptions when closing...

                  }

            }

           

           

            return retVal;

      }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM