事务的四种特性

一 什么是事务
数据库事务是指作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部执行,要么全部不执行。
为什么需要事务
经典的银行转账行为,A账户转给B账户10元,数据库操作需要两步,第一步A账户减10元,第二步B账户加10元,如果没有事务并且在两步中间发生异常,就会导致A的账户少了10元,但B的账户没有变化,如果不能保证这两步操作统一,银行的转账业务也没法进行展开了。
事务管理是每个数据库(oracle、mysql、db等)都必须实现的。
二 事务的四大特性
原子性 (atomicity):强调事务的不可分割.
一致性 (consistency):事务的执行的前后数据的完整性保持一致.
隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
持久性(durability) :事务一旦结束,数据就持久到数据库
事务运行模式(3种)

自动提交事务:默认事务管理模式。如果一个语句成功地完成,则提交该语句;如果遇到错误,则回滚该语句。
显式事务:以BEGIN TRANSACTION显式开始,以COMMIT或ROLLBACK显式结束。
隐性事务:当连接以此模式进行操作时,sql将在提交或回滚当前事务后自动启动新事务。无须描述事务的开始,只需提交或回滚每个事务。它生成连续的事务链。
下面做一个事务的示例:
JDBC用了Druid连接池
1、maven引包

<!--mysql驱动包 -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.47</version>
	</dependency>
	<!--druid连接池 -->
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>druid</artifactId>
		<version>1.1.10</version>
	</dependency>

1
2
3
4
5
6
7
8
9
10
11
12
2、数据库设计

CREATE TABLE account (
userid varchar(64) NOT NULL,
username varchar(64) NOT NULL,
accountbalance decimal(10,2) NOT NULL DEFAULT ‘0.00’,
createtime datetime DEFAULT NULL,
updatetime datetime DEFAULT NULL,
PRIMARY KEY (userid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO account VALUES (‘1001’, ‘张三’, ‘1000.00’, ‘2018-11-09 09:39:52’, ‘2018-11-09 09:39:55’);

INSERT INTO account VALUES (‘1002’, ‘李四’, ‘1000.00’, ‘2018-11-09 09:40:12’, ‘2018-11-09 09:40:14’);

在这里插入图片描述
3、建立jdbc.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/zhd?useUnicode=true&characterEncoding=UTF-8&InnoDB=true&useSSL=false
username=root
password=123456
1
2
3
4
4、建立连接池工具类DBPoolConnection

import java.io.InputStream;
import java.sql.SQLException;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.pool.DruidPooledConnection;

public class DBPoolConnection {
static Logger log = LoggerFactory.getLogger(DBPoolConnection.class);
private static DBPoolConnection dbPoolConnection = null;
private static DruidDataSource druidDataSource = null;

static {
	Properties properties = loadPropertiesFile("jdbc.properties");
	try {
		druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties); // DruidDataSrouce工厂模式
	} catch (Exception e) {
		log.error("获取配置失败");
	}
}

/**
 * @param string 配置文件名
 * @return Properties对象
 */
private static Properties loadPropertiesFile(String fullFile) {
	if (null == fullFile || fullFile.equals("")) {
		throw new IllegalArgumentException("Properties file path can not be null" + fullFile);
	}
	InputStream inputStream = null;
	Properties p = null;
	try {
		ClassLoader cl = DBPoolConnection.class.getClassLoader();
		inputStream = cl.getResourceAsStream(fullFile);
		p = new Properties();
		p.load(inputStream);
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		try {
			if (null != inputStream) {
				inputStream.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	return p;
}

/**
 * 数据库连接池单例
 * 
 * @return
 */
public static synchronized DBPoolConnection getInstance() {
	if (null == dbPoolConnection) {
		dbPoolConnection = new DBPoolConnection();
	}
	return dbPoolConnection;
}

/**
 * 返回druid数据库连接
 * 
 * @return
 * @throws SQLException
 */
public DruidPooledConnection getConnection() throws SQLException {
	return druidDataSource.getConnection();
}

}
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
5、建立JDBCUtil工具类

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**

  • 对jdbc的完整封装

*/
public class JDBCUtil {

public static Logger log = LoggerFactory.getLogger(JDBCUtil.class);

/**
 * insert update delete SQL语句的执行的统一方法
 * 
 * @param sql SQL语句
 * @param params 参数数组,若没有参数则为null
 * @return 受影响的行数
 */
public int executeUpdate(String sql, Object... params) {
	// 受影响的行数
	int affectedLine = 0;
	// 创建ResultSetMetaData对象
	Connection conn = null;
	PreparedStatement pst = null;
	try {
		// 获得连接
		conn = DBPoolConnection.getInstance().getConnection();
		// 调用SQL
		pst = conn.prepareStatement(sql);

		// 参数赋值
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				pst.setObject(i + 1, params[i]);
			}
		}
		/*
		 * 在此 PreparedStatement 对象中执行 SQL 语句, 该语句必须是一个 SQL 数据操作语言(Data
		 * Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE
		 * 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。
		 */
		// 执行
		affectedLine = pst.executeUpdate();

	} catch (SQLException e) {
		System.out.println(e.getMessage());
	} finally {
		// 释放资源
		closeAll(conn, pst, null);
	}
	return affectedLine;
}

/**
 * insert update delete SQL语句的执行的统一方法
 * 
 * @param sql SQL语句
 * @param params 参数数组,若没有参数则为null
 * @return 受影响的行数
 */
public int executeUpdate(Connection conn, String sql, Object... params) {
	// 受影响的行数
	int affectedLine = 0;
	// 创建ResultSetMetaData对象
	PreparedStatement pst = null;
	try {
		// 获得连接
		// 调用SQL
		pst = conn.prepareStatement(sql);

		// 参数赋值
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				pst.setObject(i + 1, params[i]);
			}
		}
		/*
		 * 在此 PreparedStatement 对象中执行 SQL 语句, 该语句必须是一个 SQL 数据操作语言(Data
		 * Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE
		 * 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。
		 */
		// 执行
		affectedLine = pst.executeUpdate();

	} catch (SQLException e) {
		System.out.println(e.getMessage());
	} finally {
		// 释放资源
		 close(pst);
	}
	return affectedLine;
}

/**
 * 获取结果集,并将结果放在List中
 * 
 * @param sql SQL语句 params 参数,没有则为null
 * @return List 结果集
 */
public List<Map<String, Object>> excuteQuery(String sql, Object... params) {
	// 创建ResultSetMetaData对象
	ResultSetMetaData rsmd = null;
	Connection conn = null;
	PreparedStatement pst = null;
	ResultSet rst = null;
	// 创建List
	List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
	try {
		conn = DBPoolConnection.getInstance().getConnection();
		// 调用SQL
		pst = conn.prepareStatement(sql);
		// 参数赋值
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				pst.setObject(i + 1, params[i]);
			}
		}
		// 执行
		rst = pst.executeQuery();
		rsmd = rst.getMetaData();
		// 获得结果集列数
		int columnCount = rsmd.getColumnCount();
		// 将ResultSet的结果保存到List中
		while (rst.next()) {
			Map<String, Object> map = new HashMap<String, Object>();
			for (int i = 1; i <= columnCount; i++) {
				map.put(rsmd.getColumnLabel(i), rst.getObject(i));
			}
			list.add(map);// 每一个map代表一条记录,把所有记录存在list中
		}

	} catch (SQLException e1) {
		System.out.println(e1.getMessage());
	} finally {
		// 关闭所有资源
		closeAll(conn, pst, rst);
	}
	return list;
}

/**
 * 关闭所有资源
 */
private void closeAll(Connection conn, PreparedStatement pst, ResultSet rst) {
	// 关闭结果集对象
	if (rst != null) {
		try {
			rst.close();
		} catch (SQLException e) {
			System.out.println(e.getMessage());
		}
	}

	// 关闭PreparedStatement对象
	if (pst != null) {
		try {
			pst.close();
		} catch (SQLException e) {
			System.out.println(e.getMessage());
		}
	}

	// 关闭Connection 对象
	if (conn != null) {
		try {
			conn.close();
		} catch (SQLException e) {
			System.out.println(e.getMessage());
		}
	}
}

/**
 * 关闭所有资源
 */
public void close(AutoCloseable autoCloseable) {
	if (autoCloseable != null) {
		try {
			autoCloseable.close();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
}

/**
 * 通过反射机制查询单条记录
 * 
 * @param sql
 * @param params
 * @param cls
 * @return
 * @throws Exception
 */
public <T> T findSimpleRefResult(String sql, Class<T> cls, Object... params) {
	T resultObject = null;
	int index = 1;
	Connection conn = null;
	PreparedStatement pst = null;
	ResultSet rst = null;
	try {
		conn = DBPoolConnection.getInstance().getConnection();
		pst = conn.prepareStatement(sql);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				pst.setObject(index++, params[i]);
			}
		}
		rst = pst.executeQuery();
		ResultSetMetaData metaData = rst.getMetaData();
		int cols_len = metaData.getColumnCount();
		while (rst.next()) {
			// 通过反射机制创建一个实例
			resultObject = cls.newInstance();
			for (int i = 0; i < cols_len; i++) {
				String cols_name = metaData.getColumnName(i + 1);
				Object cols_value = rst.getObject(cols_name);
				if (cols_value == null) {
					cols_value = "";
				}
				try {
					Field field = cls.getDeclaredField(cols_name.toLowerCase());
					field.setAccessible(true); // 打开javabean的访问权限
					field.set(resultObject, cols_value);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		closeAll(conn, pst, rst);
	}
	return resultObject;

}

/**
 * 通过反射机制查询多条记录
 * 
 * @param sql
 * @param params
 * @param cls
 * @return
 * @throws Exception
 */
public <T> List<T> findMoreRefResult(String sql, Class<T> cls, Object... params) {
	List<T> list = new ArrayList<T>();
	int index = 1;
	Connection connection = null;
	PreparedStatement pstmt = null;
	ResultSet resultSet = null;
	try {
		connection = DBPoolConnection.getInstance().getConnection();
		pstmt = connection.prepareStatement(sql);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				pstmt.setObject(index++, params[i]);
			}
		}
		resultSet = pstmt.executeQuery();
		ResultSetMetaData metaData = resultSet.getMetaData();
		int cols_len = metaData.getColumnCount();
		while (resultSet.next()) {
			// 通过反射机制创建一个实例
			T resultObject = cls.newInstance();
			for (int i = 0; i < cols_len; i++) {
				String cols_name = metaData.getColumnName(i + 1);
				Object cols_value = resultSet.getObject(cols_name);
				if (cols_value == null) {
					cols_value = "";
				}
				try {
					Field field = cls.getDeclaredField(cols_name.toLowerCase());
					field.setAccessible(true); // 打开javabean的访问权限
					field.set(resultObject, cols_value);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			list.add(resultObject);
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		closeAll(connection, pstmt, resultSet);
	}
	return list;
}

/**
 * 通过反射机制查询多条记录
 * 
 * @param sql
 * @param params
 * @param cls
 * @return
 * @throws Exception
 */
public List<String> findMoreRefResult(String sql, Object... params) {
	List<String> list = new ArrayList<String>();
	int index = 1;
	Connection connection = null;
	PreparedStatement pstmt = null;
	ResultSet resultSet = null;
	try {
		connection = DBPoolConnection.getInstance().getConnection();
		pstmt = connection.prepareStatement(sql);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				pstmt.setObject(index++, params[i]);
			}
		}
		resultSet = pstmt.executeQuery();
		while (resultSet.next()) {
			// 通过反射机制创建一个实例
			String cols_value = resultSet.getString(1);
			list.add(cols_value);
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		closeAll(connection, pstmt, resultSet);
	}
	return list;
}

/**
 * SQL 查询将查询结果:一行一列
 * 
 * @param sql SQL语句
 * @param params 参数数组,若没有参数则为null
 * @return 结果集
 */
public Object executeQuerySingle(String sql, Object... params) {
	Connection conn = null;
	PreparedStatement pst = null;
	ResultSet rst = null;
	Object object = null;
	try {
		// 获得连接
		conn = DBPoolConnection.getInstance().getConnection();
		// 调用SQL
		pst = conn.prepareStatement(sql);
		// 参数赋值
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				pst.setObject(i + 1, params[i]);
			}
		}
		// 执行
		rst = pst.executeQuery();
		if (rst.next()) {
			object = rst.getObject(1);
		}
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		closeAll(conn, pst, rst);
	}

	return object;
}

}
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
5、进行测试:

正常情况下:

public class JDBCTest {
public static void main(String[] args) {
JDBCUtil jdbcUtil = new JDBCUtil();
Connection conn = null;
try {
conn = DBPoolConnection.getInstance().getConnection();
conn.setAutoCommit(false);
String sql_1 = “update account set accountbalance = accountbalance + ? where userid = ?”;
String sql_2 = “update account set accountbalance = accountbalance - ? where userid = ?”;
int line_1 = jdbcUtil.executeUpdate(conn, sql_1, 10, “1001”);
int line_2 = jdbcUtil.executeUpdate(conn, sql_2, 10, “1002”);
conn.commit();
} catch (SQLException e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
jdbcUtil.close(conn);
}
}
}
在这里插入图片描述
在这里插入图片描述
异常情况下:

public class JDBCTest {
public static void main(String[] args) {
JDBCUtil jdbcUtil = new JDBCUtil();
Connection conn = null;
try {
conn = DBPoolConnection.getInstance().getConnection();
conn.setAutoCommit(false);
String sql_1 = “update account set accountbalance = accountbalance + ? where userid = ?”;
String sql_2 = “update account set accountbalance = accountbalance - ? where userid = ?”;
int line_1 = jdbcUtil.executeUpdate(conn, sql_1, 10, “1001”);
if (line_1 == 1) {
throw new RuntimeException();
}
int line_2 = jdbcUtil.executeUpdate(conn, sql_2, 10, “1002”);
conn.commit();
} catch (SQLException e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
jdbcUtil.close(conn);
}
}
}

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值