一、事务
要么都成功,要么都失败。
ACID原则
- 原子性:要么全部完成,要么都不完成。
- 一致性:总数不变。
- 隔离性:多个进程互不干扰。
- 持久性:一旦提交,不可逆,持久化到数据库。
隔离性产生的问题
- 脏读:一个事务读取了另外一个没有提交的事务。
- 不可重复读:在一个事务中,重复读取表中数据,并且表中的数据发生了改变。
- 虚读(幻读):在一个事务中,读取到了别人插入的数据,导致前后读取出来的结果不一致。
创建account表的SQL语句
CREATE TABLE account(
id INT PRIMARY KEY auto_increment,
`name` VARCHAR(40),
money FLOAT
);
INSERT INTO account(id,`name`,money) VALUES(1,'A',1000),
(2,'B',1000),
(3,'C',1000);
模拟转账的代码
package lesson04;
import lesson02.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//模拟转账功能
public class TestTransaction {
public static void main(String[] args){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
//conn相当于一个数据库对象
try {
conn = JdbcUtils.getConnection();
//关闭数据库的自动提交功能,会自动开启事务
conn.setAutoCommit(false);
String sql1 = "update account set money=money-100 where id=1";
st = conn.prepareStatement(sql1);
st.executeUpdate();
String sql2 = "update account set money=money+100 where id=2";
st = conn.prepareStatement(sql2);
st.executeUpdate();
//提交事务
conn.commit();
System.out.println("成功");
} catch (SQLException throwables) {
throwables.printStackTrace();
try {
//如果失败,则回滚
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}finally {
//关闭连接
JdbcUtils.release(conn,st,rs);
}
}
}
模拟转账失败的代码。测试原子性。
package lesson04;
import lesson02.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction1 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
//连接数据库
conn = JdbcUtils.getConnection();
//关闭自动提交功能,相当于自动开启了事务
conn.setAutoCommit(false);
//sql语句
String sql = "update account set money=money-100 where id=1";
//预编译SQL语句
st = conn.prepareStatement(sql);
//执行SQL语句
st.executeUpdate();
//故意制造一个错误,让代码自动回滚
int i = 1/0;
//sql语句
String sql1 = "update account set money=money+100 where id=2";
//预编译SQL语句
st = conn.prepareStatement(sql1);
//执行SQL语句
st.executeUpdate();
conn.commite();
System.out.println("执行");
} catch (SQLException throwables) {
throwables.printStackTrace();
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
其中,setAutoCommit(false) 开启事务。