数据库事务

数据库事务 : 一组逻辑操作单元,使数据从一种形态到另一种形态

**事务处理:**保证所有的事务作为一个工作单位来执行,即使出现了故障都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交,永久的保存下来,要么所有的事务全部回滚到最初事务开启之前的状态 ( 事务要不全部成功,要不全部失败)

注意点: 事务一旦提交,便无法回滚
什么操作会导致事务提交

  1. DDL(数据定义语言 如CREATE、ALTER、DROP) 操作会导致事务提交
  2. DML(数据操纵语言 如SELECT、UPDATE、INSERT、DELETE,)默认执行就提交,不过可以进行修改(通过 set autocommit = false进行修改)
  3. 默认关闭数据库连接时也会提交

事务代码(错误写法)

  //  通用增删改
    public static  void update(String sql, Object ... args) {
        Connection connection = null ;
        PreparedStatement ps = null;
        try
        {
            //  1.获取数据库连接
             connection = getConnection();
            //  2.获取PreparedStatement
             ps = connection.prepareStatement(sql);
            //  3.填充占位符,
            for (int i = 0; i <args.length ; i++)
            {
                ps.setObject((i+1), args[i]);
            }
            //  4.执行
            ps.execute();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            //  5.关闭
            closes(connection , ps);
        }


    }

	@Test
    public void test2(){
        String sql1 = "update dome4 set balance = balance -100 where name = ?";
        JdbcUtil.update(sql1,"zs");

        //  在此过程中模拟中途发送了错误
        System.out.println(10/ 0);


        String sql2 = "update dome4 set balance = balance +100 where name = ?";
        JdbcUtil.update(sql2,"ls");
    }

执行前
在这里插入图片描述
执行后
在这里插入图片描述

正确写法

//  和事务有关的通用增删改
    public static  void updateTx( Connection connection ,String sql, Object ... args) {
        PreparedStatement ps = null;
        try
        {
            //  1.获取PreparedStatement
            ps = connection.prepareStatement(sql);
            //  2.填充占位符,
            for (int i = 0; i <args.length ; i++)
            {
                ps.setObject((i+1), args[i]);
            }
            //  3.执行
            ps.execute();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            //  4.关闭
            closes(null , ps);
        }


    }

@Test
    public void  test1 (){
        Connection connection = null;
        try
        {
            //  1.获取连接
             connection = JdbcUtil.getConnection();
            //  事务 : zs 用户余额减100, ls用户余额加100

            //  2.设置事务DML事务不自动提交
            connection.setAutoCommit(false);

            //  3.开启事务操作
            String sql1 = "update dome4 set balance = balance -100 where name = ?";
            JdbcUtil.updateTx(connection,sql1,"zs");

            //  在此过程中模拟中途发送了错误
            System.out.println(10/ 0);


            String sql2 = "update dome4 set balance = balance +100 where name = ?";
            JdbcUtil.updateTx(connection,sql2,"ls");

            System.out.println("转账成功");
            //  4.事务处理完成提交事务
            connection.commit();

        }
        catch (Exception e)
        {
            //   如果出现异常回滚操作
            try
            {
                connection.rollback();
            }
            catch (SQLException ex)
            {
                ex.printStackTrace();
            }
        }
        finally
        {
            JdbcUtil.closes(connection,null);
        }


    }

执行前
在这里插入图片描述
执行后
在这里插入图片描述
原因:设置了DML操作数据库的自动提交事务,因为前一种方法我们在每一次执行sql语句的时候就把连接关闭了,关闭连接会自动提交,当是第二种方法,我们在事务全部操作完毕之后再关闭连接,出现错误就回滚事务,所以在出现错误的时候,下面那一条sql语句并没有执行,也并没有提交,并跑到catch里面进行事务的回滚。

事务的ACID属性

  1. 原子性(Atomicity):指的是事务是一个不可分割的单位,事务中的操作要不都发生,要不都不发生
  2. 一致性(Consistency):事务必须使数据库从一个一致性到另一个的一致性状态
  3. 隔离性(Isolation):事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  4. 持久性(Durability):持久性是指一个事务一旦被提交 。它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。

数据库并发问题

概念:对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题。
数据库并发问题:

  1. 脏读:二个事务T1,T2如果事务T1读取了事务T2更新了并且没有提交的数据,如果T2事务在此时回滚了事务,那么T1读取到T2更新的数据是无效的
  2. 不可重复读:二个事务T1,T2,当T1得到了T2的数据之后,T2更新了数据,当是T1在去获取相同的字段,获取的值就会有所不同
  3. 幻读:对于二个事务T1,T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行,之后,如果T1在去读取那个表就会多出现几行

数据库的四种隔离级别

  1. 读未提交(Read uncommitted):最低级别的隔离,允许事务读取未被其他事物提交的变更。脏读,不可重复读和幻读的问题都会出现
  2. 读取已提交(Read committed,Oracle、PostgreSQL、SQL Server默认模式):只允许事务读取已经被其它事务提交的变更.可以避免脏读,但不可重复读和幻读问题仍然可能出现
  3. 可重复读(Repeatable read,MySQL默认模式):确保事务可以多次从一个字段中读取相同的值在这个事务持续期间,禁止其他事物对这个字段进行更新可以避免脏读和不可重复读,但幻读的问题仍然存在
  4. 串行化(Serializable,SQLite默认模式):最高级别的隔离,确保事务可以从一个表中读取相同的行在这个事务持续期间,禁止其他事务对该表执行插入,更新和删除操作,所有并发问题都可以避免,但性能十分低下。

注意点 :隔离级别越高,数据一致性就越好, 但并发性越弱。

Java代码层面控制数据库的隔离级别

connection.setTransactionIsolation(Connection.TRANSACTION_NONE);
Connection的五种取值

  1. TRANSACTION_NONE (0) :表示不支持事务的常量。
  2. TRANSACTION_READ_UNCOMMITTED (1):读未提交
  3. TRANSACTION_READ_COMMITTED (2):读取已提交
  4. TRANSACTION_REPEATABLE_READ (4):可重复读
  5. TRANSACTION_SERIALIZABLE (8): 串行化
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值