JDBC-08-2--数据库事务-JDBC事务处理
原创
©著作权归作者所有:来自51CTO博客作者靠谱的大钊的原创作品,请联系作者获取转载授权,否则将追究法律责任
数据库事务
什么叫数据库事务
- 事务:一组逻辑操作单元,使数据从一种状态到另外一种状态,一组逻辑操作单元,一个或者多个DML操作
事务处理的原则:
- 保证所有事务都为一个工作单元执行 即使出现了故障,都不能改变这种方式当一个事务中执行了多个操作时,要么所有的事务都被提交(commit) , 那么这些修改就永久保存下来: 要么数据库管理系统将放弃所作的所有修改,整个事务回滚(roolBack) 到最初始状态
JDBC事务处理
那些操作会导致数据的自动提交?
DDL数据定义语言,用于定义和管理 SQL 数据库中的所有对象的语言
- DDL操作一旦执行,就会自动提交set autocommit = false 对DDL操作失效
DML数据操作语言,SQL中处理数据等操作统称为数据操纵语言
我们通过set autocommit= false 的方式 取消DML操作的自动提交
JDBC程序中为了让多个 SQL 语句作为一个事务执行
- 调用Connection对象的setAutoCommit(flase): 以取消自动提交事务
- 在所有的sql语句都成功执行后,调用commit(); 方法提交事务
- 出现异常时.调用rollback(); 进行回滚事务
若此时connection没有被关闭,还可能被被重复使用,则需要恢复其自动提交的状态
setAutoCommit(true) 尤其时使用数据库连接池技术时,执行close()方法前,建议恢复自动提交状态
案例
用户AA向用户BB转账100
未考虑数据库事务情况下的转账操作:
@Test
public void testUpdate() {
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(sql1, "AA");
//模拟网络异常
// System.out.println(10 / 0);
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(sql2, "BB");
System.out.println("转账成功");
}
// 通用的增删改操作---version 1.0
public int update(String sql, Object... args) {
Connection conn = null;
PreparedStatement ps = null;
try {
//1, 获取数据库连接
conn = JDBCUtils.getConnection();
//2 预编译sql语句 返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
//填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
//执行
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
//修改其为自动提交数据
//主要针对于使用数据库连接池的使用
try {
conn.setAutoCommit(true);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
//关闭资源
JDBCUtils.closeResource(conn, ps);
}
return 0;
}
出现问题:当模拟网络异常时,AA的钱扣除了,但是没有加到B中
解决问题:考虑数据库事务后进行转账操作
*1.什么叫数据库事务
* 事务:一组逻辑操作单元,使数据从一种状态到另外一种状态
* > 一组逻辑操作单元,一个或者多个DML操作
*2. 事务处理的原则:保证所有事务都为一个工作单元执行 即使出现了故障,都不能改变这种方式
* 当一个事务中执行了多个操作时,要么所有的事务都被提交(commit) 那么这些修改就永久保存下来
* : 要么数据库管理系统将放弃所作的所有修改,整个事务回滚(roolBack) 到最初始状态
考虑数据库事务后的转账操作
注意:
为了数据报错正常产生回滚
-
update1(Connection conn, String sql, Object... args)
连接数据库由外部测试提供,也即是关闭连接是JDBCUtils.closeResource(null, ps);
- .取消自动提
conn.setAutoCommit(false)
; - 所有的 SQL 语句都成功执行后,调用
commit();
方法提交事务 - 出现异常 调用
rollback();
方法回滚事务
@Test
public void testUpdateWithTx() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//1.取消自动提交
conn.setAutoCommit(false);
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update1(conn, sql1, "AA");
//模拟网路异常
// System.out.println(10 / 0);
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update1(conn, sql2, "BB");
System.out.println("转账成功");
//2 提交数据
conn.commit();
} catch (Exception e) {
e.printStackTrace();
//3 数据回滚
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} finally {
JDBCUtils.closeResource(conn, null);
}
}
// 通用的增删改操作---version 2.0
public int update1(Connection conn, String sql, Object... args) {
PreparedStatement ps = null;
try {
//1 预编译sql语句 返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
//2 填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
//3 执行
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
//4 关闭资源
JDBCUtils.closeResource(null, ps);
}
return 0;
}
连接数据库相关操作
操作数据库的工具类
package com.nie1.transaction.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @Description 操作数据库的工具类
*/
public class JDBCUtils {
/**
* @return
* @throws Exception
* @Description 获取数据库的连接
*/
public static Connection getConnection() throws Exception {
// 1.读取配置文件中的4个基本信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
//2获取四个配置
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
// 3.加载驱动
Class.forName(driverClass);
// 4.获取连接
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
/**
* @Description 关闭连接和Statement的操作
*/
public static void closeResource(Connection conn, Statement ps) {
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* @Description 关闭资源操作
*/
public static void closeResource(Connection conn, Statement ps, ResultSet rs) {
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
配置文件jdbc.properties
#获取
user=root
password=123123
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
driverClass=com.mysql.jdbc.Driver