打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Java事务处理全解析(三)

本系列上一篇文章中,我们看到了一个典型的事务处理失败的案例,其主要原因在于,service层和各个DAO所使用的Connection是不一样的,而JDBC中事务处理的作用对象正是Connection对象,所以不同DAO中的操作不在同一个事务里面,从而导致事务失败。从中我们得出了教训:要避免这种失败,我们可以使所有操作共享一个Connection对象,这样应该就没有问题了。

 

请通过以下方式下载本系列文章的github源代码:

git clone https://github.com/davenkin/java_transaction_workshop.git

 

在本篇文章中,我们将看到一个成功的,但是丑陋的事务处理方案,它的基本思路是:在service层创建Connection对象,再将该Connection传给各个DAO类,这样就完成了Connection共享的目的。

 

修改两个DAO类,使他们都接受一个Connection对象,定义UglyBankDao类如下:

package davenkin.step2_ugly;         import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;         public class UglyBankDao{    public void withdraw(int bankId, int amount, Connection connection) throws SQLException    {        PreparedStatement selectStatement = connection.prepareStatement("SELECT BANK_AMOUNT FROM BANK_ACCOUNT WHERE BANK_ID = ?");        selectStatement.setInt(1, bankId);        ResultSet resultSet = selectStatement.executeQuery();        resultSet.next();        int previousAmount = resultSet.getInt(1);        resultSet.close();        selectStatement.close();                 int newAmount = previousAmount - amount;        PreparedStatement updateStatement = connection.prepareStatement("UPDATE BANK_ACCOUNT SET BANK_AMOUNT = ? WHERE BANK_ID = ?");        updateStatement.setInt(1, newAmount);        updateStatement.setInt(2, bankId);        updateStatement.execute();                 updateStatement.close();    }}

 

使用同样的方法,定义UglyInsuranceDao类:

package davenkin.step2_ugly;        import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;        public class UglyInsuranceDao{    public void deposit(int insuranceId, int amount, Connection connection) throws SQLException    {        PreparedStatement selectStatement = connection.prepareStatement("SELECT INSURANCE_AMOUNT FROM INSURANCE_ACCOUNT WHERE INSURANCE_ID = ?");        selectStatement.setInt(1, insuranceId);        ResultSet resultSet = selectStatement.executeQuery();        resultSet.next();        int previousAmount = resultSet.getInt(1);        resultSet.close();        selectStatement.close();                        int newAmount = previousAmount + amount;        PreparedStatement updateStatement = connection.prepareStatement("UPDATE INSURANCE_ACCOUNT SET INSURANCE_AMOUNT = ? WHERE INSURANCE_ID = ?");        updateStatement.setInt(1, newAmount);        updateStatement.setInt(2, insuranceId);        updateStatement.execute();                updateStatement.close();    }}

 

然后修改Service类,在UglyBankService类的transfer方法中,首先创建一个Connection对象,然后在将该对象依次传给UglyBankDao的withdraw方法和UglyInsuranceDao类的deposit方法,这样service层和DAO层使用相同的Connection对象。定义UglyBankService类如下:

package davenkin.step2_ugly;      import davenkin.BankService;import javax.sql.DataSource;import java.sql.Connection;import java.sql.SQLException;      public class UglyBankService implements BankService{    private DataSource dataSource;    private UglyBankDao uglyBankDao;    private UglyInsuranceDao uglyInsuranceDao;          public UglyBankService(DataSource dataSource)    {        this.dataSource = dataSource;    }          public void transfer(int fromId, int toId, int amount)    {        Connection connection = null;        try        {            connection = dataSource.getConnection();            connection.setAutoCommit(false);                  uglyBankDao.withdraw(fromId, amount, connection);            uglyInsuranceDao.deposit(toId, amount, connection);                  connection.commit();        } catch (Exception e)        {            try            {                assert connection != null;                connection.rollback();            } catch (SQLException e1)            {                e1.printStackTrace();            }        } finally        {            try            {                assert connection != null;                connection.close();            } catch (SQLException e)            {                e.printStackTrace();            }        }    }          public void setUglyBankDao(UglyBankDao uglyBankDao)    {        this.uglyBankDao = uglyBankDao;    }          public void setUglyInsuranceDao(UglyInsuranceDao uglyInsuranceDao)    {        this.uglyInsuranceDao = uglyInsuranceDao;    }}

 

 

通过上面共享Connection对象的方法虽然可以完成事务处理的目的,但是这样做法是丑陋的,原因在于:为了完成事务处理的目的,我们需要将一个底层的Connection类在service层和DAO层之间进行传递,而DAO层的方法也要接受这个Connection对象,这种做法显然是不好的,这就是典型的API污染。

 

下一篇博文中,我们将讲到如何在不传递Connection对象的情况下完成和本文相同的事务处理功能。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Java JDBC编程总结
(2) Java SQL框架(java.sql.*)中常用接口详解
06 | 基础规范:如何理解 JDBC 关系型数据库访问规范?
JDBC常见面试题(修订版)
Java编程开发学习之JDBC
java.sql包
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服