Java学习日志(三十五): 事务,三层思想实现转账案例

JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)

事务

事务概述

事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功,要么全都失败。
事务作用:保证在一个事务(一个connection)中多次SQL操作要么全都成功,要么全都失败。 防止出现转账吞钱的现象。

数据库有事务概念,执行sql语句,就会开启事务,执行成功会提交事务,执行失败会回滚事务:

  • mysql数据库事务默认都是自动的,自动开启事务,自动提交事务,自动回滚事务
  • oracle数据库事务默认都是手动的,手动开启事务,手动提交事务,手动回滚事务

注意:事务一旦结束(提交,回滚),数据就永久保存在数据库

在Connection接口中,有操作事务的方法

  • void setAutoCommit​(boolean autoCommit) 将此连接的自动提交模式设置为给定状态。

     参数:
       autoCommit:true启用自动提交模式(默认);
                   false禁用自动提交模式,(执行sql语句之前)手动开启事务。
    
  • void commit() 一组sql一句都执行成功,提交事务

  • void rollback() 一组sql中有一条执行失败,回滚事务;把数据回滚到数据开启之前

使用原生JDBC完成转账案例

首先,创建一张账户表

# 创建一个表:账户表.
CREATE DATABASE day05;
# 使用数据库
USE day05;
# 创建账号表
CREATE TABLE account(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20),
	money DOUBLE
);
# 初始化数据
INSERT INTO account VALUES (NULL,'jack',10000);
INSERT INTO account VALUES (NULL,'rose',10000);
INSERT INTO account VALUES (NULL,'tom',10000);

在这里插入图片描述
代码示例:使用原生JDBC完成转账案例

public class Demo01JDBC {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stat = null;
        try {
            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //获取数据库连接对象Connection
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day05", "root", "root");

            //开启事务
            conn.setAutoCommit(false);

            //获取执行者对象Statement
            stat = conn.createStatement();
            //执行sql语句获取结果
            int row1 = stat.executeUpdate("UPDATE account SET money=money-1000 where NAME='jack';");
            System.out.println(0/0);
            int row2 = stat.executeUpdate("UPDATE account SET money=money+1000 where NAME='rose';");
            //处理结果
            if (row1 > 0 && row2 > 0) {
                System.out.println("转账成功");
                //提交事务
                conn.commit();
            }
        } catch (Exception e) {
            System.out.println("转账失败");
            e.printStackTrace();
            /*
                回滚事务
             */
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            //释放资源
            if(stat!=null){
                try {
                    stat.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

使用DbUtils和C3P0完成转账案例

QueryRunner的构造方法:

  • QueryRunner():空参构造,调用update/query方法执行sql语句时,必须传递Connection对象。
  • QueryRunner(DataSource ds):带连接池的构造方法,看不到Connection,也就不能操作事务。

QueryRunner的成员方法:用于执行增删改的update方法。
int update(Connection conn,String sql,Object... params) 空参构造使用。

代码示例:使用DBUtils+C3P0连接池完成转账案例

public class Demo02DBUtils {
    public static void main(String[] args) {
        //1.创建QueryRunner对象
        QueryRunner qr = new QueryRunner();
        //2.使用C3P0连接池获取Connection
        Connection conn = C3P0UtilsXML.getConnection();

        //3.使用QueryRunner对象中的方法update
        String sql1 = "UPDATE account SET money=money-1000 where NAME='jack';";
        String sql2 = "UPDATE account SET money=money+1000 where NAME='rose';";
        try {
            //开启事务
            conn.setAutoCommit(false);

            int row1 = qr.update(conn, sql1);
            int row2 = qr.update(conn, sql2);
            //4.处理结果
            if (row1 > 0 && row2 > 0) {
                System.out.println("转账成功");
                //提交事务
                conn.commit();
            }
        } catch (Exception e) {
            System.out.println("转账失败");
            e.printStackTrace();
            //回滚事务
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            //释放资源
            DbUtils.closeQuietly(conn);
        }
    }
}

三层思想

三层思想概述

在这里插入图片描述

三层思想转账案例_dao层

创建转账案例的Dao层:用于对account表进行增删改查
注意:
一张表–>一个dao
定义两个方法:
一个减钱,一个加钱

代码示例:dao层

public class AccountDao {
    /*
        定义减钱方法
        参数:
            Connection conn:两个方法使用同一个Connection,从而保证使用同一个事务
            String fromName:付款人姓名
            double money:转账金额
        返回值:
            int:影响数据库的有效行数
        String sql1 = "UPDATE account SET money=money-1000 where NAME='jack';";
        String sql2 = "UPDATE account SET money=money+1000 where NAME='rose';";
     */
    public int fromAccount(Connection conn, String fromName, double money) throws SQLException {
        //创建QueryRunner对象
        QueryRunner qr = new QueryRunner();
        //调用update方法执行sql语句,接收结果
        int row = qr.update(conn,"UPDATE account SET money=money-? where NAME=?;",money,fromName);
        //返回方法
        return row;

    }
    /*
        定义加钱方法
        参数:
            Connection conn:两个方法使用同一个Connection,从而保证使用同一个事务
            String toName:收款人姓名
            double money:转账金额
        返回值:
            int:影响数据库的有效行数
        String sql1 = "UPDATE account SET money=money-1000 where NAME='jack';";
        String sql2 = "UPDATE account SET money=money+1000 where NAME='rose';";
     */
    public int toAccount(Connection conn, String toName, double money) throws SQLException {
        //创建QueryRunner对象
        QueryRunner qr = new QueryRunner();
        //调用update方法执行sql语句,接收结果
        int row = qr.update(conn,"UPDATE account SET money=money+? where NAME=?;",money,toName);
        //返回方法
        return row;

    }
}

三层思想转账案例_service层

转账案例的Service层:接收web层传递的数据,调用dao层的方法,接收结果;把结果返回给web层
定义一个转账方法

  1. 参数接收web传递的数据(付款人姓名,收款人姓名,转账金额)
  2. 使用C3P0连接池,获取Connection
  3. 开启事务
  4. 创建AccountDao对象,调用减钱价钱方法,接收结果
  5. 对结果进行判断
  6. 执行成功,提交事务;有异常回滚事务
  7. 把结果返回给web层
  8. 释放资源

代码示例:service层

public class AccountService {
    //定义一个转账方法
    public boolean transferAccount(String fromName, String toName, double money) {
        //使用C3P0连接池,获取Connection
        Connection conn = C3P0UtilsXML.getConnection();
        //定义返回的结果
        boolean flag = false;
        try {
            //开启事务
            conn.setAutoCommit(false);
            //创建AccountDao对象
            AccountDao dao = new AccountDao();
            //调用减钱价钱方法,接收结果
            int row1 = dao.fromAccount(conn, fromName, money);
            int row2 = dao.toAccount(conn, toName, money);
            //对结果进行判断
            if (row1>0&&row2>0){
                flag = true;
                //执行成功,提交事务
                conn.commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
            //有异常回滚事务
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            //资源释放
            DbUtils.closeQuietly(conn);
        }
        //把结果返回给web层
        return flag;
    }
}

三层思想转账案例_web层

创建转账案例的web层

  1. 使用Scanner获取用户输入的数据(付款人姓名,收款人姓名,转账金额)
  2. 创建AccountService对象
  3. 调用转账方法,接收转账结果
  4. 对结果进行判断,给用户展示结果

代码示例:web层

public class AccountWeb {
    public static void main(String[] args) {
        //使用Scanner获取用户输入的数据(付款人姓名,收款人姓名,转账金额)
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入付款人姓名:");
        String fromName = sc.next();
        System.out.print("请输入收款人姓名:");
        String toName = sc.next();
        System.out.print("请输入转账金额:");
        double money = sc.nextDouble();
        //创建AccountService对象
        AccountService service = new AccountService();
        //调用转账方法,接收转账结果
        boolean b = service.transferAccount(fromName, toName, money);
        //对结果进行判断,给用户展示结果
        if (b) {
            System.out.println("转账成功");
        } else {
            System.out.println("转账失败");
        }
    }
}

转账结果:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章