事务
1.事务的概念
update account set money=money-100 wherename=‘a’;
update account set money=money+100 wherename=‘b’;
2、TPL
事务(Transaction)处理语言
数据库有可能是自动提交事务的(MySQL默认就是自动提交事务的),每一条语句都是单独的事务。
start transaction:开启事务
commit:提交事务。永久的存储到硬盘上
rollback:回滚事务。回到最开始的地方
3、JDBC控制事务
package com.hcx.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.hcx.utils.JdbcUtils;
演示事务
//CREATE TABLE bank
//(
// id INT PRIMARY KEY,
// NAME VARCHAR(20) ,
// money FLOAT
//)
//
//INSERT INTO bank VALUES(1,"张无忌",10000) ;
//INSERT INTO bank VALUES(2,"令狐冲",1) ;
//
//SELECT * FROM bank ;
public class TransactionTest {
//模拟执行张无忌给令狐冲转账5000
@Test
public void testTransaction() throws Exception {
// 获得链接对象
Connection conn = JdbcUtils.getConnection();
PreparedStatement pstmt = conn.prepareStatement("update bank set money = money -? where id = ?") ;
pstmt.setFloat(1, 5000) ;
pstmt.setInt(2, 1) ;
int n = pstmt.executeUpdate() ;
System.out.println(n);
System.out.println(10/0);
PreparedStatement pstmt1 = conn.prepareStatement("update bank set money = money + ? where id = ?") ;
pstmt1.setFloat(1, 5000) ;
pstmt1.setInt(2, 2) ;
int n1 = pstmt1.executeUpdate() ;
System.out.println(n1);
// 释放资源
JdbcUtils.release(null, pstmt, conn);
JdbcUtils.release(null, pstmt1, conn);
}
//采用事务处理转账失败的情况
@Test
public void testTransaction1() throws Exception {
// 获得链接对象
Connection conn = JdbcUtils.getConnection();
PreparedStatement pstmt = null ;
PreparedStatement pstmt1 = null ;
//让数据库不要自动提交事务
conn.setAutoCommit(false) ;
try{
pstmt = conn.prepareStatement("update bank set money = money -? where id = ?") ;
pstmt.setFloat(1, 2000) ;
pstmt.setInt(2, 1) ;
int n = pstmt.executeUpdate() ;
System.out.println(n);
System.out.println(10/2);
pstmt1 = conn.prepareStatement("update bank set money = money + ? where id = ?") ;
pstmt1.setFloat(1, 2000) ;
pstmt1.setInt(2, 2) ;
int n1 = pstmt1.executeUpdate() ;
System.out.println(n1);
//手动进行提交,体现一致性
conn.commit() ;
}catch(Exception e){
//让事务进行回滚
conn.rollback() ;
}
// 释放资源
JdbcUtils.release(null, pstmt, conn);
JdbcUtils.release(null, pstmt1, conn);
}
}
4.事务的特性(ACID)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
5.事务的隔离级别
不考虑事务的隔离级别会导致什么问题?
1、脏读:指一个事务到读到另外一个事务中未提交的数据。
2、不可重复读:指一个事务读到另外一个事务执行update的语句的结果(已提交)
3、虚读:指一个事务读到另外一个事务执行的insert的语句的结果(已提交)
MySQL中支持的事务隔离级别:
READ UNCOMMITTED:脏读、不可重复读、虚读有可能发生。
READ COMMITTED:防止脏读的发生;不可重复读、虚读有可能发生。
REPEATABLE READ:防止脏读、不可重复读的发生;虚读有可能发生。(MySQL中默认)
SERIALIZABLE:防止脏读、不可重复读、虚读。
随着级别的增高,数据越安全,但效率越低。
MySQL中常用的命令:
查看当前的事务隔离级别:select@@tx_isolation;
更改当前的事务隔离级别:settransaction isolation level 四个级别;
6.数据库的锁
共享锁
一个事务开启时,使用了共享锁,其他事务也可以设置共享锁。读数据是没有问题的。
select * from XXX lock in share mode;
排他锁
一个事务开启时,使用了排他锁,其他事务只有等待
update insert 等语句会自动加排他锁
select * from XXX for update;