MYSQL中的事务

8 篇文章 0 订阅

1.1事务的特性
ACID
		原子性:事务里面的操作单元不可切割,要么全部成功,要么全部失败
		一致性:事务执行前后,业务状态和其他业务状态保持一致.
		隔离性:一个事务执行的时候最好不要受到其他事务的影响
		持久性:一旦事务提交或者回滚.这个状态都要持久化到数据库中

1.2不考虑隔离性会出现的问题

脏读:在一个事务中读取到另一个事务没有提交的数据

不可重复读:在一个事务中,两次查询的结果不一致(针对的update操作) 不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。

虚读(幻读):在一个事务中,两次查询的结果不一致(针对的insert操作) 无法演示出来,MySQL已经默认避免了

1.3MYSQL的四种隔离级别
通过设置数据库的隔离级别来避免上面的问题
	read uncommitted  	读未提交	上面的三个问题都会出现
	read committed  	读已提交	可以避免脏读的发生 Oracle 默认级别
	repeatable read		可重复读	可以避免脏读和不可重复读的发生  MySQL 默认级别
	serializable		串行化		可以避免所有的问题
1.4演示

未提交

package com.xawl.demo;
import com.xawl.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
public class MyTest {
    public static void main(String[] args) {
        //事务:生活中的事务,指的就是比较正式的事情。
        //数据库中的事务,值得是一个操作,这个操作里面可能会包含很多个步骤,那么这些步骤,是整体不可再分割的,这些步骤,要么同时成功,要么同时失败。
        //比如转账这个操作。
        // 张三给李四转钱。
        //张三的账户要扣钱 5000    -1000=4000
        //异常
        //李四的账户要加钱 2000    +1000=3000
        //数据库默认的设置,事务自动开启,自动提交
        try {
            //张三扣钱。
            Connection conn1 = JDBCUtils.getConnection();
            //数据库默认的设置,事务自动开启,自动提交
            //默认 扣钱是一个单独的事务
            PreparedStatement statement1 = conn1.prepareStatement("update bank set money=money-1000 where username='zhangsan'");
            statement1.executeUpdate();
            //模拟异常
            int i = 1 / 0;
            //李四加钱。
            Connection conn2 = JDBCUtils.getConnection();
            //数据库默认的设置,事务自动开启,自动提交
            //默认,加钱也是一个单独的事务。
            PreparedStatement statement2 = conn2.prepareStatement("update bank set money=money+1000 where username='lisi'");
            statement2.executeUpdate();
            //对于转账,这个业务逻辑,那么减钱和扣钱,必须在同一个事务中。上面默认就是减钱一个事务,扣钱也是一个事务。
            //所以我们得这么做,关闭数据库自动提交事务,由我们手动提交事务,那么这么做,我们可以把扣钱操作和加钱操作,放在同一个事务中,如果转账途中遇到异常,我们可以回滚事务。
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }
}

已提交

package com.xawl.demo;
import com.xawl.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class MyTest2 {
    public static void main(String[] args) {
        //事务:生活中的事务,指的就是比较正式的事情。
        //数据库中的事务,值得是一个操作,这个操作里面可能会包含很多个步骤,那么这些步骤,是整体不可再分割的,这些步骤,要么同时成功,要么同时失败。
        //比如转账这个操作。
        // 张三给李四转钱。
        //张三的账户要扣钱 5000    -1000=4000
        //异常
        //李四的账户要加钱 2000    +1000=3000
        //数据库默认的设置,事务自动开启,自动提交
        Connection conn1 = null;
        try {
            //张三扣钱。
            conn1 = JDBCUtils.getConnection();
            //设置数据库的隔离级别
            // conn1.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
            //设置事务不自动提交
            //将此连接的自动提交模式设置为给定状态。如果连接处于自动提交模式下,则它的所有 SQL 语句将被执行并作为单个事务提交
            //autoCommit - 为 true 表示启用自动提交模式;为 false 表示禁用自动提交模式
            conn1.setAutoCommit(false);   //set @@autocommit=0;
            //数据库默认的设置,事务自动开启,自动提交
            //默认 扣钱是一个单独的事务
            PreparedStatement statement1 = conn1.prepareStatement("update bank set money=money-1000 where username='zhangsan'");
            statement1.executeUpdate();
            //模拟异常
            int i = 1 / 0;
            //数据库默认的设置,事务自动开启,自动提交
            //默认,加钱也是一个单独的事务。
            PreparedStatement statement2 = conn1.prepareStatement("update bank set money=money+1000 where username='lisi'");
            statement2.executeUpdate();
            //对于转账,这个业务逻辑,那么减钱和扣钱,必须在同一个事务中。上面默认就是减钱一个事务,扣钱也是一个事务。
            //所以我们得这么做,关闭数据库自动提交事务,由我们手动提交事务,那么这么做,我们可以把扣钱操作和加钱操作,放在同一个事务中,如果转账途中遇到异常,我们可以回滚事务。
        } catch (Exception e) {
            e.printStackTrace();
            //遇到任何异常,我们都要回滚事务。
            try {
                conn1.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            //手动提交事务
            try {
                conn1.commit(); //手动提交事务
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    /*
    *  set @@autocommit=0; //设置事务手动提交
  SHOW VARIABLES like '%autocommit%';
   START transaction ;  -- 手动开启事务
SELECT * from emp WHERE id='06c4c8b4cc0640f6848696aaa0cb5f2b' for update;
rollback -- 回滚事务
COMMIT; -- 提交事务
*  注意;数据定义语言(DDL)语句不能被回滚
* */
}
1.5补充
演示脏读的发生:
			将数据库的隔离级别设置成 读未提交
				set session transaction isolation level read uncommitted;
			查看数据库的隔离级别
				select @@tx_isolation;
			演示:
			打开两个窗口进行演示:给两个窗口设置好同的隔离级别
			开启事务  start transaction;
			修改数据:update bank set money=1500 where username='lisi';
			让另一个窗口开启事务 查询数据 他查到了  就是脏读
			我这边窗口 一回滚(rollback),钱又没过去
避免脏读的发生,将隔离级别设置成  读已提交
	set session transaction isolation level read committed;
	不可避免不可重复读的发生.
	
避免不可重复读的发生 经隔离级别设置成 可重复读
	set session transaction isolation level  repeatable read;
			
演示串行化 可以避免所有的问题
	set session transaction isolation level  serializable;  
	我这边的事务不提交,那边的事务无法执行锁表的操作. 
		
四种隔离级别的效率
		read uncommitted>read committed>repeatable read>serializable
四种隔离级别的安全性
		read uncommitted<read committed<repeatable read<serializable
		
开发中绝对不允许脏读发生.
		mysql中默认级别:repeatable read
		oracle中默认级别:read committed

java中控制隔离级别:
		Connection的api
			void setTransactionIsolation(int level) 
				level是常量
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Geek Li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值