银行转账(跨库事务)

题目:
        数据库事务,银行转账的例子。
        a和b不在同一个数据库里(跨数据库)的事务设计。如何保证两个或多个数据库之间转账事务的执行和回滚。
        MySQL怎么做。自己写代码怎么实现。

【如何实现跨库的事务操作】(跨数据库怎样保证事务执行和回滚)
 
 

【两段式提交】
两个事务,在保证一个"中心"事务是完整的情况下,如果这个事务提交,将另一个事务加入到一个队列中去异步由另外的进程负责完成操作。
 

【银行转账业务场景的几种实现思路对比】
银行转账的核心业务逻辑:
  1. 源账户扣除转账金额,当然首先需要先判断源账户余额是否足够,如果不够,则无法转账; 
  2. 目标账户增加转账金额; 
  3. 为源账户生成一笔转账记录; 
  4. 为目标账户生成一笔转账记录;
 
 
【用数据库事务控制语句模拟银行汇款过程】
Connection
PreparedStatement
ResultSet
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
 
import jdbc.util.DBUtil;
 
public class Trans {
 
    public static void main(String[] args) {
        Trans tran = new Trans();
        tran.transfer(12500);
        tran.print("select * from account");
    }
     
    /**
     * 汇款
     * @param from    汇款人
     * @param to      接受人
     * @param amount  汇款金额
     */
     
    public void transfer(int from, int to, double amount) {
        String sql1 = "update account set balance=balance-? where id=?";
        String sql2 = "update account set balance=balance+? where id=?";
 
        // 在汇款以后,如果汇出帐号的余额为负数,就抛出余额不足异常,自动回滚到原始状态
        String sql3 = "select balance from account where id=?";
 
        Connection conn = null;
        try{
            conn = DBUtil.getConnection();
            conn.setAutoCommit(false);   //开启事务
 
            PreparedStatement ps1 = conn.prepareStatement(sql1);
            ps1.setDouble(1,amount);
            ps1.setInt(2, from);
            ps1.executeUpdate();
 
            PreparedStatement ps2 = conn.prepareStatement(sql2);
            ps2.setDouble(1,amount);
            ps2.setInt(2, to);
            ps2.executeUpdate();
 
            //检查余额
            PreparedStatement ps3 = conn.prepareStatement(sql3);
            ps3.setInt(1, from);
            ResultSet rs = ps3.executeQuery();
            double balance = 0;
            while(rs.next()){
                balance = rs.getDouble("balance");
            }
            if(balance<0){
                throw new Exception("余额不足");
            }
 
            rs.close();
            ps1.close();ps2.close();ps3.close();
            conn.commit();             //提交事务
        }catch(Exception e){
            e.printStackTrace();
 
            try{
                conn.rollback();        //回滚事务
            catch(SQLException e1) {
                e1.printStackTrace();
            }
 
        }
 
    finally{
            DBUtil.close(conn);
        }
         
    }
     
    publicvoidprint(String sql){
        Connection conn = null;
        try{
            conn = DBUtil.getConnection();
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery(sql);
            ResultSetMetaData meta = rs.getMetaData();
            intcols = meta.getColumnCount();
            for(inti=1;i<=cols;i++){
                System.out.print(meta.getColumnName(i)+" ");
            }
            System.out.println();
             
            while(rs.next()){
                for(inti=1;i<=cols;i++){
                     Object data = rs.getObject(i);
                     System.out.print(data+" ");
                }
                System.out.println();
            }
            rs.close();
            st.close();
         
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            DBUtil.close(conn);
        }
         
    }
 
}


【存储过程、事务在银行转账系统的应用】http://blog.csdn.net/joetao/article/details/5757024
        最近项目中涉及到多表删除的情况,为了保证数据的完整性,准备用存储过程结合事务实现该效果。但自己以前只是看过事务方面的东西,但没真正用过。在网上收索了下发现这篇文章不错!但都是图片!如是自己全部敲了一边。并附上调用存储过程的代码!这篇文章对怎样写一个复杂的存储过程还是很有借鉴的意义的!直接贴带码了。
        本篇一银行的转账系统为例说明,因为这个例子贴近生活,很容易理解!
 
use BankSystem
use master
go
create DataBase BankSystem
go
use BankSystem
go
create table CardInfo
(
PKID int identity(1,1) primary key ,
CardNum nvarchar(19) not null,            --卡号
Balance money default(0)                  --余额 
)
go
create table Transfer_Event
(
PKID int identity(1,1) primary key,
FromCardID nvarchar(19) not null,        --源卡号        
ToCardID nvarchar(19) not null,          --目标卡号
TransMoney money,                        --转账金额
OccurTime datetime                       --发生时间
)
--插入记录                    
insert into CardInfo(CardNum,Balance) values('123456789',80.8)  
insert into CardInfo(CardNum,Balance) values('123',10.9) 
go     
 

--实现转账过程的存储过程实现如下(成功返回0,余额不够返回1,出现异常返回2)
create procedure TranserMoney
(
@fromCardNum varchar(19),        --转账源卡号
@toCardNum  varchar(19),         --转账目标卡号 
@tansMoney Money,                --转账金额  
@occurTime DateTime              --转账时间
       
)
as
begin 
     declare @cardNum varchar(19)
     declare @balance Money
      --开始事务 
     begin transaction 
      --定义游标
     declare cursorTransfer cursor for select CardNum,Balance from CardInfo where CardNum=@fromCardNum  
      --打开游标 
      open cursorTransfer 
      --取字段值,放入@cardNum,@balance
      fetch next from cursorTransfer into @cardNum,@balance     
      while @@FETCH_STATUS=0   --取游标状态(0--表示成功)
      begin 
      if(@balance>=@tansMoney)  --判断余额是否大于转账金额
         begin
 update CardInfo set Balance=Balance-@tansMoney where CardNum=@fromCardNum
 if @@ERROR<>0 goto ERR --发生错误跳转
 update CardInfo set Balance=Balance+@tansMoney where CardNum=@toCardNum
 if @@ERROR<>0 goto ERR
 insert into Transfer_Event(FromCardID,ToCardID,TransMoney,OccurTime)values(@fromCardNum,@toCardNum,@tansMoney,@occurTime)
 if @@ERROR<>0 goto ERR
 commit transaction   --提交事务
 close cursorTransfer --关闭游标
 deallocate cursorTransfer
 return 0    --执行正常,返回0
         end  
      else  --金额不够,返回1,回滚事务
          begin 
             rollback transaction   --回滚事务               
 close cursorTransfer --关闭游标
 deallocate cursorTransfer
 return 1    --执行正常,返回0
   end
      end    
end
ERR:--发生异常返回2
    begin
         rollback transaction  --回滚事务
         close cursorTransfer
         deallocate  cursorTransfer
         return 2
     end 
go


--调用存储过程 
declare @fromCardNum nvarchar(19),@toCardNum nvarchar(19),@money money,@dateTime DateTime,@flag int
set @fromCardNum='123456789'
set @toCardNum='123'
set @dateTime='2009-7-17'
set @money=50
exec @flag= TranserMoney @fromCardNum,@toCardNum,@money,@dateTime
select @flag
select *from CardInfo;
select *from Transfer_Event;     
 
posted @ 2015-07-08 23:24  Uncle_Nucky  阅读(1279)  评论(0编辑  收藏  举报