事务就是将一组SQL语句放在同一批次内去执行
如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行
MySQL事务处理只支持InnoDB和BDB数据表类型
特点:要么都成功,要么都失败。
情景分析:
1.Sql执行:成龙龙给成果果转钱, 成龙龙 777 —> 77 给成果果 700
2.Sql执行:成果果接到成龙龙的钱, 成龙龙 700 <—> 成果果 777
两个Sql语句放在一起执行,一个批次进行执行,一成全成,一败全败。
一批次的操作,要么一起成功,要么一起失败。
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(ROLLBACK)到事务开始前的状态,就像这个事务从来没有执行过一样。
事务前后的数据完整性要保持一致。
一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving an Invariant),以转账案例为例,Eg:成龙和成果一共有777+700元,转账前后,都是如此,金额总数不变。
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
隔离所导致的一些问题:
一个事务读取了另外一个事务没有提交的数据。
在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。(一般是行影响,多了一行)
事务一单提交就不可逆了,被持久化到数据库里。
1.事务没有提交,就恢复到原状态。
2.事务一旦提交,就持久化到数据库。
执行事务的流程和基本语法:
-- MySQL是默认开启事务自动提交的,咱们学习时,可以先关闭。
set autocommit = 0; -- 关闭事务
set autocommit = 1; -- 开启事务,开启是默认的
-- 手动处理事务
set autocommit = 0; -- 关闭事务
-- 事务开始:
start transaction;
-- 标记一个事务的开始,从这个代码之后的sql都在同一个事务里面
-- 提交:实现持久化。(成功的话)
commit;
-- 回滚:返回原来的样子。(失败的话)
rollback;
-- 事物结束,重新开启。
set autocommit = 1; -- 开启事务,开启是默认的
-- 了解:设置事务的保存点,就像游戏里的存档点。
savepoint 保存点名;
-- 回滚至保存点:就像游戏里死后的返回上一个存档点。
rollback to savepoint 保存点名;
-- 撤销保存点:
release savepoint 保存点名;
模拟场景:
转账练习:创建数据库和表格。
create database `shop` character set utf8 collate utf8_general_ci;
use shop;
create table `account` (
`id` int(3) not null auto_increment,
`name` varchar(30) not null,
`money` decimal(9,2) not null,
primary key (`id`)
)engine = innodb default charset = utf8;
/*
mysql字段decimal(9,2)中9是定点精度,2是小数位数。
存在这么一个公式:decimal(a,b)。
其中a指定指定小数点左边和右边可以存储百的十进度制数字的最大个数,最大精度38;
b指定小数点右边可以存储的十进制数字的最大个数,小数位数必须是从 0 到 a之间的值,
默认小数位数是 0。
*/
insert into account(`name`,`money`) values
('成果果','7777'),
('成龙龙','70000');
模拟转账:事务处理
-- 关闭自动提交。
set autocommit = 0;
-- 开启一个事务。
start transaction;
-- 关闭安全模式,防止无法删改数据等。
SET SQL_SAFE_UPDATES = 0;
-- 成果果减去777元
update account set money = money - 777 where `name` = '成果果';
-- 成龙龙接收777元。
update account set money = money + 777 where `name` = '成龙龙';
-- 判断成功,提交。
commit;
-- 判断失败,回滚。
rollback;
-- 开启安全模式,
SET SQL_SAFE_UPDATES = 1;
-- 恢复默认值,恢复自动提交。
set autocommit = 1;
成功修改后:
执行rollback:
执行commit:
且无法再次修改为原来的样子。
成功案例:
package com.Edwin.lession04;
import com.Edwin.lession02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Edwin D
* @date 2020.5.23 上午 10:58
*/
public class TestTransaction1 {
public static void main(String[] args) throws SQLException {
Connection con = null;
PreparedStatement pres = null;
ResultSet res = null;
try {
con = JdbcUtils.getConnection();
// 关闭数据库的自动提交,同时会默认自动开启事务
con.setAutoCommit(false);//可以理解为“开启事务”
String sql1 = "update account set money = money - 77 where id = 1 ";
pres = con.prepareStatement(sql1);
pres.executeUpdate();
String sql2 = "update account set money = money + 77 where id = 2 ";
pres = con.prepareStatement(sql2);
pres.executeUpdate();
// 事务完毕,提交事务。
con.commit();
System.out.println("Success!");
} catch (SQLException e) {
// con.rollback(); //如果失败,则会自动回滚。但是异常中早已包括了。
e.printStackTrace();
}finally {
JdbcUtils.release(con,pres,res);
}
}
}
输出:
原先的Edwin:777.77,Jarvis:7777.77。现在实现事务后如图:
try {
con = JdbcUtils.getConnection();
// 关闭数据库的自动提交,同时会默认自动开启事务
con.setAutoCommit(false);//可以理解为“开启事务”
String sql1 = "update account set money = money - 77 where id = 1 ";
pres = con.prepareStatement(sql1);
pres.executeUpdate();
// 增添一个无法完成的语句,使其必定执行rollback
int x = 1/0;
String sql2 = "update account set money = money + 77 where id = 2 ";
pres = con.prepareStatement(sql2);
pres.executeUpdate();
// 事务完毕,提交事务。
con.commit();
System.out.println("Success!");
}catch (SQLException e) {
// con.rollback(); //如果失败,则会自动回滚。但是异常中早已包括了。
e.printStackTrace();
}finally {
JdbcUtils.release(con,pres,res);
}
}
输出:
1.开启事务。
con.setAutoCommit(false);//可以理解为“开启事务”
2.一组业务执行完毕,提交事务。
3.可以在catch中显示定义rollback回滚语句,单默认情况下,失败就会回滚。
《【狂神说Java】MySQL最新教程通俗易懂》
视频连接:https://www.bilibili.com/video/BV1NJ411J79W
《狂神说MySQL06:事务和索引》
原文连接
2020.05.17