四种控制事务的方法

本文介绍了事务控制的四种方式:在DAO层控制、业务层控制、抽取事务管理工具类以及使用AOP拦截器。详细步骤包括项目结构、类创建与修改,以及不同方法下事务的管理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

四种控制事务的方法

第一种

在DAO层控制事务

新建项目tx1

1.导入所需jar包
commons-dbcp-1.4.jar
commons-dbutils-1.4.jar
commons-pool-1.5.6.jar
mysql-connector-java-5.0.8-bin.jar
2.新建com.view包,模拟客户端调用action
package com.view;

import com.service.BusinessService;
import com.service.impl.BusinessServiceImpl;

public class Client {
    //模拟action中调用service
    public static void main(String[] args) {
        BusinessService s = new BusinessServiceImpl();

        s.transfer("aaa","bbb",100);
    }
}
3.新建com.service包,写业务接口
package com.service;

public interface BusinessService {
    /**
     * 模拟转账
     * @param from  转出的账户
     * @param to  目标账户
     * @param money  交易金额
     */
    void transfer(String from, String to, float money);

}
4.新建com.service.impl包,实现业务接口
package com.service.impl;

import java.sql.Connection;

import com.dao.AccountDao;
import com.dao.impl.AccountDaoImpl;
import com.service.BusinessService;
import com.utils.DBCPUtil;

public class BusinessServiceImpl implements BusinessService {

    private AccountDao dao = new AccountDaoImpl();

    @Override
    public void transfer(String from, String to, float money) {
        dao.transfer(from, to, money);
    }
}
5.新建com.dao包,写数据接口DAO
package com.dao;

public interface AccountDao {
    /**
     * 转账,这里有点牵扯到业务的意思
     * @param from
     * @param to
     * @param money 
     */
    void transfer(String from, String to, float money);

}
6.新建com.dao.impl,写数据接口DAO的实现
package com.dao.impl;

import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;

import com.dao.AccountDao;
import com.utils.DBCPUtil;

public class AccountDaoImpl implements AccountDao {
    private QueryRunner qr = new QueryRunner();

    @Override
    public void transfer(String from, String to, float money) {
        Connection conn = null;
        try {
            conn =DBCPUtil.getConnection();
            conn.setAutoCommit(false);
            qr.update(conn, "update account set money=money-? where name=?",money,from);
            qr.update(conn, "update account set money=money+? where name=?",money,to);
        } catch (Exception e) {
            if(conn!=null){
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
        }finally{
            if(conn!=null){
                try {
                    conn.commit();
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
7.工具类
package com.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

public class DBCPUtil {
    private static DataSource dataSource;
    static{
        try {
            InputStream in = DBCPUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties props = new Properties();
            props.load(in);
            dataSource = BasicDataSourceFactory.createDataSource(props);
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public static DataSource getDataSource(){
        return dataSource;
    }

  //获得连接
    public static Connection getConnection(){
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
8.dbconfig.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/jdbc
username=root
password=19941119liu

initialSize=10

maxActive=50

maxIdle=20

minIdle=5

maxWait=60000

connectionProperties=useUnicode=true;characterEncoding=utf8

defaultAutoCommit=true

defaultReadOnly=

defaultTransactionIsolation=REPEATABLE_READ

第二种

业务层控制事务

拷贝tx1项目到tx2

1.新建com.domain包,描述实体Account
package com.domain;

public class Account {
    private int id;
    private String name;
    private float 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 float getMoney() {
        return money;
    }
    public void setMoney(float money) {
        this.money = money;
    }

}
2.修改AccountDao.java

AccountDao不在涉及到业务,只做crud操作

package com.dao;

import com.domain.Account;

public interface AccountDao {
    /**
     * 根据户名查询账户
     * @param accountName
     * @return
     */
    Account findByName(String accountName);

    /**
     * 更新账户
     * @param account
     */
    void updateAccount(Account account);
}
3.修改dao的实现
package com.dao.impl;

import java.sql.Connection;
import java.sql.SQLException;

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

import com.dao.AccountDao;
import com.domain.Account;
import com.utils.DBCPUtil;

public class AccountDaoImpl implements AccountDao {
    private QueryRunner qr = new QueryRunner();
    private Connection conn;
    public AccountDaoImpl(Connection conn){
        this.conn  = conn;
    }
    //查账户
    @Override
    public Account findByName(String accountName) {
        try {
            return qr.query(conn, "select * from account where name=?", new BeanHandler<Account>(Account.class),accountName);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    //改账户
    @Override
    public void updateAccount(Account account) {
        try {
            qr.update(conn, "update account set money=? where id=?",account.getMoney(),account.getId());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
4.业务接口不变,只需修改业务实现
package com.service.impl;

import java.sql.Connection;
import java.sql.SQLException;

import com.dao.AccountDao;
import com.dao.impl.AccountDaoImpl;
import com.domain.Account;
import com.service.BusinessService;
import com.utils.DBCPUtil;

//业务层控制事务
public class BusinessServiceImpl implements BusinessService {

    @Override
    public void transfer(String from, String to, float money) {
        Connection conn = null;
        try {
            //拿连接
            conn = DBCPUtil.getConnection();
            conn.setAutoCommit(false);
            AccountDao dao = new AccountDaoImpl(conn);
            //调取DAO查找两个账户
            Account fromAccount = dao.findByName(from);
            Account toAccount = dao.findByName(to);

            fromAccount.setMoney(fromAccount.getMoney() - money);
            toAccount.setMoney(toAccount.getMoney() + money);

            //对账户进行更改
            dao.updateAccount(fromAccount);
            dao.updateAccount(toAccount);
        } catch (Exception e) {
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {
            if (conn != null) {
                try {
                    conn.commit();
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

第三种

抽取工具类,封装与事务有关的方法

拷贝tx2项目到tx3项目

1.在com.utils包中新建TransactionManager.java

package com.utils;

import java.sql.Connection;
import java.sql.SQLException;

//封装所有与事务有关的方法
public class TransactionManager {
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    //获取连接
    public static Connection getConnection(){
      //先从当前线程中获取连接
        Connection conn = tl.get();
        if(conn == null){
          //如果没有则从数据源中拿
            conn = DBCPUtil.getConnection();
            tl.set(conn);
        }
        return conn;
    }   
    //开启事务
    public static void startTransaction(){
        try {
            Connection conn = getConnection();
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }   
    //回滚
    public static void rollback(){
        Connection conn = getConnection();
        try {
            conn.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }   
    //释放资源
    public static void release(){
        try {
            Connection conn = getConnection();
            conn.close();
            tl.remove();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }   
    //提交事务
    public static void commit(){
        try {
            Connection conn = getConnection();
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

3.重写业务的实现

package com.service.impl;

import java.sql.Connection;
import java.sql.SQLException;

import com.dao.AccountDao;
import com.dao.impl.AccountDaoImpl;
import com.domain.Account;
import com.service.BusinessService;
import com.utils.DBCPUtil;
import com.utils.TransactionManager;

//业务层控制事务
public class BusinessServiceImpl implements BusinessService {
    private AccountDao dao = new AccountDaoImpl();
    @Override
    public void transfer(String from, String to, float money) {
        try {
            TransactionManager.startTransaction();

            Account sAccount = dao.findByName(from);
            Account tAccount = dao.findByName(to);

            sAccount.setMoney(sAccount.getMoney() - money);
            tAccount.setMoney(tAccount.getMoney() + money);

            dao.updateAccount(sAccount);
            dao.updateAccount(tAccount);
        } catch (Exception e) {
            TransactionManager.rollback();
        }finally{
            TransactionManager.commit();
            TransactionManager.release();
        }
    }   
}

第四种

AOP控制事务

通过AOP拦截业务方法,给业务方法加上事务的方法

1.首先修改业务方法的实现,修改transfer()方法
package com.service.impl;

import java.sql.Connection;
import java.sql.SQLException;

import com.dao.AccountDao;
import com.dao.impl.AccountDaoImpl;
import com.domain.Account;
import com.service.BusinessService;
import com.utils.DBCPUtil;
import com.utils.TransactionManager;

//我不再管事务了,我只管我的业务逻辑
public class BusinessServiceImpl implements BusinessService {
    private AccountDao dao = new AccountDaoImpl();
    @Override
    public void transfer(String from, String to, float money) {
            Account sAccount = dao.findByName(from);
            Account tAccount = dao.findByName(to);
            sAccount.setMoney(sAccount.getMoney() - money);
            tAccount.setMoney(tAccount.getMoney() + money);
            dao.updateAccount(sAccount);
            dao.updateAccount(tAccount);
    }
}
2.客户端再调用的时候,调用的是工厂产生的代理对象,代理对象的方法结合了业务方法和事务方法
package com.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.service.BusinessService;
import com.service.impl.BusinessServiceImpl;

//AOP控制事务
public class BeanFactory {
    public static BusinessService getBusinessService(){
        final BusinessService s = new BusinessServiceImpl();

        BusinessService proxyS = (BusinessService) Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass().getInterfaces(), new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                try {
                    TransactionManager.startTransaction();
                    Object rtValue = method.invoke(s, args);
                    return rtValue;
                } catch (Exception e) {
                    TransactionManager.rollback();
                    throw new RuntimeException(e);
                }finally{
                    TransactionManager.commit();
                    TransactionManager.release();
                }
            }
        });
        return proxyS;
    }
}
3.客户端通过工厂拿到业务实例
package com.view;

import com.service.BusinessService;
import com.service.impl.BusinessServiceImpl;
import com.utils.BeanFactory;

public class Client {
    //模拟action中调用service
    public static void main(String[] args) {

        BusinessService s = BeanFactory.getBusinessService();

        s.transfer("aaa","bbb",100);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值