什么是Java事務
通常的觀念認為,事務僅與數據庫相關。
事務必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)的縮寫。事務的原子性表示事務執行過程中的任何失敗都將導致事務所做的任何修改失效。一致性表示當事務執行失敗時,所有被該事務影響的數據都應該恢復到事務執行前的狀態。隔離性表示在事務執行過程中對數據的修改,在事務提交之前對其他事務不可見。持久性表示已提交的數據在事務執行失敗時,數據的狀態都應該正確。
通俗的理解,事務是一組原子操作單元,從數據庫角度說,就是一組SQL指令,要么全部執行成功,若因為某個原因其中一條指令執行有錯誤,則撤銷先前執行過的所有指令。更簡答的說就是:要么全部執行成功,要么撤銷不執行。
既然事務的概念從數據庫而來,那Java事務是什么?之間有什么聯系?
實際上,一個Java應用系統,如果要操作數據庫,則通過JDBC來實現的。增加、修改、刪除都是通過相應方法間接來實現的,事務的控制也相應轉移到Java程序代碼中。因此,數據庫操作的事務習慣上就稱為Java事務。
事務的特性:
1) 原子性(atomicity):事務是數據庫的邏輯工作單位,而且是必須是原子工作單位,對于其數據修改,要么全部執行,要么全部不執行。
2) 一致性(consistency):事務在完成時,必須是所有的數據都保持一致狀態。在相關數據庫中,所有規則都必須應用于事務的修改,以保持所有數據的完整性。
3) 隔離性(isolation):一個事務的執行不能被其他事務所影響。
4) 持久性(durability):一個事務一旦提交,事物的操作便永久性的保存在DB中。即使此時再執行回滾操作也不能撤消所做的更改。
事務(Transaction):是并發控制的單元,是用戶定義的一個操作序列。這些操作要么都做,要么都不做,是一個不可分割的工作單位。通過事務,sql server 能將邏輯相關的一組操作綁定在一起,以便服務器 保持數據的完整性。事務通常是以begin transaction開始,以commit或rollback結束。Commint表示提交,即提交事務的所有操作。具體地說就是將事務中所有對數據的更新寫回到磁盤上的物理數據庫中去,事務正常結束。Rollback表示回滾,即在事務運行的過程中發生了某種故障,事務不能繼續進行,系統將事務中對數據庫的所有已完成的操作全部撤消,滾回到事務開始的狀態。
自動提交事務:每條單獨的語句都是一個事務。每個語句后都隱含一個commit。 (默認)
顯式事務:以begin transaction顯示開始,以commit或rollback結束。
隱式事務:當連接以隱式事務模式進行操作時,sql server數據庫引擎實例將在提交或回滾當前事務后自動啟動新事務。無須描述事物的開始,只需提交或回滾每個事務。但每個事務仍以commit或rollback顯式結束。連接將隱性事務模式設置為打開之后,當數據庫引擎實例首次執行下列任何語句時,都會自動啟動一個隱式事務:alter table,insert,create,open ,delete,revoke ,drop,select, fetch ,truncate table,grant,update在發出commit或rollback語句之前,該事務將一直保持有效。在第一個事務被提交或回滾之后,下次當連接執行以上任何語句時,數據庫引擎實例都將自動啟動一個新事務。該實例將不斷地生成隱性事務鏈,直到隱性事務模式關閉為止。
JDBC事務管理
在使用JDBC的時候, 如何進行事務的管理。直接看一下代碼
示例代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
/** * @Title: JDBCTrans.java * @Package com.oscar999.trans * @Description: * @author XM * @date Feb 14, 2017 4:38:27 PM * @version V1.0 */ package com.oscar999.trans; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * @author * */ public class JDBCTrans { public JDBCTrans() { } /** * * @param sHostName * @param sPortNumber * @param sSid * @param userName * @param password * @return * @throws SQLException */ public Connection getConnection(String sHostName, String sPortNumber, String sSid, String userName, String password) throws SQLException { Connection conn = null ; String url = getOraclURL(sHostName, sPortNumber, sSid); conn = DriverManager.getConnection(url,userName,password); return conn; } /** * * @param conn * @param sql * @throws SQLException */ public void add(Connection conn, String sql) throws SQLException { Statement stmt = null ; try { stmt = conn.createStatement(); stmt.execute(sql); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (stmt != null ) stmt.close(); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String sHostName = "" ; String sPortNumber = "" ; String sSid = "" ; String userName = "" ; String password = "" ; sHostName = "" ; sPortNumber = "" ; sSid = "" ; userName = "" ; password = "" ; try { Class.forName( "oracle.jdbc.driver.OracleDriver" ); } catch (ClassNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } JDBCTrans jdbcTrans = new JDBCTrans(); Connection conn = null ; try { conn = jdbcTrans.getConnection(sHostName, sPortNumber, sSid, userName, password); conn.setAutoCommit( false ); // can't insert, update //1. add SQL String addSQL = "insert into TEST_TABLE values('name1','value1')" ; jdbcTrans.add(conn,addSQL); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { /*if (conn != null) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } }*/ } } private String getOraclURL(String sHostName, String sPortNumber, String sSid) { String url = "jdbc:oracle:thin:@" + sHostName + ":" + sPortNumber + ":" + sSid; return url; } } |
針對以上代碼, 說明如下:
以上代碼有幾點說明的部分:
1. conn.setAutoCommit(false)
執行之后不提交事務。
對于Select沒有影響, 但對于Insert和Update的話, 沒有提交數據就不會被修改
2. conn.close();
關閉Connection的代碼有被Mark掉, 是想呈現conn.setAutoCommit(false)
的效果。
原因是在 Connection Close的時候會執行一次Commit.
而如果Connection是在應用服務器中使用連接池的話, Connection就不會被Close, 也就不會執行Commit.
3. setAutoCommit(false)
用法大多數是在要執行多條語句才提交。
所以針對以上第三點, 更接近實際的狀況的代碼如示例代碼2
示例代碼2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/** * @Title: JDBCTrans.java * @Package com.oscar999.trans * @Description: * @author XM * @date Feb 14, 2017 4:38:27 PM * @version V1.0 */ package com.oscar999.trans; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * @author * */ public class JDBCTrans { public JDBCTrans() { } /** * * @param sHostName * @param sPortNumber * @param sSid * @param userName * @param password * @return * @throws SQLException */ public Connection getConnection(String sHostName, String sPortNumber, String sSid, String userName, String password) throws SQLException { Connection conn = null ; String url = getOraclURL(sHostName, sPortNumber, sSid); conn = DriverManager.getConnection(url, userName, password); return conn; } /** * * @param conn * @param sql * @throws SQLException */ public void add(Connection conn, String sql) throws SQLException { Statement stmt = null ; try { stmt = conn.createStatement(); stmt.execute(sql); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (stmt != null ) stmt.close(); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String sHostName = "" ; String sPortNumber = "" ; String sSid = "" ; String userName = "" ; String password = "" ; sHostName = "" ; sPortNumber = "" ; sSid = "" ; userName = "" ; password = "" ; try { Class.forName( "oracle.jdbc.driver.OracleDriver" ); } catch (ClassNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } JDBCTrans jdbcTrans = new JDBCTrans(); Connection conn = null ; try { conn = jdbcTrans.getConnection(sHostName, sPortNumber, sSid, userName, password); conn.setAutoCommit( false ); // can't insert, update // 1. add SQL 1 String addSQL = "insert into TEST_TABLE values('name1','value1')" ; jdbcTrans.add(conn, addSQL); //2. add SQL 2 addSQL = "insert into TEST_TABLE values('name2','value2')" ; jdbcTrans.add(conn, addSQL); conn.commit(); } catch (SQLException e) { // TODO Auto-generated catch block if (conn!= null ){ try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } e.printStackTrace(); } finally { if (conn != null ) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } private String getOraclURL(String sHostName, String sPortNumber, String sSid) { String url = "jdbc:oracle:thin:@" + sHostName + ":" + sPortNumber + ":" + sSid; return url; } } |
這里需要說明的是: conn.rollback();
只要執行有異常,就要rollback , 這一步必不可少
如果沒有在執行出現異常的時候進行回滾。如果在執行第一條語句之后出現異常,con既沒有提交也沒有回滾,表就會被鎖住(如果oracle數據庫就是行鎖),而這個鎖卻沒有機會釋放。
可能在執行con.close()
的時候會釋放鎖,但還是如果應用服務器使用了數據庫連接池,連接不會被斷開。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家學習或者使用java能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。