1. 程式人生 > >dljd_(018-020)_jdbc中mysql的事務管理

dljd_(018-020)_jdbc中mysql的事務管理

使用 恢復 原子 cti rep 圖片 close insert val

一、通過debug模式驗證jdbc中mysql管理事務的默認方式(自動提交)示例

package edu.aeon.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import edu.aeon.aeonutils.AeonJdbcUtils;
/**
 * [說明]:驗證jdbc中mysql管理事務的默認方式(自動提交)
 * @author aeon
 */
public class TestJDBC {
    
/** * 使用jdbc中mysql管理事務的默認方式(自動提交)驗證 */ public static void jdbc_insert(){ Connection connection=null; PreparedStatement preparedStatement = null; try { connection = AeonJdbcUtils.getMySqlConnection(); String sql="insert into user(userid,username,userpw) values (?,?,?)";
//第一條數據 //將sql語句進行預編譯然後保存到preparedStatement對象中 preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1, 10006); preparedStatement.setString(2, "aeon6"); preparedStatement.setString(3, "aeon6"); int rowCount = preparedStatement.executeUpdate(); System.out.println(rowCount
+"條數據被插入!"); //第二條數據 preparedStatement.setInt(1, 10007); preparedStatement.setString(2, "aeon7"); preparedStatement.setString(3, "aeon7"); rowCount = preparedStatement.executeUpdate(); System.out.println(rowCount+"條數據被插入!"); //第三條數據 preparedStatement.setInt(1, 10008); preparedStatement.setString(2, "aeon8"); preparedStatement.setString(3, "aeon8"); rowCount = preparedStatement.executeUpdate(); System.out.println(rowCount+"條數據被插入!"); //第四條 preparedStatement.setInt(1, 10006);//模擬錯誤 preparedStatement.setString(2, "aeon9"); preparedStatement.setString(3, "aeon9"); rowCount = preparedStatement.executeUpdate(); System.out.println(rowCount+"條數據被插入!"); //第五條數據 preparedStatement.setInt(1, 100010); preparedStatement.setString(2, "aeon10"); preparedStatement.setString(3, "aeon10"); rowCount = preparedStatement.executeUpdate(); System.out.println(rowCount+"條數據被插入!"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { AeonJdbcUtils.closeDB(null, preparedStatement, connection); } } public static void main(String[] args) { jdbc_insert(); } }

執行結果截圖:

  技術分享圖片

  數據庫截圖:

  技術分享圖片

  當我們在debug模式下執行完第一條數據後執行第二條數據前,我們可以看到第一條數據已經被插入到數據庫當中了、因此可以判斷出第一條事務被默認的提交到數據庫當中了。

  當在執行第四條語句的時候出了主鍵沖突作用、但是這個錯誤不會影響到前三條數據的正常執行(這就是鑒於事物的原子行)

  當第四條語句(事務)出錯後,那麽第五條數據是不會被正常執行的!

二、這種jdbc中mysql的默認提交事務在某些場合下並不使用

  比如說進行轉賬操作時、a 卡向b卡轉賬 100萬元

  當程序跑到a卡裏面的錢被扣了100萬元後、b卡裏面的錢沒有被加前、突然停電了、那麽這種情況就是a持卡人說我向你轉了100萬、而b持卡人說我根本沒有收到100萬、我們怎麽在程序裏面避免這種現象的發生?(將a卡扣錢事務和b卡的加錢事務放到一個事務當中)、當扣錢和加錢同時執行成功,則本次轉賬成功、否則當次事務中的任何一個操作出現異常的情況下視為本事務執行失敗,恢復到轉賬前。

  2.1實現(在事務執行之前將事務的提交方式改為手動提交)

  此處由於本人比較小懶、就不模擬轉賬操作了(設計到轉賬還要從新見測試表)、我們拿之前的例子說明即可(因為原理一樣):

  

package edu.aeon.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import edu.aeon.aeonutils.AeonJdbcUtils;
/**
 * [說明]:修改jdbc中事務的提交方式
 * @author aeon
 */
public class TestJDBC {
    /**
     * @throws SQLException 
     */
    public static void jdbc_insert() throws SQLException{
        Connection connection=null;
        PreparedStatement preparedStatement = null;
        try {
            connection = AeonJdbcUtils.getMySqlConnection();
            //設置事務的提交方式為手動提交
            connection.setAutoCommit(false);
            String sql="insert into user(userid,username,userpw) values (?,?,?)";
            //第一條數據
            //將sql語句進行預編譯然後保存到preparedStatement對象中
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 10006);
            preparedStatement.setString(2, "aeon6");
            preparedStatement.setString(3, "aeon6");
            int rowCount = preparedStatement.executeUpdate();
            //第二條數據
            preparedStatement.setInt(1, 10007);
            preparedStatement.setString(2, "aeon7");
            preparedStatement.setString(3, "aeon7");
            rowCount = preparedStatement.executeUpdate();
            //第三條數據
            preparedStatement.setInt(1, 10008);
            preparedStatement.setString(2, "aeon8");
            preparedStatement.setString(3, "aeon8");
            rowCount = preparedStatement.executeUpdate();
            //第四條
            preparedStatement.setInt(1, 10006);//模擬錯誤
            preparedStatement.setString(2, "aeon9");
            preparedStatement.setString(3, "aeon9");
            rowCount = preparedStatement.executeUpdate();
            //第五條數據
            preparedStatement.setInt(1, 100010);
            preparedStatement.setString(2, "aeon10");
            preparedStatement.setString(3, "aeon10");
            rowCount = preparedStatement.executeUpdate();
            //提交事務
            connection.commit();
            System.out.println("本次操作成功!");
            
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        } catch (SQLException e) {
            connection.rollback();
            System.out.println("本次操作失敗!");
            e.printStackTrace();
        }finally {
            AeonJdbcUtils.closeDB(null, preparedStatement, connection);
        }
    }
    public static void main(String[] args) {
        try {
            jdbc_insert();
        } catch (SQLException e) {
            System.out.println("本次操作失敗!");
            e.printStackTrace();
        }
    }
}

執行結果截圖:

  技術分享圖片  

數據庫截圖:

  技術分享圖片

  當我們將這個模擬異常去掉後、執行結果截圖:

  技術分享圖片

  再去看看數據庫:

   技術分享圖片

  可見數據已經進來了!

  當使用jdbc修改了事務的提交方式為手動提交後、那麽接下來執行的所有操作都將被放入到一個事務中了(commit()、rollback()之前的操作都將是一個事務)、當遇到commit()時將當前事務提交到數據庫中、當遇到rollback()時,當前事務中的所有操作都將被撤回到事務執行之前(又恢復jdbc提交事務的默認方式)。

  

dljd_(018-020)_jdbc中mysql的事務管理