Java事务处理全解析(三)——丑陋的案例
在本系列的上一篇文章中,我们看到了一个典型的事务处理失败的案例,其主要原因在于,service层和各个DAO所使用的Connection是不一样的,而JDBC中事务处理的作用对象正是Connection对象,所以不同DAO中的操作不在同一个事务里面,从而导致事务失败。从中我们得出了教训:要避免这种失败,我们可以使所有操作共享一个Connection对象,这样应该就没有问题了。
在本篇文章中,我们将看到一个成功的,但是丑陋的事务处理方案,它的基本思路是:在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对象的情况下完成和本文相同的事务处理功能。
Java事务处理全解析(三)——丑陋的案例的更多相关文章
- Java事务处理全解析(二)——失败的案例
在本系列的上一篇文章中,我们讲到了Java事务处理的基本问题,并且讲到了Service层和DAO层,在本篇文章中,我们将以BankService为例学习一个事务处理失败的案例. BankService ...
- Java事务处理全解析(一)——Java事务处理的基本问题
Java中的事务处理有多简单?在使用EJB时,事务在我们几乎察觉不到的情况下发挥着作用:而在使用Spring时,也只需要配置一个TransactionManager,然后在需要事务的方法上加上Tran ...
- Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)
在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法.在本篇中 ...
- Java事务处理全解析(六)—— 使用动态代理(Dynamic Proxy)完成事务
在本系列的上一篇文章中,我们讲到了使用Template模式进行事务管理,这固然是一种很好的方法,但是不那么完美的地方在于我们依然需要在service层中编写和事务处理相关的代码,即我们需要在servi ...
- Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的TransactionManager)
在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的.在本篇文章中,我们将引入另外 ...
- Java事务处理全解析(八)——分布式事务入门例子(Spring+JTA+Atomikos+Hibernate+JMS)
在本系列先前的文章中,我们主要讲解了JDBC对本地事务的处理,本篇文章将讲到一个分布式事务的例子. 请通过以下方式下载github源代码: git clone https://github.com/d ...
- Java事务处理全解析(五)—— Template模式
在本系列的上一篇文章中,我们讲到了使用TransactionManger和ConnectionHolder完成线程安全的事务管理,在本篇中,我们将在此基础上引入Template模式进行事务管理. Te ...
- java事务处理全解析
http://blog.csdn.net/huilangeliuxin/article/details/43446177
- 《Java面试全解析》505道面试题详解
<Java面试全解析>是我在 GitChat 发布的一门电子书,全书总共有 15 万字和 505 道 Java 面试题解析,目前来说应该是最实用和最全的 Java 面试题解析了. 我本人是 ...
随机推荐
- codefoces round193a
link: http://codeforces.com/contest/332/problem/A /* ID: zypz4571 LANG: C++ TASK: 193a.cpp */ #inclu ...
- 准备开始自己搞企业管理软件,从openerp入手
公司运行了半年多,人还比较少,只用了一些即时通讯工具,还有svn等基本的工具 记账用的是gnucash 其他的管理急需相应的软件,找了很长时间也没有合适的 想了想,还是从开源的openerp odoo ...
- PHP设置图片文件上传大小的具体实现方法
PHP默认的上传限定是最大2M,想上传超过此设定的文件,需要调整PHP.apache等的一些参数 我们简要介绍一下PHP文件上传涉及到的一些参数: •file_uploads :是否允许通过HTTP上 ...
- Linux驱动设计——阻塞和同步
阻塞和非阻塞是设备访问的两种基本方式,阻塞和非阻塞驱动程序使用时,经常会用到等待队列. 阻塞和非阻塞 阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作.被挂起的 ...
- Java——异常
/* * 异常: 是在运行时期 发生的 不正常情况. * 在java中类的形式对不正常情况进行了描述和封装对象. * * 描述不正常的情况类,就成为异常. * * 问题很多,就意味着描述 ...
- RecyclerView使用完全解析
http://blog.csdn.net/a396901990/article/details/40153759 Android RecyclerView 使用完全解析 体验艺术般的控件 通过这个控件 ...
- myeclipse10安装egit和使用
一.下载egit插件并安装到eclipse 下载egit插件包,然后解压放到Eclipse的dropins文件夹内或者直接放到对应的文件夹下 二.安装成功(window->preferences ...
- CentOS怎样强制卸载PHP以及自定义安装PHP
很无语,CentOS居然php版本才5.1.6,很多开源的CMS无法安装. 查看php版本命令: #php -v 这个命令是删除不干净的 #yum remove php 因为使用这个命令以后再用 #p ...
- C#事件(event)解析
事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂.而这些东西却往往又是编程中常用且非常重要的东西.大家都知道windows消息处理机制的重要,其实C#事件就是基于window ...
- 07-Java 中的IO操作
1.Java IO简介: (1)I/O :in \out 即输入与输出.基本功能:读写. (2)IO流:作用:读写设备上的数据,硬盘文件.内存.键盘.网络-- 根据数据的走向,可分为:输入流.输出流. ...