MySql事务(JDBC手动控制事务 事务的特性 事务的隔离级别)

MySql事务

事务的概述:

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。
事务案例:
A–B转账,有以下两条sql语句:
update count set money=money+100 where name=’aaa’;
update count set money=money-100 where name=’bbb’;
其中一条sql语句失败,则在此事务内的其他sql语句全部失败,要么一起成功,要么一起失败

Mysql中的事务

a、mysql引擎是支持事务的
b、mysql默认自动提交事务。每条语句都处在单独的事务中。
c、手动控制事务
开启事务:start transaction | begin conn.setAutoCommit(false);
提交事务: commit conn.commit();
回滚事务: rollback conn.rollback();

JDBC事务

JDBC事务是由Connection对象所控制的,它提供了两种事务模式:自己主动提交和手动提交,默认是自己主动提交。

   自己主动提交就是:在JDBC中。在一个连接对象Connection中。默认把每一个SQL语句的运行都当做是一个事务(即每次运行完SQL语句都会马上将操作更新到数据库)。

   手动提交就是:当须要一次性运行多个SQL语句,将多个SQL语句组成一个事务(即要么都成功,要么回滚全部的操作)时,就得手动提交。

在命令行中观察主动提交:

进入mysql:

mysql -u 用户名 -p 密码

这里写图片描述
进入holiday数据库:

use holiday;

这里写图片描述
在mysql直接写一个sql语句(所以是默认自动提交的):
执行前

这里写图片描述
这里写图片描述

执行后:
这里写图片描述

在命令行中观察手动提交:

开启事务:

start transaction|begin

这里写图片描述
这里写图片描述

因为开启事务后并没有commit(提交),所以即使内存中数据变化了,但是没有提交,并没有存盘,所以表的数据依然没有变化!
这里写图片描述

在JDBC中实现事务:

代码:
没有手动控制事务(执行事务前):
这里写图片描述
代码:

package commons;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestTransaction {
    public static void main(String[] args){
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = DBCPUtils.openConnection();
            ps = conn.prepareStatement("update count set money=money-100 where name='aaa'");
            ps.execute();
            int i=10/0;//在两条sql语句中间出现异常
            ps = conn.prepareStatement("update count set money=money+100 where name='bbb'");
            ps.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBCPUtils.closeConnection(conn,ps,null);
        }
    }

}

执行结果:
aaa执行了sql语句,bbb没执行
aaa给bbb转账100元,aaa少钱了,bbb的钱确没多!
这里写图片描述

修改后,手动控制事务,一个事务中的所有sql语句失败一起失败,成功一起成功

conn.setAutoCommit(false);//相当于开启事务 begin
 conn.commit();//相当于 提交事务
conn.rollback();//回滚事务  rollback

代码:

package commons;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestTransaction {
    public static void main(String[] args){
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = DBCPUtils.openConnection();
            conn.setAutoCommit(false);//相当于开启事务 begin
            ps = conn.prepareStatement("update count set money=money-100 where name='aaa'");
            ps.execute();
            int i=10/0;//在两条sql语句中间出现异常
            ps = conn.prepareStatement("update count set money=money+100 where name='bbb'");
            ps.execute();
            conn.commit();//相当于 提交事务
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();//只要出现异常  回滚事务  rollback
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }finally {
            DBCPUtils.closeConnection(conn,ps,null);
        }
    }

}

事务的特性(面试题)

原子性:事务是一个整体,事务中的操作要么都发生,要么都不发生;
一致性:事务必须要使数据库从一个一致性状态转换到另外一个一致性状态,即转账的总金额不变;
隔离性:多个用户并发访问数据库时,多个并发事务之间要相互隔离,谁也别影响谁;
持久性:指一个事务一旦被提交,它对数据库的改变就是永久的,即使数据库发生故障也不应该对其有任何影响。即提交后必须存盘。

事务的隔离级别

1.脏读:用户当前操作的事务读到了另一个事务未提交的数据

例子:
我现在正在取钱,账户里有500,我没有提交取钱的这个事务的时候,一哥们正好现在要给我转账,他给我转300,但他也没有提交,就给我打了电话,老王我给你转账了300,我一看账户当前余额800,我说好的。然后这哥们啪,rollback了,我一看账户500……
这就是读到了别人没有提交的脏数据

2.不可重复读和虚读(幻读)很类似,一个是由update导致的,一个是由insert导致的

2.1 不可重复读:我当前操作的事务还没完成提交,就读取到了另一个事务提交到的数据。(update)
2.2 虚读(幻读):我当前操作的事务还没完成提交,就读取到了另一个事务插入提交的数据。(insert)

数据库通过设置事务的隔离级别防止以上情况的发生:(有可能发生,不是一定发生
* 1、READ UNCOMMITTED: 赃读、不可重复读、虚读都有可能发生。
* 2、READ COMMITTED: 避免赃读。不可重复读、虚读都有可能发生。(oracle默认的)
* 4、REPEATABLE READ:避免赃读、不可重复读。虚读有可能发生。(mysql默认)
* 8、SERIALIZABLE: 避免赃读、不可重复读、虚读。
级别越高,性能越低,数据越安全

mysql中:
查看当前的事务隔离级别:SELECT @@TX_ISOLATION;
更改当前的事务隔离级别:SET TRANSACTION ISOLATION LEVEL 四个级别之一。
设置隔离级别必须在事务之前


一、事务隔离级别为read uncommitted

脏读,不可重复读,虚读都有可能发生
查看mysql默认事务隔离级别:
这里写图片描述
设置当前事务隔离级别 (在开启事务之前设置) read uncommmitted(脏读 不可重复读 虚读都有可能发生;因为读取到了没有提交的数据):
这里写图片描述

进入数据库,读取当前数据:
这里写图片描述

开启另一个事务(线程)操作同一个数据,但是没有提交:
这里写图片描述

结果读取到脏数据,没有提交,另一个事务却读取到了提交后的数据:
这里写图片描述

哥们我转账给你了啊,却没提交,rollback后,一脸懵逼:
这里写图片描述

二、事务隔离级别为read committed

避免了脏读,但是不可重复读和虚读都有可能发生

发生不可重复读:
设置事务隔离级别为read committed后
开启事务A,查询count表
再开启一个事务update B,并commit
事务A还没commit就可查询到事务B提交的数据
会导致事务A的查询的数据一致变化,干扰到了事务A
这里写图片描述

发生虚读:
设置事务隔离级别为read committed后
开启事务A,查询count表
再开启一个事务Binsert,并commit
事务A还没commit就可查询到事务B提交的数据
会导致事务A的查询的数据一致变化,干扰到了事务A
这里写图片描述

三、事务隔离级别为repeatable read

避免脏读 不可重复读 虚读可能发生
这里写图片描述

四、事务隔离级别为serializable

避免脏读 不可重读读 虚读 (最高级别)
只要当前事务不commit ,其他事务都不会执行
这里写图片描述

JDBC控制事务的隔离级别

这里写图片描述
READ UNCOMMITTED 等级: 1
READ COMMITTED 等级:2
REPEATABLE READ 等级:4
SERIALIZABLE 等级:8

如何在java程序中控制事务的隔离级别;
在开启事务前设置:
Connection.setTransactionIsolation(int level);

但是一般不用写
因为Oracle mysql已经自动设置好了级别

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值