java学习笔记39(sql事物)

在之前的学习中,我们学习了使用PreparedStatement类,使用这个类消除了sql注入的隐患,可是,还有些一些其他的隐患,这里以银行转账业务为例,

假设  一个银行,张三在里面存了1000元,李四也在里面存了1000元,张三给李四转账500,那么张三的钱少500,李四的钱多500,可是如果转账的瞬间,张三的钱扣过后,给李四增加钱之前,假设停电了,那么钱就不见了,具体如下:

创建一个假设银行的数据表:

create table account
(
  id     int auto_increment
    primary key,
  NAME   varchar(10) null,
  balnce double      null
);

当张三给李四转账500元时,我们用两句语句分开执行,java实现具体代码如下:

package com.zs.Demo;

import JDBCUtils.JDBCUtils;

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

public class ZhuanZhang {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入转账金额:");
        double money = sc.nextDouble();
        zhuanzhang(money);
    }

    private static void zhuanzhang(double money) {
        Connection conn = JDBCUtils.getConnection();
        PreparedStatement pre=null;
        try {
            //张三减少money元
            String sql = "update account set balnce = balnce-? where name=?;";
            pre = conn.prepareStatement(sql);
            pre.setDouble(1,money);
            pre.setString(2,"张三");
            pre.executeUpdate();
            //李四增加money元
            String sql2="update account set balnce = balnce+? where name=?;";
            pre = conn.prepareStatement(sql2);
            pre.setDouble(1, money);
            pre.setString(2,"李四");
            pre.executeUpdate();
            System.out.println("转账成功");
        } catch (SQLException e) {
            System.out.println("转账失败");
            e.printStackTrace();
        }finally{
            JDBCUtils.close(conn,pre);
        }
    }
}

运行结果:

我们现在在张三和李四转账之间插入一个异常,假设停电,具体代码在上面代码中添加一句异常,如下:

package com.zs.Demo;

import JDBCUtils.JDBCUtils;

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

public class ZhuanZhang {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入转账金额:");
        double money = sc.nextDouble();
        zhuanzhang(money);
    }

    private static void zhuanzhang(double money) {
        Connection conn = JDBCUtils.getConnection();
        PreparedStatement pre=null;
        try {
            //张三减少money元
            String sql = "update account set balnce = balnce-? where name=?;";
            pre = conn.prepareStatement(sql);
            pre.setDouble(1,money);
            pre.setString(2,"张三");
            pre.executeUpdate();
            /*这里插入异常,0不能作为除数,所以这里会报错,用这种方式来假设停电之类的异常,我们会发现上
            面的语句已经执行了,到这里出现异常下面的语句不能执行,张三的钱扣了,李四的钱却没有增加,钱不见了*/
            System.out.println(100/0);
            
            //李四增加money元
            String sql2="update account set balnce = balnce+? where name=?;";
            pre = conn.prepareStatement(sql2);
            pre.setDouble(1, money);
            pre.setString(2,"李四");
            pre.executeUpdate();
            System.out.println("转账成功");
        } catch (SQLException e) {
            System.out.println("转账失败");
            e.printStackTrace();
        }finally{
            JDBCUtils.close(conn,pre);
        }
    }
}

运行结果:

 这时我们发现钱少了500,不见了,为了解决这种问题,数据库中,我们把这两种操作捆绑成一个事物,执行结果有两种,成功或者失败,不可以分开执行,

执行成功称为:提交事务,出现异常或者失败称:回滚事务。

在该例种,我们使用事物来处理时,思路如下:

  1.获取链接

  2.开启事物

  3.获取PreparedStatement对象

  4.执行两次更新操作,

  5.正常情况提交事务,出现异常时回滚事物

  6.关闭资源

代码:

package com.zs.Demo;

import JDBCUtils.JDBCUtils;

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

/*需求分析:模拟银行转账业务,张三给李四转账,当张三的钱扣除后,李四的钱增加*/
public class ShiWu {
    private static PreparedStatement pre;
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入转账金额:");
        double money = sc.nextDouble();
        zhuangzhang(money);
    }

    private static void zhuangzhang(double money) {
        //获得连接
        Connection conn=JDBCUtils.getConnection();
        try {
//            开启事物功能
            conn.setAutoCommit(false);
//            执行sql语句
            String sql="update account set  balnce=balnce-? where name=?";
            String sql2="update account set balnce = balnce+? where name=?";
            pre= conn.prepareStatement(sql);
            pre.setDouble(1,money);
            pre.setString(2,"张三");
            /*这里添加异常,到这里时出现异常,所以事物不成功,回滚事物,去掉下面异常语句,程序正常提交事务*/
            System.out.println(100/0);

            pre.executeUpdate();
            pre= conn.prepareStatement(sql2);
            pre.setDouble(1,money);
            pre.setString(2,"李四");
            pre.executeUpdate();
//            提交事务
            conn.commit();
            System.out.println("转账成功");
        } catch (Exception e) {
            try {
//                回滚事务
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
            System.out.println("转账失败");
        }
//        关闭资源
        JDBCUtils.close(conn,pre);
    }
}

运行结果:

正常提交的话,将代码中的异常语句注销就可以了,出现异常时,就会回滚事务,我们发现钱没有少,整个事务执行失败,异常前面的代码也没有成功执行。

 

posted @ 2019-04-02 16:37  Zs夏至  阅读(184)  评论(0编辑  收藏  举报