目录
事务(Transaction)
一个最小的不可再分的工作单元,最终表达为一条或者多条SQL语句,对应一个完整的业务,比如:借书,转账等
事务的四大特性
业务动作对应的SQL会被看成一个整体,是不可再分的。事务中操作的执行过程只会有两种情况,成功/失败,当事务中所有操作都执行成功(commit)时,事务成功。当其中任意一个操作失误时,其他已经被执行的操作会撤销然后回滚(rollback),事务失败。
一致性指的是数据一致性,事务必须使数据库从一个一致性状态变换到另外一个一致性状态
一个事务的执行不能被其他事务干扰。针对多用户场景,当有多个用户同时针对数据进行增删查改时,需要保持隔离的特性。理想情况下,一个用户在对数据进行修改时,不能有其他用户对该用户的操作存在干扰
持久性也称永久性,当事务成功提交时,数据库中数据的修改就是永久性的
MySQL中使用事务
-- 事务开始
start transaction;
-- 执行的SQL语句
insert语句/update语句/delete语句
-- 提交
commit;
例子
- 先建表
-- 书籍信息表
CREATE TABLE `library`.`books` (
`bid` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NOT NULL COMMENT '书籍名称',
`count` INT NOT NULL COMMENT '存量',
`total` INT NOT NULL COMMENT '总量',
PRIMARY KEY (`bid`))
COMMENT = '书籍信息';
-- 借阅者信息表
CREATE TABLE `library`.`readers` (
`rid` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NOT NULL,
PRIMARY KEY (`rid`))
COMMENT = '借阅者信息';
-- 借阅记录表
CREATE TABLE `library`.`records` (
`reid` INT NOT NULL AUTO_INCREMENT,
`rid` INT NOT NULL COMMENT '谁借的',
`bid` INT NOT NULL COMMENT '借的哪本书',
`borrowed_at` DATETIME NOT NULL DEFAULT current_timestamp COMMENT '借阅时间',
PRIMARY KEY (`reid`))
COMMENT = '借阅记录';
- 插入书籍信息和借阅人信息
-- 插入书籍
insert into books(name,count,total) values
('三国演义',30,30),
('鲁滨逊漂流记',10,10);
-- 插入借阅者信息
insert into readers(name) values
('张三'),
('李四');
- 借书操作
- 必须要进行commit,事务才算提交成功,否则会回滚
-- 借阅人:借书 rid为1的张三借阅了bid为2的鲁滨逊漂流记
start transaction;
update books set count = count - 1 where bid = 2;
insert into records (rid,bid) values (1,2);
commit;
JDBC中使用事务
例子
- 先连接数据库
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author happy
*/
public class DBUtil {
private static final DataSource dataSource;
static {
MysqlDataSource db = new MysqlDataSource();
String url = "jdbc:mysql://localhost:3306/library?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
db.setUrl(url);
db.setUser("root");
db.setPassword("12345");
dataSource = db;
}
public static Connection connection() throws SQLException {
return dataSource.getConnection();
}
}
- rid为2李四借阅bid为1的三国演义
import com.zhang.util.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author happy
* 有事务,并且commit
*/
public class Demo1 {
public static void main(String[] args) throws SQLException {
String sql1 = "update books set count = count -1 where bid = 1";
String sql2 = "insert into records (rid,bid) values (2,1)";
// 要在同一个事务中,操作 sql1 和 sql2,意味着必须在一条 Connection 完成
// 关闭connection的自动提交,需要手动提交
try(Connection c = DBUtil.connection()){
// 关闭自动提交
c.setAutoCommit(false);
try(PreparedStatement ps = c.prepareStatement(sql1)){
ps.executeUpdate();
}
try(PreparedStatement ps = c.prepareStatement(sql2)){
ps.executeUpdate();
}
c.commit();
}
System.out.println("借阅成功");
}
}