zoukankan      html  css  js  c++  java
  • JDBC事务之例子篇

    上一篇随笔记了一些有关JDBC事务管理的理论知识。这篇来看例子(主要怕一篇随笔装所有东西太长了然后分开呵呵)

    一般讲事务管理的,都是拿转钱来当例子的,嗯没错我们这也是。

    这个是数据库中的t_account表,装的就是额~可以理解成一个银行账号,就有id,用户名,还有用户的存款。

    然后是一个简单的Java实体类:

    package com.java.ws.transactionDemo;
    
    /**
     * 数据库的实体对应类
     * 银行账号类
     * @author 85060
     *
     */
    public class Account {
        private int id;
        private String accountName;
        private float accountBalance;
        
        public Account(int id, String accountName, float accountBalance) {
            this.id = id;
            this.accountBalance = accountBalance;
            this.accountName = accountName;
        }
        
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getAccountName() {
            return accountName;
        }
        public void setAccountName(String accountName) {
            this.accountName = accountName;
        }
        public float getAccountBalance() {
            return accountBalance;
        }
        public void setAccountBalance(float accountBalance) {
            this.accountBalance = accountBalance;
        }
        
        
    }

    DbUtil类:是个封装了获取JDBC驱动还有连接代码的类,就不贴了,主要就是提供Connection还有关闭数据库连接和预处理。

    然后来看 这个AccountInOutDao,这里我们不是很规范,逻辑代码也写在了这里:

    package com.java.ws.transactionDemo;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    import com.java.ws.util.DbUtil;
    
    public class AccountInOutDao {
        
        private static DbUtil dbUtil = new DbUtil();
        
        /* new Account(1, "张三", 500);
         new Account(2, "李四", 1000);*/
        
        
        public static int outMoney(Account user, int amount, Connection con) {
            
            String sql = "UPDATE t_account set accountBalance = accountBalance - ? where id = ?";
            PreparedStatement pstmt = null;
            int result = 0;
            try {
                
                
                
                pstmt = con.prepareStatement(sql);
                pstmt.setInt(1, amount);
                pstmt.setInt(2, user.getId());
                result = pstmt.executeUpdate();//返回执行的条数
                
                
                
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                System.out.println("在借钱出去的数据库操作里面出错");
                e.printStackTrace();
            } finally {
                dbUtil.close(pstmt, con);
            }
            
            return result;
        }
        
        
        public static int inMoney(Account user, int amount, Connection con) {
            
            String sql = "UPDATE t_account set accountBalance = accountBalance + ? where id = ?";
            PreparedStatement pstmt = null;
            int result = 0;
            try {
                
                
                
                pstmt = con.prepareStatement(sql);
                pstmt.setInt(1, amount);
                pstmt.setInt(2, user.getId());
                result = pstmt.executeUpdate();//返回执行的条数
                
                
                
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                System.out.println("在借钱出去的数据库操作里面出错");
                e.printStackTrace();
            } finally {
                dbUtil.close(pstmt, con);
            }
            
            
            return result;
        }
        
        
        public static void main(String[] args) {
         Connection con = dbUtil.getCon();
            System.out.println("张三要转钱200块了");
            if(outMoney(new Account(1, "张三", 500), 200, con) != 0) {
                System.out.println("成功转钱");
            }
            
            
            System.out.println("张三要转钱200块了");
            if(inMoney(new Account(2, "李四", 1000), 200, con) != 0) {
                System.out.println("成功收钱");
            }
            
        }
        
        
    }

    操作后结果:

     

    这里先是一个普通且正常运行的情况,就看拿钱也成功,取钱也成功。但如果我们现在人为地在转钱和收钱中间制造一个异常的话呢?

    public static void main(String[] args) {
            
            System.out.println("张三要转钱200块了");
            if(outMoney(new Account(1, "张三", 500), 200) != 0) {
                System.out.println("成功转钱");
            }
            
            System.out.println(1/0);  //制造了一个异常
            
            System.out.println("张三要转钱200块了");
            if(inMoney(new Account(2, "李四", 1000), 200) != 0) {
                System.out.println("成功收钱");
            }
            
    }

    结果就是,显而易见:

     

    张三是转了两百块钱,然而李四啥都没收到。这要是在现实的银行系统中还得了hhh。

    所以我们这里采用事务管理的方式,给个try catch块,如果抓到错误,就回滚。

        public static void main(String[] args) {
            
            Connection con = null;
            
            try {
                
                
                
                
                con = dbUtil.getCon();
                con.setAutoCommit(false);
                
                
                System.out.println("张三要转钱200块了");
                if(outMoney(new Account(1, "张三", 500), 200, con) != 0) {
                    System.out.println("成功转钱");
                }
                
                System.out.println(1/0);  //制造异常
                
                System.out.println("张三要转钱200块了");
                if(inMoney(new Account(2, "李四", 1000), 200, con) != 0) {
                    System.out.println("成功收钱");
                }
                
                
                
                
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                System.out.println("转账失败!");
                try {
                    
                    
                    con.rollback();//有错误,回滚
                    System.out.println("刚刚走了回滚那一步");
                    
                } catch (SQLException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                
            } finally {
                try {
                    
                    
                    con.commit();  //最后提交,如果是没异常,则正常提交,如果有异常,就提交回滚那个位置前面的那些操作
                
                
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                dbUtil.close(con);
            }
            
            
            
      }
        

    结果:

    数据库信息没变化:

    刚刚我们采用全部回滚,也可以定点回滚:

    Savepoint savePoint = null;
    
    savePoint = con.setSavepoint(); //记忆点
    
                      
    con.rollback(savePoint);//有错误,回滚到记忆点

    附:

    一开始我是在InMoney和OutMoney里面分别建立Connection,然后在main方法里面又搞了一个Connection用来回滚,想着说应该是可以吧,回滚到之前main这个con的初始情况。结果不行,要改成一个Connection才行。 后面百度相关信息,有看到当多个线程使用一个Connection的时候,会引起事务的混乱。。我想这也是为什么要有连接池这种技术的原因吧。

  • 相关阅读:
    AutoFac
    MEF 基础简介 四
    MEF 基础简介 三
    MEF 基础简介 二
    MEF 基础简介 一
    Ioc原理理解
    .NET里面 abstract class和Interface有什么区别以及用法的展现?
    .NET-ORM框架EF-Code First代码优先
    SQL SERVER PIVOT与用法解释
    SQL Server 中的 NOLOCK 到底是什么意思?
  • 原文地址:https://www.cnblogs.com/wangshen31/p/8856575.html
Copyright © 2011-2022 走看看