文章目录
事务
一、事务的基本介绍
1、概念
如果包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。
2、操作
-
① 开启事务:
start transaction;
-
② 回滚:
rollback;
-
③ 提交:
commit;
3、操作实例
account.sql
-- 创建account表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT;
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME,balance) VALUES ('zhangsan',1000),('lisi',1000);
SELECT * FROM account;
UPDATE account SET balance =1000;
--张三给李四转账500元
--0.开启事务
START TRANSACTION;
--1.张三账户-500
UPDATE account SET balance = balance - 500 WHERE NAME ='zhangsan';
--2.李四账户+500
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';
--发现执行没有问题,提交事务
COMMIT;
--发现出现问题,回滚事务
ROLLBACK;
4、MySQL数据库中默认自动提交
事务提交的两种方式
1)自动提交
- mysql是自动提交的
- 一条DML(增删改)语句会自动提交一次事务
2)手动提交
- Oracle 数据库默认是手动提交事务
- 需要先开启事务,然后手动提交
修改事务的默认提价方式
-
查看事务的默认提交方式:
SElECT @@autocommit;
--1 代表自动提交 0 代表手动提交 -
修改默认提交方式:
set @@autocommit = 0;
二、事务的四大特征
-
原子性(atomicity)
:事务必须是原子工作单元;对其数据修改,要么全都执行,要么全都不执行【最小的工作单位】 -
一致性(consistency
:事务在完成时,必须使所有的数据都保持一致状态【同时成功或者同时失败】 -
隔离性(isolation)
:由并发事务所作的修改必须与任何其他并发事务所作的修改隔离【事务与事务之间相互不影响】 -
持久性(durability)
:事务完成之后,它对于系统的影响是永久性的【事务一旦提交不可回滚】
三、事务的隔离级别
1、概念
多个事务之间隔离,相互独立的,但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题:
2、存在的问题
-
① 脏读:一个事务读取到另一个书屋中没有提交的数据
-
② 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样
-
③ 幻读:一个事务操作(DML)数据库中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
3、隔离级别
隔离的级别:
- ①
read uncommitted:
读未提交- 产生的问题:脏读,不可重复读,幻读
- ②
read committed:
读已提交- 产生的问题:不可重复读、幻读
- ③
repeatable read:
可重复读- 产生的问题:幻读
- ④
serializable:
串行化- 可以解决所有的问题
注意:隔离级别从小到大安全性越来越高,但是效率越来越低
隔离级别的设置
-
数据库查询隔离级别:
select @@tx_isolation;
-
数据库设置隔离级别:
set global transaction isolation level 级别字符串;
注:设置完隔离级别后需要重新打开mysql数据库才会生效。
演示
set global transaction isolation level read uncommitted;
start transaction;
-- 转账操作
update account set balance = balance - 500 where id = 1;
update account set balance = balance + 500 where id = 2;
四、Jdbc事务控制
1、概述
- 默认事务提交策略:一条命令自成一个完整事务
- 需求:各个逻辑单元要么一起成功,要么一起失败(比如转账)
2、控制事务的API:
使用Connection对象来管理事务
conn.setAutoCommit(false);
将jdbc的事务计较改为手动提交conn.commit();
手动提交conn.rollback();
如果事务出错,就让他它回滚
注意:连接提交策略一经设置,永久改变。
3、核心代码
将JDBC自动提交关闭,改成手动提交,然后在让出错的事务在异常里捕获成回滚。这样保证了提交事务出错数据不改动。从而达到数据的正确性。
步骤:
1. 获取连接Connection对象
2.Connection对象开启事务
3.Connection对象获取执行sql语句的Statement对象
4.定义2条sql语句(2条update语句:扣款,收款)
5.Statement对象执行sql语句,获取结果
6.如果sql语句正常执行,没有出现问题,提交事务
7.处理结果
8.如果sql语句执行过程中出现问题,回滚事务
9.关闭资源
代码:
import java.sql.*;
import util.JdbcUtil1;
/*
* jdbc控制事务
*/
public class testTrasaction {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstm = null;
PreparedStatement pstm1 = null;
try {
//获得连接
conn = JdbcUtil1.getConnection();
//设置jdbc手动提交
conn.setAutoCommit(false);
//降职ְ
String sql = "update emp set job='clerk' where ename='陈美嘉'";
pstm = conn.prepareStatement(sql);
pstm.executeUpdate();
//降薪
String sql1 = "update emp set comm='300' where ename='陈美嘉'";
pstm1 = conn.prepareStatement(sql1);
pstm1.executeUpdate();
//提交事务
conn.commit();
} catch (Exception e) {
//事务回滚
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally{
try {
JdbcUtil1.release(null, pstm, null);
JdbcUtil1.release(null, pstm1, conn);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
JdbcUtil1
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.*;
public class JdbcUtil1 {
//声明properties
static Properties pro = new Properties();
//加载驱动
static{
InputStream is = null;
try{
is = JdbcUtil1.class.getResourceAsStream("/conf/db.properties");
//加载文件
pro.load(is);
Class.forName(pro.getProperty("driverClassName"));
}catch(Exception e){
e.printStackTrace();
}finally{
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//获取连接
public static Connection getConnection() throws Exception{
String url = pro.getProperty("url");
String user = pro.getProperty("username");
String password = pro.getProperty("password");
//获取连接
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
//释放资源/关闭连接
public static void release(ResultSet rs,PreparedStatement pstm,Connection conn) throws Exception{
if(rs!=null){
rs.close();
}
if(pstm!=null){
pstm.close();
}
if(conn!=null){
conn.close();
}
}
}