Dao跨事务调用实现转账功能

1.首先在数据库当中创建数据库,并且创建它的 实现类

package com.beiwo.epet.entity;

public class Account {
    private int id;

    private String name;

    private int money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

}

2.导入jar包,并且 添加到构建路径

3.在这里采用的是C3P0数据源,并且导入它的固定格式文件c3p0-config.xml

    数据源

package com.beiwo.epet.util;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Util {
	
	//C3P0数据源
	private static ComboPooledDataSource dataSource=new ComboPooledDataSource();
	
	public static DataSource getDataSource() {
		return dataSource;
	}
	
	
	public static Connection getConn(){
		try {
			return dataSource.getConnection();
		} catch (SQLException  e) {
			throw new  RuntimeException(e);
		}
	}
	
	public static Connection getConn2(){
		Connection conn=null;
		
		try {
			conn=dataSource.getConnection();
		} catch (Exception  e) {
			e.printStackTrace();
		}
		
		return conn;
	}
	
	//释放连接
	public static void realease(ResultSet rs,Statement stmt,Connection conn){
		try {
			if(null!=rs){
				rs.close();
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		try {
			if(null!=stmt){
				stmt.close();
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		try {
			if(null!=conn){
				conn.close();
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
	
	
	
}

     

  C3P0的固定格式

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
  <default-config>
  	<property name="driverClass">com.mysql.jdbc.Driver</property>
  	<property name="jdbcUrl">jdbc:mysql:///day05</property>
  	<property name="user">root</property>
  	<property name="password">root</property>
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
  </default-config>
</c3p0-config>

4.定义一个Dao接口(BaseDao)

package com.beiwo.epet.dao;

import com.beiwo.epet.entity.Account;

public interface  AccountDao {

    /**
     * 
     * @param fromName   	//谁转的
     * @param toName  		// 转给谁
     * @param money    		//转了多少钱
     * @throws Exception
     */
    public void updateAccount(String fromName,String toName,int money)throws Exception;
    
    
    /**
     * 更新信息
     * @param account
     * @throws Exception
     */
    public void updateAccount(Account account)throws Exception;
    
    /**
     * 获取名字
     * @param name
     * @return
     * @throws Exception
     */
    public Account findAccountByName(String name)throws Exception;
}

 5.Dao的实现类

package com.beiwo.epet.dao.impl;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import com.beiwo.epet.dao.AccountDao;
import com.beiwo.epet.entity.Account;
import com.beiwo.epet.util.C3P0Util;
import com.beiwo.epet.util.TransactionManager;

public class AccountDaoImpl implements AccountDao{

    @Override
    public void updateAccount(String fromName, String toName, int money) throws Exception{
        QueryRunner qr=new QueryRunner(C3P0Util.getDataSource());
        
        qr.update("UPDATE account SET money=money-? WHERE name=?",money,fromName);
        qr.update("UPDATE account SET money=money+? WHERE name=?",money,toName);
    }

    @Override
    public void updateAccount(Account account) throws Exception{
        QueryRunner qr=new QueryRunner();
        qr.update(TransactionManager.getConnection(),"UPDATE account SET money=? WHERE name=?", account.getMoney(),account.getName());
    }

    @Override
    public Account findAccountByName(String name) throws Exception{
        QueryRunner qr=new QueryRunner();
        return qr.query(TransactionManager.getConnection(),"SELECT * FROM account WHERE name=?",new BeanHandler<Account>(Account.class),name);

    }

    
    
}

 6.定义一个服务层接口来实现转账功能

package com.beiwo.epet.service;

public interface AccountService {

    public void transfer(String formName,String toName,int money);
    
}

 7.实现服务层接口

package com.beiwo.epet.service.impl;

import com.beiwo.epet.dao.AccountDao;
import com.beiwo.epet.dao.impl.AccountDaoImpl;
import com.beiwo.epet.entity.Account;
import com.beiwo.epet.service.AccountService;
import com.beiwo.epet.util.TransactionManager;

public class AccountServiceImpl implements AccountService{

    @Override
    public void transfer(String formName, String toName, int money) {
        AccountDao accountDao=new AccountDaoImpl(); 
        
        try {
            ///开始一个事务,start transaction;
            //获取转入和转出的账户对象
            TransactionManager.startTransaction();
            
            Account fromAccount=accountDao.findAccountByName(formName);
            Account toAccount=accountDao.findAccountByName(toName);
            
            //修改账户的各自金额
            fromAccount.setMoney(fromAccount.getMoney()-money);
            toAccount.setMoney(toAccount.getMoney()+money);
            
            //完成转账的操作
            accountDao.updateAccount(fromAccount);
            
        //如果没有使用ThreadLocal,那么当我们添加这个异常的时候,下面的代码就不会执行,直接进入异常处理,两个事务要么都执行,要么都不执行
int i=2/0; accountDao.updateAccount(toAccount); TransactionManager.commitTransaction(); } catch (Exception e) { try { TransactionManager.rollbackTransaction();;//事务的回滚 } catch (Exception e2) { e2.printStackTrace(); } }finally{ try { TransactionManager.close(); } catch (Exception e2) { e2.printStackTrace(); } } } }

 8.再次过程中我们需要保证Connection是同一个Connection,,所以再定义一个管理类来保证是同一个Connection

package com.beiwo.epet.util;

import java.sql.Connection;

public class TransactionManager {

    private static ThreadLocal<Connection> t1=new ThreadLocal<Connection>();
   
    //获取连接
    public static Connection getConnection(){
        Connection conn=t1.get();//从当前线程中取出一个连接
        if(null==conn){
            conn=C3P0Util.getConn();
            t1.set(conn);//把conn对象放入当前线程中去
        }
        return conn;
    }
    
    
    
    //开始事务
    public static void startTransaction(){
        try {
            Connection conn=getConnection();
            conn.setAutoCommit(false);//从当前线程中取出连接,并开始事务
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    //提交事务
    public static void commitTransaction(){
        try {
            Connection conn=getConnection();
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    //回滚事务
    public static void rollbackTransaction(){
        try {
            Connection conn=getConnection();
            conn.rollback();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    //关闭连接
    public static void close(){
        try {
            Connection conn=getConnection();
            conn.close();
            t1.remove();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    
    
    
}

 9.最后一步就是测试,在此过程中我们没有使用main函数,所以我们自定义一个测试类来测试

package com.beiwo.epet.test;

import org.junit.Test;

import com.beiwo.epet.service.AccountService;
import com.beiwo.epet.service.impl.AccountServiceImpl;

public class TestTransfer {

    
    @Test
    public void test(){
        AccountService accountService=new AccountServiceImpl();
        
        accountService.transfer("aaa", "bbb", 100);
        
    }
}

数据库中原有的数据如下:

测试之后的结果如下:

原文地址:https://www.cnblogs.com/houjiie/p/6196197.html