事物的概念
事务由单独单元的一个或多个SQL语句组成,在这个单元中,每个MySQL语句是相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中某条SQL语句一旦执行失败或产生错误,整个单元将会回滚。所有受到影响的数据将返回到事物开始以前的状态;如果单元中的所有SQL语句均执行成功,则事物被顺利执行。
事物的四个特征
原子性(Atomicity):
事务中的所有元素作为一个整体提交或回滚,事务的个元素是不可分的,事务是一个完整操作。
一致性(Consistemcy):事物完成时,数据必须是一致的,也就是说,和事物开始之前,数据存储中的数据处于一致状态。保证数据的无损。(实际产生的结果逻辑上必须正确,在转账的例子中,钱的总额不变)
隔离性(Isolation):对数据进行修改的多个事务是彼此隔离的。这表明事务必须是独立的,不应该以任何方式以来于或影响其他事务。(通过锁来保证)
持久性(Durability):事务完成之后,它对于系统的影响是永久的,该修改即使出现系统故障也将一直保留,真实的修改了数据库(持久化操作,文件层面的修改)
一致性(Consistemcy):事物完成时,数据必须是一致的,也就是说,和事物开始之前,数据存储中的数据处于一致状态。保证数据的无损。(实际产生的结果逻辑上必须正确,在转账的例子中,钱的总额不变)
隔离性(Isolation):对数据进行修改的多个事务是彼此隔离的。这表明事务必须是独立的,不应该以任何方式以来于或影响其他事务。(通过锁来保证)
持久性(Durability):事务完成之后,它对于系统的影响是永久的,该修改即使出现系统故障也将一直保留,真实的修改了数据库(持久化操作,文件层面的修改)
事务的语句
开始事物:BEGIN TRANSACTION
提交事物:COMMIT TRANSACTION
回滚事务:ROLLBACK TRANSACTION
提交事物:COMMIT TRANSACTION
回滚事务:ROLLBACK TRANSACTION
一个验证数据库事物的小例子
在银行转账的例子中,,
show databases;
显示已存在的数据库,收款方银行卡余额增加,付款方银行卡余额减少。对应于数据库的两个update操作,这两个操作要么都完成,要么都不完成。
关于默认数据库的作用,请参考MySQL安装后默认自带数据库的作用
创建相关的数据库表:
create database Test_Transaction; //创建数据库
use Test_Transaction; //切换表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
balance NUMERIC(10.2)
);
desc account; //查看表的结构
INSERT INTO account(NAME,balance) VALUES('zs', 100000);
INSERT INTO account(NAME,balance) VALUES('ls', 100000);
INSERT INTO account(NAME,balance) VALUES('ww', 100000);
SELECT * FROM account;
public class JDBC {
public static void main(String[] args) {
Transaction();
}
//获得连接
private static Connection getConn() {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/Test_Transaction";
String username = "root";
String password = "mysql";
Connection conn = null;
try {
Class.forName(driver); //classLoader,加载对应驱动
conn = (Connection) DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void Transaction(){
Connection conn = null;
PreparedStatement ps= null;
Savepoint savepoint = null;
try {
//获得连接
conn = getConn();
//设置不自动提交
conn.setAutoCommit(false);
//执行操作
updatePassword();
//设置回滚点
savepoint = conn.setSavepoint();
BringMoney();
//提交事务
conn.commit();
}catch (Exception e){
try {
//回滚事物
conn.rollback(savepoint);
}catch (SQLException sqlException){
sqlException.printStackTrace();
}
e.printStackTrace();
}finally {
try {
conn.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void BringMoney() throws Exception{
Connection conn = null;
PreparedStatement ps= null;
String sql ="UPDATE account SET balance=balance+? WHERE id=?;";
//预编译
ps = conn.prepareStatement(sql);
//设置第一个参数
ps.setInt(1,1000);
//设置第二个参数
ps.setInt(2,1);
ps.executeUpdate();
/***
* 假如此处出现了异常
*/
//int a= 10/0;
ps.setInt(1,-1000);
//设置第二个参数
ps.setInt(2,2);
ps.executeUpdate();
}
public static void updatePassword() throws Exception{
Connection conn = null;
PreparedStatement ps= null;
String sql ="UPDATE account SET password=? WHERE id=?;";
//预编译
ps = conn.prepareStatement(sql);
//设置第参数
ps.setInt(1,123456);
ps.setInt(2,1);
ps.executeUpdate();
}
}
事物的四大特性和隔离级别
四大特性
脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
开启事物,并执行update操作
START TRANSACTION;
UPDATE account SET balance=balance-10000 WHERE id=1;
在事物提交之前,执行查询操作
此时用可视化工具,查看数据库
可以发现,查询的结果和数据库实际的结果并不一致,产生了脏读现象
不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
虚读(幻读)
隔离级别
Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
Repeatable read (可重复读):可避免脏读、不可重复读的发生。
Read committed (读已提交):可避免脏读的发生。
Read uncommitted (读未提交):最低级别,任何情况都无法保证
相关的sql语句
查看当前数据库表的隔离级别
select @@tx_isolation;
设置事物的隔离级别
set tx_isolation=’隔离级别名称;’