JDBC中的事务回滚

事务回滚

  • 理解:防止出现未知错误,导致原先要执行完全的数据只执行了一半,最终影响数据,也就是 事务是一组组合成逻辑工作单元的操作,虽然系统中可能会出错,但事务将控制和维护事务中每个操作的一致性完整性

  • 事务遵循ACID原则

    1. 原子性:要么全部完成,要么都不完成
    2. 一致性:总数不变
    3. 隔离性:多个进程互不干扰
    4. 持久性:一旦提交不可逆,即持久化到数据库
  • 下面在实例中体现事务回滚的作用,假设现在有个转账业务

  • 且有如下的用户信息:
    JDBC中的事务回滚_第1张图片

  • 当我们想要对这个表进行如下操作:

    1. stu_id=1的用户stu_salary+1000
    2. stu_id=3的用户stu_salary-1000

正常执行的code:

package com.mystudy.jdbc;

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

public class Affair {
    public static void main(String[] args) {
        Connection conn= null;
        PreparedStatement ps= null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test1?useSSL=true","root","root");
            String sql1="UPDATE student SET stu_salary=stu_salary+1000 WHERE stu_id=1";
            ps = conn.prepareStatement(sql1);
            ps.executeUpdate();
            String sql2="UPDATE student SET stu_salary=stu_salary-1000 WHERE stu_id=3";
            ps = conn.prepareStatement(sql2);
            ps.executeUpdate();
            System.out.println("执行成功");
        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        finally {
            //资源释放
            try {
                ps.close();
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

  • 结果:

JDBC中的事务回滚_第2张图片
注:很成功!

第一个执行第二个未执行的code:

  • 假设有未知原因这里将未知原因显式的定义成:int x=1/0;从而导致第一个执行,第二个尚未执行的code:
package com.mystudy.jdbc;

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

public class Affair {
    public static void main(String[] args) {
        Connection conn= null;
        int a = 0,b=0;
        PreparedStatement ps= null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test1?useSSL=true","root","root");
            String sql1="UPDATE student SET stu_salary=stu_salary+1000 WHERE stu_id=1";
            ps = conn.prepareStatement(sql1);
            ps.executeUpdate();
            int x=1/0;
            String sql2="UPDATE student SET stu_salary=stu_salary-1000 WHERE stu_id=3";
            ps = conn.prepareStatement(sql2);
            ps.executeUpdate();
            System.out.println("执行成功");
        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        finally {
            //资源释放
            try {
                ps.close();
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

  • 结果:

JDBC中的事务回滚_第3张图片
注:成功执行了第一个sql语句,但是第二个由于int x=1/0;的错误而没有执行,显然,这样是不规范的。那么就有了下面的事务回滚

  • 利用事务回滚,实现事务的原子性

两个一起执行,或者一起不执行的code:

package com.mystudy.jdbc;

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

public class Affair {
    public static void main(String[] args) {
        Connection conn= null;
        int a = 0,b=0;
        PreparedStatement ps= null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test1?useSSL=true","root","root");
            //关闭数据库的自动提交
            conn.setAutoCommit(false);
            String sql1="UPDATE student SET stu_salary=stu_salary+1000 WHERE stu_id=1";
            ps = conn.prepareStatement(sql1);
            ps.executeUpdate();
            int x=1/0;
            String sql2="UPDATE student SET stu_salary=stu_salary-1000 WHERE stu_id=3";
            ps = conn.prepareStatement(sql2);
            ps.executeUpdate();
            //业务完毕,提交事务
            conn.commit();
            System.out.println("执行成功");
        } catch (SQLException | ClassNotFoundException e) {
            try {
                //如果失败则默认回滚,
                conn.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            e.printStackTrace();
        }
        finally {
            //资源释放
            try {
                ps.close();
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

  • 结果

JDBC中的事务回滚_第4张图片

  • 解释:
    1. 因为数据库是自动提交的(就是执行code后读取到哪执行到哪,这也是要进行事务回滚的原因),所以我们要将数据库的自动提交关闭,那么使用codeconn.setAutoCommit(false);
    2. 关闭了自动提交,但总是要提交事务的,由该codeconn.commit();实现
    3. 上面两个设置了基本就可以实现原子性,这里为了防止意外,在catch语句中再次显式的用:conn.rollback();实现事物的回滚
  • 这里再建议学习一下sql注入问题:sql注入问题
  • 这里有JDBC简单的入门学习流程:学习流程

你可能感兴趣的:(JDBC,jdbc,java,数据库,mysql)