一、事务简介
事务处理在数据库开发中有着非常重要的作用,所谓事务就是所有的操作要么一起成功,要么一起失败,事务本身具有原子性(Atomicity)、一致性(Consistency)、隔离性或独立性(Isolation)、持久性(Durability)等四个特征,这四个特征被称为ACID特性 。
原子性:原子性是事务最小的单元。是不可再分割的单元。相当于一个个小的数据库操作,这些操作必须同时成功,如果一个失败了,则一切的操作将全部失败。
一致性:在数据库操作的前后是一致的,保证数据的有效性,如果事务正常操作则系统会维持有效性,如果事务出现错误,则回到最原始的状态,也要维持其有效性,这样保证了事务开始时和结束时系统处于一致的状态。
隔离性:多个事务可以同时进行且彼此之间无妨访问,只有当事务完成最终操作时,才能看到结果。
持久性:事务完成以后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将会保存。
二、MySQL对事物的支持
序号 | 命令 | 描述 |
1 | SET AUTOCOMMIT = 0 | 取消自动提交处理,开启事务处理 |
2 | SET AUTOCOMMIT = 1 | 打开自动提交处理,关闭事务处理 |
3 | START TRANSACTION | 启动事务 |
4 | BEGIN | 启动事务,相当于执行START TRANSACTION |
5 | COMMIT | 提交事务 |
6 | ROLLBACK | 回滚全部事务 |
7 | SAVEPOINT 事务保存点名称 | 设置事务保存点 |
8 | ROOLBACK TO SAVEPOINT 事务保存点名称 | 回滚操作到保存点 |
三、JDBC事务处理
模拟一个银行转账的程序。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import util.DbUtil;
public class Bank {
/**
* 转出
* @param con
* @param accountName
* @param account
* @throws SQLException
*/
private static void outCount(Connection con,String countName,int count) throws SQLException{
String sql="update t_bank set countBalance=countBalance-? where countName=?";
PreparedStatement psta = con.prepareStatement(sql);
psta.setInt(1, count);
psta.setString(2, countName);
psta.executeUpdate();
}
/**
* 转入
* @param con
* @param countName
* @param count
* @throws SQLException
*/
private static void inCount(Connection con,String countName,int count) throws SQLException{
String sql = "update t_bank set countBalance=countBalance+? where countName=?";
PreparedStatement psta = con.prepareStatement(sql);
psta.setInt(1, count);
psta.setString(2, countName);
psta.executeUpdate();
}
public static void main(String[] args) {
DbUtil dbUtil = new DbUtil();
Connection con=null;
try {
con=dbUtil.getcon();
con.setAutoCommit(false); // 取消自动提交
System.out.println("张三开始向李四转账!");
int count=500;
outCount(con, "张三", count);
inCount(con, "李四", count);
System.out.println("转账成功!");
} catch (Exception e) {
try {
con.rollback(); // 回滚
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
try {
con.commit(); // 提交事务
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
四、设置一个保存点
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
import util.DbUtil;
public class Bank {
/**
* 转出
* @param con
* @param accountName
* @param account
* @throws SQLException
*/
private static void outCount(Connection con,String countName,int count) throws SQLException{
String sql="update t_bank set countBalance=countBalance-? where countName=?";
PreparedStatement psta = con.prepareStatement(sql);
psta.setInt(1, count);
psta.setString(2, countName);
psta.executeUpdate();
}
/**
* 转出
* @param con
* @param countName
* @param count
* @throws SQLException
*/
private static void inCount(Connection con,String countName,int count) throws SQLException{
String sql = "update t_bank set countBalance=countBalance+? where countName=?";
PreparedStatement psta = con.prepareStatement(sql);
psta.setInt(1, count);
psta.setString(2, countName);
psta.executeUpdate();
}
public static void main(String[] args) {
DbUtil dbUtil = new DbUtil();
Savepoint sp=null;
Connection con=null;
try {
con=dbUtil.getcon();
con.setAutoCommit(false); // 取消自动提交
System.out.println("张三开始向李四转账!");
int count=500;
sp = con.setSavepoint();//设置一个保存点
outCount(con, "张三", count);
inCount(con, "李四", count);
System.out.println("转账成功!");
} catch (Exception e) {
try {
con.rollback(sp); // 回滚到保存点
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
try {
con.commit(); // 提交事务
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
假设张三跟李四之间的转账出现小虫子,con.rollback(sp);会回滚到创建sp这个保存点的位置。使张三、李四账户上的钱不变并向上抛出异常等待处理。