3、数据库事务、自动提交与手动提交、事务回滚

事务

简介

事务指一组最小逻辑操作单元,里面有多个操作组成。组成事务的每一部分必须要同时提交成功,如果有一个操作失败,整个操作就回滚。

事务ACID特性
1、原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2、一致性(Consistency)
事务的一致性是指事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。 通俗的说:我和你的钱加起来一共是2000,那么不管我和你之间如何转账,转几次账,事务结束后我们的钱相加起来应该还得是2000,这就是事务的一致性。
3、隔离性(Isolation)
指多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。 通俗的说:多个用户并发访问操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
4、持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

默认情况下,Connection 对象处于自动提交模式下,这意味着它在执行每个语句后都会自动提交更改。

如果禁用了自动提交模式,那么要提交更改就必须显式调用commit 方法,否则无法保存数据库更改。

如果连接处于自动提交模式下,则它的所有 SQL 语句将被执行并作为单个事务提交。否则,它的 SQL 语句将聚集到事务中,直到调用 commit 方法或 rollback 方法为止。默认情况下,新连接处于自动提交模式。

事务的引入

1、数据表准备

CREATE TABLE IF NOT EXISTS bank(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20) NOT NULL,
	money INT NOT NULL
);
INSERT INTO bank VALUES(NULL, '张三', 1000),(NULL, '李四', 1000);

2、转账

package org.westos.demo3;

import org.westos.util.JDBCUtil;

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

/**
 * @author lwj
 * @date 2020/8/11 15:41
 */
public class MyTest {
    public static void main(String[] args) throws SQLException {
        //事务:一组SQL语句,要么同时成功,要么同时失败
        /*
        转账:必须用到事务操作,张三-100,李四+100要么同时成功,要么同时失败,不能张三-100,而李四没有+100
        张三-100
        异常
        李四+100
         */
        Connection conn1 = JDBCUtil.getConnection();
        Connection conn2 = JDBCUtil.getConnection();
        PreparedStatement ps1 = conn1.prepareStatement("update bank set money = money - 100 where id = 1");
        PreparedStatement ps2 = conn2.prepareStatement("update bank set money = money + 100 where id = 2");
        //事务默认自动提交,两个操作分属两个不同的事务

        ps1.executeUpdate();
        //模拟异常:ps1事务提交了,但是ps2事务还没提交
        int i = 10 / 0;
        ps2.executeUpdate();

        JDBCUtil.close(ps1, conn1);
        JDBCUtil.close(ps2, conn2);
    }
}

在这里插入图片描述

转账

恢复bank表中数据为1000与1000。

1、正常转账

package org.westos.demo3;

import org.westos.util.JDBCUtil;

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

/**
 * @author lwj
 * @date 2020/8/11 16:01
 */
public class MyTest2 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = JDBCUtil.getConnection();
            conn.setAutoCommit(false);
            //设置手动提交事务

            ps = conn.prepareStatement("update bank set money = money - 100 where id = 1");
            ps.executeUpdate();

            ps = conn.prepareStatement("update bank set money = money + 100 where id = 2");
            ps.executeUpdate();

            //手动提交事务
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        } finally {
            try {
                JDBCUtil.close(ps, conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

2、异常转账

package org.westos.demo3;

import org.westos.util.JDBCUtil;

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

/**
 * @author lwj
 * @date 2020/8/11 16:01
 */
public class MyTest2 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = JDBCUtil.getConnection();
            conn.setAutoCommit(false);
            //设置手动提交事务

            ps = conn.prepareStatement("update bank set money = money - 100 where id = 1");
            ps.executeUpdate();

            int i = 100 / 0;

            ps = conn.prepareStatement("update bank set money = money + 100 where id = 2");
            ps.executeUpdate();

            //手动提交事务
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //一旦遇到异常,则回滚事务,不再执行commit
            try {
                conn.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        } finally {
            try {
                JDBCUtil.close(ps, conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

异常转账过后,事务回滚,没有commit操作,也就不会有转账,money字段保持不变。

在这里插入图片描述

恢复bank表中数据为1000与1000。

3、事务回滚到回滚点

package org.westos.demo3;

import org.westos.util.JDBCUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;

/**
 * @author lwj
 * @date 2020/8/11 16:01
 */
public class MyTest2 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        Savepoint point = null;
        try {
            conn = JDBCUtil.getConnection();
            conn.setAutoCommit(false);
            //设置手动提交事务

            //第一次转账
            ps = conn.prepareStatement("update bank set money = money - 100 where id = 1");
            ps.executeUpdate();

            ps = conn.prepareStatement("update bank set money = money + 100 where id = 2");
            ps.executeUpdate();

            point = conn.setSavepoint();
            //设置回滚点
            
            //第二次转账
            ps = conn.prepareStatement("update bank set money = money - 100 where id = 1");
            ps.executeUpdate();
            int i = 100 / 0;
            ps = conn.prepareStatement("update bank set money = money + 100 where id = 2");
            ps.executeUpdate();

            //手动提交事务
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //一旦遇到异常,则回滚事务
            try {
                conn.rollback(point);
                //回滚到指定的回滚点
                conn.commit();
                //如果此处不提交事务,那么将没有机会提交
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        } finally {
            try {
                JDBCUtil.close(ps, conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

在第一次转账与第二次转账之间设置一个回滚点,当发生异常时,事务回滚到回滚点之前的状态。

而且在rollback之后需要有一次commit操作。
在这里插入图片描述

当取消设置回滚点,而发生异常时,默认回滚到初始状态,即1000-1000。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值