mysql数据库中的事务

    xiaoxiao2021-03-25  97

    1. 什么是事务:

    事务中有多个操作,这些操作的执行结果要么完全成功,要么完全失败,不可能出现一部分成功,一部分失败的情况。比如说转账业务:张三给李四转100w,那么有两个操作,一个是张三减去100w,李四加上100w,两个操作都成功,要么都失败,不能出现张三减了100w,李四没有加上100w的情况。

    2.事务的四种特性:

    原子性:事务中的操作都是不可分割的原子单位,事务中所有的操作要么全部成功,要么全部失败。

    一致性:事务执行后,数据库的状态与他的业务规则应该保持不变。比如转账业务,转账前后,两个账户的总额是不变的。

    隔离性:隔离是在并发操作中,不同事务之间应该隔离开来,使得每个并发事务都互不干扰。

    持久性:一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务,数据库马上崩溃,在数据库重新启动完,数据库中的数据也要保持不变。

    3.与事务有关的几个方法:

    connection.setAutoCommit(boolean):设置事务是否自动提交,如果设置为true,自动提交,那么每执行一条sql语句,就相当于执行一个单独的事务,就会自动提交,如果设置为false,那就相当于开启了一条事务。

    connection.commit():事务的提交。

    Connection.rollback():回滚事务。

    4.jdbc处理事务的格式:

    try {

     con.setAutoCommit(false);//开启事务…

      ….

      …

      con.commit();//try的最后提交事务

    } catch() {

      con.rollback();//回滚事务

    }

     

    5.事务的简单例子:

    以插入数据为例,同时执行插入两条数据,这两条数据要么都成功插入到数据库中,要么都不能成功的插入到数据库中。

    publicint insertUser(){

                       int count = 0;

                       String sql = "insertinto user values(?,?)";

                       PreparedStatementprepareStatement = null;

     

                       try {

                                //手动提交,也就是执行了sql语句但是不同步到数据库中,只有两个都正确,才会自动提交到数据库中。

                                connection.setAutoCommit(false);

                                prepareStatement =connection.prepareStatement(sql);

     

                                prepareStatement.setString(1,"zhang");

                                prepareStatement.setString(2,  "123456");

    //插入到数据库张三的数据,张三这个数据是数据库的主键。

                                prepareStatement.execute();

                               

                                prepareStatement.setString(1,"zhang");

                                prepareStatement.setString(2,"123456");

    //再次相数据库中插入张三这条数据时,因为张三主键已经存在了,所以执行是不成功的

                                prepareStatement.execute();

    //当第二条数据执行不成功时,就会抛出异常

                                connection.commit();

                       } catch (SQLException e) {

                                //执行不成功回滚,回滚到两条数据都没插入之前的数据库状态。

                                try {

                                         connection.rollback();

                                } catch(SQLException e1) {

                                         System.out.println("回滚失败!");

                                }

                               

                                throw newRuntimeException(e.getMessage());

                       }finally{

                                try {

                                         prepareStatement.close();

                                } catch(SQLException e) {

                                         e.printStackTrace();

                                }

                               

                                try {

                                         connection.close();

                                } catch(SQLException e) {

                                         // TODOAuto-generated catch block

                                         e.printStackTrace();

                                }

                       }

                      

                       return count;

    }

    6.事务的隔离级别:

    6.1事务的并发问题:

               脏读:读到另一个事务未提交的更新数据,即读到了脏数据。

               不可重复读:两次读取同一个数据读到的结果不一样。即另一事务修改了事务。

               幻读:对同一张表两次读到的数据不一样,应为另一条事务插入了新的记录。

    6.2不可重复读和幻读的区别:

    不可重复读是读取到了另一事务的更新;

    幻读是读取到了另一事务的插入(MySQL中无法测试到幻读)

    7.数据库内部定义了四种隔离级别,用于解决三种隔离问题

    1 Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)

    2 Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)不可以避免虚读

    3 Read committed:可避免脏读情况发生(读已提交)

    4 Read uncommitted:最低级别,以上情况均无法保证。(读未提交)

     

    操作数据库内部隔离级别

    set session transaction isolation level 设置事务隔离级别

    select @@tx_isolation   查询当前事务隔离级别

     

    实验一:演示脏读发生

    在A窗口将隔离级别设置 read uncommitted

    A、B窗口同时开启事务

    B窗口执行转账操作update account set money = money - 500 where name='bbb';

    update account set money = money + 500 where name ='aaa'; 未提交事务

    A窗口查询 select *from account; 查询到转账结果(脏读)

    B 回滚 rollback

    A窗口查询 金钱丢失

     

    实验二:演示不可重复读

    在A窗口设置隔离级别 read committed; 重复实验一,发现无法脏读

    B窗口转账后,提交事务

    A窗口查询到 B提交的数据 (不可重复读)

     

    实验三:演示阻止不可重复读发生

    在A窗口设置隔离级别 repeatable read 重复试验二,发现不会发生不可重复读

     

    实验四:演示serializable 串行事务效果

    A窗口设置隔离级别serializable

    A、B同时开启事务

    B窗口插入一条数据insert into account values(null,'ddd',1000);

    在A窗口查询数据 select * from account;

    发现A 窗口阻塞了,等待B事务执行结束

     

    安全性:serializable > repeatableread > read committed > read uncommitted

    性能 :serializable < repeatable read < read committed < readuncommitted

     

    结论: 实际开发中,通常不会选择 serializable 和 read uncommitted , mysql默认隔离级别repeatable read ,oracle默认隔离级别 read committed

     

    JDBC程序中能否指定事务的隔离级别 ?

    Connection接口中定义事务隔离级别四个常量:

    static int TRANSACTION_READ_COMMITTED

              指示不可以发生脏读的常量;不可重复读和虚读可以发生。

    static int TRANSACTION_READ_UNCOMMITTED

              指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。

    static int TRANSACTION_REPEATABLE_READ

              指示不可以发生脏读和不可重复读的常量;虚读可以发生。

    static int TRANSACTION_SERIALIZABLE

              指示不可以发生脏读、不可重复读和虚读的常量。

     

    通过 void setTransactionIsolation(intlevel) 设置数据库隔离级别

    转载请注明原文地址: https://ju.6miu.com/read-17981.html

    最新回复(0)