数据库事务

数据库事务

指的是一组最小的逻辑操作单元,组成事务的每一个部分,要么全部执行,如果有某一步执行行错误,整个操作,要回滚到最初开始的状态。
事务的4大特性

  • 原子性
    事务是不可分割的,组成事务的每个部分,要么同时成功, 要么同时失败。
  • 一致性
    事务从一种状态 变换成另一种状态,结果的总和是一样的。比如转账,两边加起来的钱是一样的。
  • 隔离性
    并发访问的时候,一个事务不受其他事务的影响
  • 持久性
    事务一旦被提交,对数据库的改变是永久的。

例如: bank银行用户表
在这里插入图片描述
现在张三要给李四转1000块钱
正常情况如下:

package com.jingfei.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class Transaction {
	public static void main(String[] args) throws Exception{
		Class.forName("com.mysql.jdbc.Driver");
		Connection connection = DriverManager.getConnection("jdbc:mysql:///mydb", "root", "123456");
		//禁止自动提交,将sql语句聚集到一个事务中
		connection.setAutoCommit(false);
		//张三给李四转1000块钱
		String sql="update bank set money=money-1000 where username='张三'";
		String sql2="update bank set money=money+1000 where username='李四'";
		PreparedStatement statement=connection.prepareStatement(sql);
		PreparedStatement statement2=connection.prepareStatement(sql2);
		statement.executeUpdate();
		statement2.executeUpdate();
		//提交事务
		connection.commit();
		//释放资源
		connection.close();
		statement.close();
		statement2.close();
		
	}
}

若中途出错需要回滚到初始状态


package com.jingfei.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Transaction {
	static Connection connection=null;
	static PreparedStatement statement=null;
	static PreparedStatement statement2=null;
	public static void main(String[] args) {
		try {
			Class.forName("com.mysql.jdbc.Driver");
			connection = DriverManager.getConnection("jdbc:mysql:///mydb", "root", "123456");
			//禁止自动提交,将sql语句聚集到一个事务中
			connection.setAutoCommit(false);
			//张三给李四转1000块钱
			String sql="update bank set money=money-1000 where username='张三'";
			String sql2="update bank set money=money+1000 where username='李四'";
			statement=connection.prepareStatement(sql);
			statement2=connection.prepareStatement(sql2);
			statement.executeUpdate();
			//手动制造错误
			System.out.println(1/0);
			statement2.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
			//若注释掉以下try catch的话,发生错误后不回滚,就会发现张三少了1000,但李四并没有加上1000.
			try {
				//发生错误回滚到初始状态
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}finally {
			
			try {
				//手动提交事务
				connection.commit();
				//释放资源
				connection.close();
				statement.close();
				statement2.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
				
		}
		
	}
}

也可以设置回滚点
Savepoint savepoint = conn.setSavepoint();//z爱事务前设置一个回滚点
conn.rollback(savepoint);在发生错误的时候回滚到回滚点


数据库隔离级别

  • 按照隔离级别由低到高
    read uncommited<read comited <repeatable read <serializable
  • 查看数据库隔离级别
    select @@tx_isolation
    mysql默认为REPEATABLE-READ
    oracle默认READ COMMITED

级别read uncommited 不能避免脏读,

  • 一个事务中可以读到另一个事务未提交(没有持久化)的数据

级别read commited 可以避免脏读

  • 但在一个事务中读取的结果会出现不同,也叫(不可重复读)。就是在一个李四有一个事务查看自己的钱,张三有一个事务转钱给李四1000,但是张三并没有提交的时候让李四查一下,李四查看了后说钱没到,然后张三说你别急,然后张三执行了commit提交,然后再让李四查看,李四说钱到了。就是再一个事务中 查询结果不同。

级别repeatable read 可以避免不可重复读

  • 在一次事务中两次读取的结果一致,即李四两次读取的结果都是张三没转钱给他,张三说你把卡拔下重新插一下(重新一个事务)就好了,李四照做,就可以查看到张三转来了1000块钱。

级别serializable 可以避免所有问题,会锁表,效率低,这边事务不提交,另一边一直处于等待查询状态。


谢谢

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值