JDBC03 利用JDBC實現事務提交與回滾【調用Connection中的方法實現事務管理】

来源:http://www.cnblogs.com/NeverCtrl-C/archive/2017/07/07/7133147.html
-Advertisement-
Play Games

目錄 1 Connection中的重用方法 2 JDBC事務管理經典案例 1 Connection類中常用的方法回顧 1.1 Statement createStatement() throws SQLException; 創建一個Statement實例(即:創建一個SQL執行對象) 1.2 Pre ...


 目錄

  1 Connection中的重用方法

  2 JDBC事務管理經典案例

1 Connection類中常用的方法回顧

  1.1 Statement createStatement() throws SQLException;

    創建一個Statement實例(即:創建一個SQL執行對象)

  1.2 PreparedStatement prepareStatement(String sql) throws SQLException;

    創建一個PreparedStatement對象(即:創建一個預編譯SQL執行對象)

  1.3 void setAutoCommit(boolean autoCommit) throws SQLException;

    設置事務的自動提交(false為關閉自動提交,true為啟動自動提交)

  1.4 void commit() throws SQLException;

    手動提交事務

  1.5 void rollback() throws SQLException;

    手動回滾事務

 

2 需要用到事務回滾的經典案例:銀行轉賬案例

  轉出和轉入是一個事務,如果轉出成功但是轉入失敗的會就需要進行事務回滾,否則就出出現轉出者餘額減少但是轉入者餘額沒有增加

  註意:事務的提交與回滾是通過Connection提供的方法來調用的;本質上事務還是依賴資料庫的實現;Connection的方法實質上也是調用了資料庫事務機制.

  2.1 不使用事務控制的轉賬業務

    缺點:如果轉入成功,但是轉入失敗的話,會造成轉出者餘額減少,但是轉入者餘額不變

    項目結構圖

      

 1 package cn.xiangxu.entity;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.util.Scanner;
 6 
 7 import cn.xiangxu.tools.DBUtil;
 8 
 9 public class Test {
10     public static void main(String[] args) {
11         Scanner scanner = new Scanner(System.in);
12         System.out.println("請輸入轉出用戶名:");
13         String outName = scanner.nextLine();
14         System.out.println("請輸入需要轉出的資金額度:");
15         Double money = Double.parseDouble(scanner.nextLine());
16         System.out.println("請輸入轉入用戶名:");
17         String inName = scanner.nextLine();
18         System.out.println("轉出賬戶為:" + outName + "轉出金額為:" + money + "轉入賬戶為:" + inName);
19         
20         
21         Connection conn = null;
22         try {
23             conn = DBUtil.getConnection(); // 實例化連接對象
24             
25 //            conn.setAutoCommit(false); // 關閉自動提交事務功能
26             
27             String sql = "UPDATE client "
28                     + "SET account = account - ? " 
29                     + "WHERE name = ? ";
30             PreparedStatement ps = conn.prepareStatement(sql);
31             ps.setDouble(1, money);
32             ps.setString(2, outName);
33             Integer rs = ps.executeUpdate();
34             if(rs > 0) {
35                 System.out.println("轉出成功");
36             } else {
37                 System.out.println("轉出失敗");
38                 return; // 轉出失敗跳出函數,不再執行下麵的語句;但是finally中的語句還是會執行的,因為就算天塌下來finally中的語句都會執行
39             }
40             
41             System.out.println("======分割線=======");
42             
43             String sql_in = "UPDATE client "
44                     + "SET account = account + ? " 
45                     + "WHERE name = ? ";
46             PreparedStatement ps_in = conn.prepareStatement(sql_in);
47             ps_in.setDouble(1, money);
48             ps_in.setString(2, inName);
49             Integer judge_in = ps_in.executeUpdate();
50             if(judge_in > 0) {
51                 System.out.println("轉入成功");
52 //                conn.commit(); // 轉出、轉入都成功就提交事務
53             } else {
54                 System.out.println("轉入失敗");
55 //                conn.rollback(); // 轉出成功、轉入失敗就回滾事務
56             }
57             
58 //            conn.setAutoCommit(true); // 打開自動提交事務
59             
60         } catch (Exception e) {
61             // TODO Auto-generated catch block
62             e.printStackTrace();
63         } finally {
64             System.out.println("我是finally中的語句喲");
65             try {
66                 DBUtil.closeConnection();
67             } catch (Exception e) {
68                 // TODO Auto-generated catch block
69                 e.printStackTrace();
70             }
71         }
72     }
73 }
轉賬業務java源代碼
1 CREATE TABLE client  (
2     id INT (10)  PRIMARY KEY,
3     name VARCHAR (10),
4     pwd VARCHAR (10),
5     account INT (20)
6 );
SQL語句
 1 package cn.xiangxu.tools;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.sql.Connection;
 6 import java.sql.SQLException;
 7 import java.util.Properties;
 8 
 9 import org.apache.commons.dbcp.BasicDataSource;
10 
11 public class DBUtil {
12     /*
13      * ThreadLocal用於線程跨方法共用數據使用
14      * ThreadLocal內部有一個Map,  key為需要共用數據的線程本身,value就是其需要共用的數據
15      */
16     private static ThreadLocal<Connection> tl; // 聲明一個類似於倉庫的東西
17     private static BasicDataSource dataSource; // 聲明一個資料庫連接池對象
18     
19     // 靜態代碼塊,在類載入的時候執行,而且只執行一次
20     static {
21         tl = new ThreadLocal<Connection>(); // 實例化倉庫對象
22         dataSource = new BasicDataSource(); // 實例資料庫連接池對象
23 
24         Properties prop = new Properties(); // 創建一個Properties對象用(該對象可以用來載入配置文件中的屬性列表)
25         InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config/mysql.properties"); // 讀取配置文件信息
26         try {
27             prop.load(is); // 載入配置文件中的屬性列表
28             
29             String driverClassName = prop.getProperty("driverClassName"); // 獲取屬性信息
30             String url = prop.getProperty("url");
31             String username = prop.getProperty("username");
32             String password = prop.getProperty("password");
33             Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));
34             Integer maxWait = Integer.parseInt(prop.getProperty("maxWait"));
35             
36             dataSource.setDriverClassName(driverClassName); // 初始化資料庫連接池(即:配置資料庫連接池的先關參數)
37             dataSource.setUrl(url);
38             dataSource.setUsername(username);
39             dataSource.setPassword(password);
40             dataSource.setMaxActive(maxActive);
41             dataSource.setMaxWait(maxWait);
42             
43             is.close(); // 關閉輸入流,釋放資源
44         } catch (IOException e) {
45             // TODO Auto-generated catch block
46             e.printStackTrace();
47         } 
48         
49     }
50     
51     /**
52      * 創建連接對象(註意:靜態方法可以直接通過類名來調用)
53      * @return 連接對象
54      * @throws Exception
55      */
56     public static Connection getConnection() throws Exception { 
57         try {
58             Connection conn = dataSource.getConnection(); // 創建連接對象(利用資料庫連接池進行創建)
59             tl.set(conn); // 將連接對象放到倉庫中
60             return conn; 
61         } catch (Exception e) {
62             // TODO Auto-generated catch block
63             e.printStackTrace();
64             throw e;
65         }
66     }
67     
68     /**
69      * 關閉連接對象(註意:靜態方法可以通過類名直接調用)
70      * @throws Exception
71      */
72     public static void closeConnection() throws Exception {
73         Connection conn = tl.get(); // 從倉庫中取出連接對象
74         tl.remove(); // 清空倉庫
75         if(conn != null) { // 判斷連接對象是否釋放資源
76             try {
77                 conn.close();
78             } catch (Exception e) {
79                 // TODO Auto-generated catch block
80                 e.printStackTrace();
81                 throw e;
82             }
83         }
84     }
85 
86 }
資料庫連接池的java源代碼
1 # zhe shi zhu shi , yi ban bu yong zhong wen 
2 # deng hao liang bian mei you kong ge, mo wei mei you fen hao
3 # hou mian bu neng you kong ge
4 driverClassName=com.mysql.jdbc.Driver
5 url=jdbc:mysql://localhost:3306/test
6 username=root
7 password=182838
8 maxActive=100
9 maxWait=3000
資料庫信息文件
 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 2   <modelVersion>4.0.0</modelVersion>
 3   <groupId>cn.xiangxu</groupId>
 4   <artifactId>testJDBC</artifactId>
 5   <version>0.0.1-SNAPSHOT</version>
 6   <dependencies>
 7       <dependency>
 8           <groupId>mysql</groupId>
 9           <artifactId>mysql-connector-java</artifactId>
10           <version>5.1.37</version>
11       </dependency>
12       <dependency>
13           <groupId>junit</groupId>
14           <artifactId>junit</artifactId>
15           <version>4.12</version>
16       </dependency>
17       <dependency>
18           <groupId>commons-dbcp</groupId>
19           <artifactId>commons-dbcp</artifactId>
20           <version>1.4</version>
21       </dependency>
22   </dependencies>
23 </project>
maven依賴文件

  2.2 利用事務控制的轉賬業務

 1 package cn.xiangxu.entity;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.SQLException;
 6 import java.util.Scanner;
 7 
 8 import cn.xiangxu.tools.DBUtil;
 9 
10 public class Test {
11     public static void main(String[] args) {
12         Scanner scanner = new Scanner(System.in);
13         System.out.println("請輸入轉出用戶名:");
14         String outName = scanner.nextLine();
15         System.out.println("請輸入需要轉出的資金額度:");
16         Double money = Double.parseDouble(scanner.nextLine());
17         System.out.println("請輸入轉入用戶名:");
18         String inName = scanner.nextLine();
19         System.out.println("轉出賬戶為:" + outName + "轉出金額為:" + money + "轉入賬戶為:" + inName);
20         
21         
22         Connection conn = null;
23         try {
24             conn = DBUtil.getConnection(); // 實例化連接對象
25             
26             conn.setAutoCommit(false); // 關閉自動提交事務功能
27             
28             String sql = "UPDATE client "
29                     + "SET account = account - ? " 
30                     + "WHERE name = ? ";
31             PreparedStatement ps = conn.prepareStatement(sql);
32             ps.setDouble(1, money);
33             ps.setString(2, outName);
34             Integer rs = ps.executeUpdate();
35             if(rs > 0) {
36                 System.out.println("轉出成功");
37             } else {
38                 System.out.println("轉出失敗");
39                 return; // 轉出失敗跳出函數,不再執行下麵的語句;但是finally中的語句還是會執行的,因為就算天塌下來finally中的語句都會執行
40             }
41             
42             System.out.println("======分割線=======");
43             
44             String sql_in = "UPDATE client "
45                     + "SET account = account + ? " 
46                     + "WHERE name = ? ";
47             PreparedStatement ps_in = conn.prepareStatement(sql_in);
48             ps_in.setDouble(1, money);
49             ps_in.setString(2, inName);
50             Integer judge_in = ps_in.executeUpdate();
51             if(judge_in > 0) {
52                 System.out.println("轉入成功");
53                 conn.commit(); // 轉出、轉入都成功就提交事務
54             } else {
55                 System.out.println("轉入失敗");
56                 conn.rollback(); // 轉出成功、轉入失敗就回滾事務
57             }
58             
59             conn.setAutoCommit(true); // 打開自動提交事務
60             
61         } catch (Exception e) {
62             // TODO Auto-generated catch block
63             try {
64                 conn.rollback(); // 捕獲到異常後也需要進行事務回滾
65             } catch (SQLException e1) {
66                 // TODO Auto-generated catch block
67                 e1.printStackTrace();
68             } 
69             e.printStackTrace();
70         } finally {
71             System.out.println("我是finally中的語句喲");
72             try {
73                 DBUtil.closeConnection();
74             } catch (Exception e) {
75                 // TODO Auto-generated catch block
76                 e.printStackTrace();
77             }
78         }
79     }
80 }
轉賬業務的java源代碼

  2.3 將關閉自動提交功能、手動提交功能、手動回滾功能封裝到一個類中

  1 package cn.xiangxu.tools;
  2 
  3 import java.io.IOException;
  4 import java.io.InputStream;
  5 import java.sql.Connection;
  6 import java.sql.SQLException;
  7 import java.util.Properties;
  8 
  9 import org.apache.commons.dbcp.BasicDataSource;
 10 
 11 public class DBUtil {
 12     /*
 13      * ThreadLocal用於線程跨方法共用數據使用
 14      * ThreadLocal內部有一個Map,  key為需要共用數據的線程本身,value就是其需要共用的數據
 15      */
 16     private static ThreadLocal<Connection> tl; // 聲明一個類似於倉庫的東西
 17     private static BasicDataSource dataSource; // 聲明一個資料庫連接池對象
 18     
 19     // 靜態代碼塊,在類載入的時候執行,而且只執行一次
 20     static {
 21         tl = new ThreadLocal<Connection>(); // 實例化倉庫對象
 22         dataSource = new BasicDataSource(); // 實例資料庫連接池對象
 23 
 24         Properties prop = new Properties(); // 創建一個Properties對象用(該對象可以用來載入配置文件中的屬性列表)
 25         InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config/mysql.properties"); // 讀取配置文件信息
 26         try {
 27             prop.load(is); // 載入配置文件中的屬性列表
 28             
 29             String driverClassName = prop.getProperty("driverClassName"); // 獲取屬性信息
 30             String url = prop.getProperty("url");
 31             String username = prop.getProperty("username");
 32             String password = prop.getProperty("password");
 33             Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));
 34             Integer maxWait = Integer.parseInt(prop.getProperty("maxWait"));
 35             
 36             dataSource.setDriverClassName(driverClassName); // 初始化資料庫連接池(即:配置資料庫連接池的先關參數)
 37             dataSource.setUrl(url);
 38             dataSource.setUsername(username);
 39             dataSource.setPassword(password);
 40             dataSource.setMaxActive(maxActive);
 41             dataSource.setMaxWait(maxWait);
 42             
 43             is.close(); // 關閉輸入流,釋放資源
 44         } catch (IOException e) {
 45             // TODO Auto-generated catch block
 46             e.printStackTrace();
 47         } 
 48         
 49     }
 50     
 51     /**
 52      * 創建連接對象(註意:靜態方法可以直接通過類名來調用)
 53      * @return 連接對象
 54      * @throws Exception
 55      */
 56     public static Connection getConnection() throws Exception { 
 57         try {
 58             Connection conn = dataSource.getConnection(); // 創建連接對象(利用資料庫連接池進行創建)
 59             tl.set(conn); // 將連接對象放到倉庫中
 60             return conn; 
 61         } catch (Exception e) {
 62             // TODO Auto-generated catch block
 63             e.printStackTrace();
 64             throw e;
 65         }
 66     }
 67     
 68     /**
 69      * 關閉連接對象(註意:靜態方法可以通過類名直接調用)
 70      * @throws Exception
 71      */
 72     public static void closeConnection() throws Exception {
 73         Connection conn = tl.get(); // 從倉庫中取出連接對象
 74         tl.remove(); // 清空倉庫
 75         if(conn != null) { // 判斷連接對象是否釋放資源
 76             try {
 77                 conn.close();
 78             } catch (Exception e) {
 79                 // TODO Auto-generated catch block
 80                 e.printStackTrace();
 81                 throw e;
 82             }
 83         }
 84     }
 85     
 86     /**
 87      * 在執行SQL語句前關閉JDBC的自動提交事務功能
 88      * @throws SQLException
 89      */
 90     public static void tansBegin() throws SQLException {
 91         try {
 92             tl.get().setAutoCommit(false); // 從倉庫中獲取連接對象並調用setAutoCommit來關閉自動提交事務功能
 93         } catch(SQLException e) {
 94             e.printStackTrace();
 95             throw e;
 96         }
 97     }
 98     
 99     /**
100      * 手動回滾功能
101      * @throws SQLException
102      */
103     public static void transBack() throws SQLException {
104         tl.get().rollback(); // 從倉庫中獲取連接對象並調用rollback來實現事務回滾操作
105         tl.get().setAutoCommit(true); // 回滾啟動事務自動提交功能
106     }
107     
108     /**
109      * 手動提交功能
110      * @throws SQLException
111      */
112     public static void transCommit() throws SQLException {
113         tl.get().commit(); // 從倉庫中獲取連接對象並調用commit來實現事務提交操作
114         tl.get().setAutoCommit(true); // 提交後啟動事務自動提交功能
115     }
116 
117 }
DBUtil
 1 package cn.xiangxu.entity;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.SQLException;
 6 import java.util.Scanner;
 7 
 8 import cn.xiangxu.tools.DBUtil;
 9 
10 public class Test {
11     public static void main(String[] args) {
12         Scanner scanner = new Scanner(System.in);
13         System.out.println("請輸入轉出用戶名:");
14         String outName = scanner.nextLine();
15         System.out.println("請輸入需要轉出的資金額度:");
16         Double money = Double.parseDouble(scanner.nextLine());
17         System.out.println("請輸入轉入用戶名:");
18         String inName = scanner.nextLine();
19         System.out.println("轉出賬戶為:" + outName + "轉出金額為:" + money + "轉入賬戶為:" + inName);
20         
21         
22         Connection conn = null;
23         try {
24             conn = DBUtil.getConnection(); // 實例化連接對象
25             
26             DBUtil.tansBegin(); // 關閉自動提交事務功能
27             
28             String sql = "UPDATE client "
29                     + "SET account = account - ? " 
30                     + "WHERE name = ? ";
31             PreparedStatement ps = conn.prepareStatement(sql);
32             ps.setDouble(1, money);
33             ps.setString(2, outName);
34             Integer rs = ps.executeUpdate();
35             if(rs > 0) {
36                 System.out.println("轉出成功");
37             } else {
38               

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • include包含頭文件的語句中,雙引號和尖括弧的區別 #include <>格式:引用標準庫頭文件,編譯器從標準庫目錄開始搜索 #incluce ""格式:引用非標準庫的頭文件,編譯器從用戶的工作目錄開始搜索 預處理器發現 #include 指令後,就會尋找後跟的文件名並把這個文件的內容包含到當前 ...
  • 一、Spring與JDBC模板 1、搭建環境 2、數據源的配置 3、從屬性文件讀取資料庫連接信息 4、配置JDBC模板 5、DAO實現類繼承JdbcDaoSupport類 6、對資料庫的增刪改操作 7、對資料庫的查詢操作 二、Spring的事務管理 ...
  • 學習Java以來第一篇隨筆,寫一寫初學Socket編程中容易碰到的一個問題。照著教材上的例子敲了下麵這段單線程網路通信的代碼: 這段代碼應該是初學Socket編程都要敲的一段,邏輯還是比較簡單的。但是一開始我的TCPServer類和TCPClient類運行後,在控制台無法列印出兩者通過流交互的信息, ...
  • 作者: kent鵬 轉載請註明出處: http://www.cnblogs.com/xieyupeng/p/7129152.html 該項目在SSH三大框架整合基礎上進行開發:http://www.cnblogs.com/xieyupeng/p/7108141.html 一、客戶列表 1.分析 2. ...
  • 一、用途 我們需要將記憶體中的數據進行序列化,即寫入文件中時,寫入的類型只能是字元串或者二進位類型。但是如果我們想要將複雜一些的數據類型,如:列表、字典或者函數之類的同樣進行序列化,我們就要用到 json或者pickle。 二、json序列化 1、dumps序列化和loads反序列化 dumps把數據 ...
  • 3、一個整數,它加上100後是一個完全平方數,再加上168又是一個完全平方數,請問該數是多少? 方法一: 方法二:看了別人的思路,我覺得我儼然是個弱智。 4、輸入某年某月某日,判斷這一天是這一年的第幾天? 方法一: 方法二: 5、輸入三個整數x,y,z,請把這三個數由小到大輸出。 方法一 方法二: ...
  • 之前一篇Python 封裝DBUtils 和pymysql 中寫過一個basedao.py,最近幾天又重新整理了下思緒,優化了下 basedao.py,目前支持的方法還不多,後續會進行改進、添加。 主要功能: 1.查詢單個對象: 所需參數:表名,過濾條件 2.查詢多個對象: 所需參數:表名,過濾條件 ...
  • 適用情境:serialize()返回字元串,此字元串包含了表示value的位元組流,可以存儲於任何地方。這有利於存儲或傳遞 PHP 的值,同時不丟失其類型和結構。比較有用的地方就是將數據存入資料庫或記錄在文件中的時候 serialize()可處理處資源類型外所有的類型,也可以序列化對象 <?php $ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...