数据库事务

数据库事务:

         数据库事务(DatabaseTransaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行

1.事务有什么用:

正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。

数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术。

mysql管理事务

方式一:

         starttracsaction 开启事务

         rollback事务回滚 (将数据恢复到事务开始的操作)

         commit事务提交 (对事务中的操作,进行确认提交,事务在提交后,数据就不可恢复)

        

         注意:mysql中事务默认自动提交的,每当执行一条SQL 就会提交一个事务。

         Oracle中事务默认 不自动提交,需要在执行SQL语句后,通过commit手动提交

 

方式二:

         setautocommit = off; 关闭自动提交

         相当于每条SQL执行前都加上了 starttransaction

2.事务回滚点的设置

JDBC提供事务回滚点接口Savepoint ,如果在事务中进行savepoint设置,可以在事务回滚时,回滚到指定回滚点。

//事务回滚点
  @Test
  public void demo2() {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    //事务回滚点
    Savepoint savepoint = null;
    try {
        connection = JDBCUtils.getConnection();
        connection.setAutoCommit(false);    // start transaction 开启事务
        savepoint = connection.setSavepoint();
  
        String sql = "insert into user values(?,?,?)";
        preparedStatement = connection.prepareStatement(sql);
  
        for (int i = 1; i < 901; i++) {
  
            //数据在插入 788条的时候报错了。
            if(i == 788) {
                int a = i / 0;
            }
  
            //设置参数
            preparedStatement.setInt(1,i);
            preparedStatement.setString(2,"name "+i);
            preparedStatement.setString(3,"password "+i);
            //加入队列
            preparedStatement.addBatch();
  
            //每隔300条向数据库中发送一次
            if(i % 300 ==0) {
                preparedStatement.executeBatch();
                preparedStatement.clearBatch();
            }
  
            //每个500条数据设置一个事务回滚点
            if(i % 500 ==0) { 
                preparedStatement.executeBatch();
                preparedStatement.clearBatch();
                savepoint = connection.setSavepoint();
            }
        }
  
        //执行剩余记录
        preparedStatement.executeBatch();
  
        //没有异常提交事务
        connection.commit();
  
  
    }catch (Exception e) {
        //事务回滚
        try {
            connection.rollback(savepoint);
            //提交回滚点之前所保存的数据
            connection.commit();
        }catch (SQLException e1) {
            e1.printStackTrace();
        }
        e.printStackTrace();
    }finally {
        JDBCUtils.release(null,preparedStatement,connection);
    }
}

 

3.事务的四大特性

4.1 原子性(Atomicity)

         事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处理操作子集的可能性。事务中的操作不可分割,要么全部成功,要么都失败。

4.2 一致性(consistency)

         事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。某些维护一致性的责任由应用程序开发人员承担,他们必须确保应用程序已强制所有已知的完整性约束。例如,当开发用于转帐的应用程序时,应避免在转帐过程中任意移动小数点。

       例如:

              在公司里面会有部门,部门下面会有员工,如果这个时候把财务部门删除了,那么财务部门下面的员工就会失去组织,就破坏了数据的一致性。

4.3 隔离性(Isolation)

         并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为隔离性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。当事务可序列化时将获得最高的隔离级别。在此级别上,从一组可并行执行的事务获得的结果与通过连续运行每个事务所获得的结果相同。由于高度隔离会限制可并行执行的事务数,所以一些应用程序降低隔离级别以换取更大的吞吐量。

       例如:多个事务同时操作一条数据记录,事务之间应该不互相影响,事务之间应该进行隔离。

4.3.1 隔离性引发的问题

如果数据库不考虑并发线程事务访问的隔离,那么将会引发那些问题?(一般指的是对数据进行修改,更新,或者删除)

4.3.1.1 脏读

         定义:一个事务读取到另一个事务未提交的数据

         张三:给李四转账 100元,未提交(commit)

         李四:查询多了100块钱

         张三:回滚(rollback)

         李四:查询100块钱没了

4.3.1.2 不可重复读

定义:在一个事务先后两次读取发生数据不一致的情况,第二次读取到了另一个事务已经提交的数据(强调数据的更新)

张三:查询账户10000块钱

李四:给张三转了5000块钱

张三:查询15000块钱

4.3.1.3 虚读(幻读)

定义:在一个事务中,第二次读取发生数据记录数的不同,读取到灵一个事务已经提交的数据(强调数据记录的变化(inesrt))

张三:读取user表发现有5条记录

李四:向user表插入了一条记录

张三:读取user表发现存在6表记录

4.3.2 数据库的隔离级别

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

1.      read uncommitted最低级别,允许以上三类情况的发生。

2.      read committed不会发生脏读,允许不可重复读和虚读的发生。

3.      repeatable read不会发生脏读,和不可重复读,允许虚拟发生

4.      serializable 事务最高级别,所有事务操作是串行化的不存在并发问题。

 

操作数据库内部隔离级别

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

set session transaction isolation level 设置隔离级别  

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

性能: serializable<repeatable read<readcommitted<read uncommitted

 

Mysql默认的级别是repeatable read 

Oracle默认的级别是 read committed


4.4 持久性(durability)

事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持,一旦提交事务之后数据将会永久改变。

5 事务的丢失更新

5.1 什么是丢失更新

两个事务或多个事务更新同一条数据,但这是事务彼此之间都不知道其他事务在进行修改,因为后面修改的会覆盖前面修改的数据。

5.2 如何解决丢失更新

         悲观锁(Pessimistic Lock)        

         乐观锁(Optimistic Lock)

悲观锁

悲观锁的实现,往往依靠数据库提供的锁机制

         mysql数据库内部提供两种常用锁机制:共享锁(读锁)和排它锁(写锁)

共享所:允许一张数据表中数据记录,添加多个共享锁,添加共享锁记录,对于其他事务可读不可写的。

排它锁:一张数据表中数据记录,只能添加一个排它锁,在添加排它锁的数据不能再添加其他共享锁和排它锁的 ,对于其他事物可读不可写的

         注意:只要是对数据加锁之后该数据就是可读不可写。

*** 所有数据记录修改操作,自动为数据添加排它锁

 

添加共享锁方式:select * fromaccount lock in share mode ;

添加排它锁方式:select * fromaccount for update;

* 锁必须在事务中添加,如果事务结束了锁就释放了

解决丢失更新:事务在修改记录过程中,锁定记录,别的事务无法并发修改

乐观锁

 乐观锁机制采取了更加宽松的加锁机制。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。相对悲观锁而言,乐观锁更倾向于开发运用.

采用记录的版本字段,来判断记录是否修改过-------------- timestamp

timestamp 可以自动更新

create table test (

   idint,

   versionTIMESTAMP

);

 

 

* timestamp 在插入和修改时 都会自动更新为当前时间

 

解决丢失更新:在数据表添加版本字段,每次修改过记录后,版本字段都会更新,如果读取是版本字段,与修改时版本字段不一致,说明别人进行修改过数据(重改)





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

brid_fly

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

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

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

打赏作者

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

抵扣说明:

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

余额充值