1、什么是数据库事务
一组逻辑操作单元,使数据从一种状态变换到另一种状态。(一组逻辑操作单元:一个或多个DML操作)
案例:用户AA向用户BB转账100。
sql语句:
update user_table set balance = balance - 100 where user = ?;
update user_table set balance = balance + 100 where user = ?;
如果在第一条语句后出现异常导致第二条语句没有执行,那么数据库已经执行了第一条语句,则会出现账户只减不加的情况,所以需要两条语句都执行后,一起在数据库执行,要么都执行,要么都不执行,这时需要使用事务来解决。
2、事务处理的原则
保证所有事务都作为一个工作单元来执行,即使出现故障,都不能改变这种执行方式。
当在一个事务中执行多个操作时,要么所有事务都被提交,那么这些修改就永久保存;
要么数据库管理系统将放弃所作的所有修改,整个事务回滚到最初状态。
3、数据一旦提交,就不可回滚
4、哪些操作会导致数据的自动提交
①DDL操作一旦执行,都会自动提交(setAutoCommit失效);
②DML默认情况,自动提交,但可以通过setAutoCommit取消自动提交;
③默认再关闭连接时,会自动提交数据。
一、代码实现
前提
创建jdbc.properties配置文件
封装连接数据库的基本信息
user=root
password=ad
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
driverClass=com.mysql.cj.jdbc.Driver
创建软件包unil,软件包下创建JDBCUtils类
封装连接数据库、关闭的方法
package util;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**封装数据库连接和关闭*/
public class JDBCUtils {
public static Connection getConnection() throws Exception{
//读取配置文件基本信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
//加载驱动
Class.forName(driverClass);
//获取连接
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
}
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();
}
}
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();
}
}
}
考虑事务的增删改操作
与前面不同的是,需要传入连接的数据库。
在调用通用的增删改方式时,连接数据库,取消自动提交,在sql语句都执行完成时,再提交数据,出现异常则回滚事务,最后需要恢复自动提交。
setAutoCommit()设置自动提交状态
commit()提交数据
rollback()回滚数据
public static void testUpdateWithTx(){
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//取消自动提交
conn.setAutoCommit(false);
String sql = "update user_table set balance = balance - 100 where user = ?";
update(conn,sql,"AA");
//模拟网络异常
System.out.println(10/0);
String sql1 = "update user_table set balance = balance + 100 where user = ?";
update(conn,sql1,"BB");
System.out.println("转账成功");
//提交数据
conn.commit();
}catch (Exception e){
e.printStackTrace();
//回滚数据
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
//恢复自动提交
try {
conn.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
JDBCUtils.closeResource(conn,null);
}
}
/**通用增删改操作(考虑事务)*/
public static void update(Connection conn,String sql,Object ...args){//args可变形参,占位符长度
PreparedStatement ps = null;
try {
//预编译
ps = conn.prepareStatement(sql);
//填充占位符
for(int i = 0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
//执行
ps.execute();
}catch (Exception e){
e.printStackTrace();
}finally {
//资源关闭
JDBCUtils.closeResource(null,ps);
}
}