在本系列的上一篇文章中,我们看到了一个典型的事务处理失败的案例,其主要原因在于,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事务处理全解析(三)——丑陋的案例的更多相关文章

  1. Java事务处理全解析(二)——失败的案例

    在本系列的上一篇文章中,我们讲到了Java事务处理的基本问题,并且讲到了Service层和DAO层,在本篇文章中,我们将以BankService为例学习一个事务处理失败的案例. BankService ...

  2. Java事务处理全解析(一)——Java事务处理的基本问题

    Java中的事务处理有多简单?在使用EJB时,事务在我们几乎察觉不到的情况下发挥着作用:而在使用Spring时,也只需要配置一个TransactionManager,然后在需要事务的方法上加上Tran ...

  3. Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)

    在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法.在本篇中 ...

  4. Java事务处理全解析(六)—— 使用动态代理(Dynamic Proxy)完成事务

    在本系列的上一篇文章中,我们讲到了使用Template模式进行事务管理,这固然是一种很好的方法,但是不那么完美的地方在于我们依然需要在service层中编写和事务处理相关的代码,即我们需要在servi ...

  5. Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的TransactionManager)

    在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的.在本篇文章中,我们将引入另外 ...

  6. Java事务处理全解析(八)——分布式事务入门例子(Spring+JTA+Atomikos+Hibernate+JMS)

    在本系列先前的文章中,我们主要讲解了JDBC对本地事务的处理,本篇文章将讲到一个分布式事务的例子. 请通过以下方式下载github源代码: git clone https://github.com/d ...

  7. Java事务处理全解析(五)—— Template模式

    在本系列的上一篇文章中,我们讲到了使用TransactionManger和ConnectionHolder完成线程安全的事务管理,在本篇中,我们将在此基础上引入Template模式进行事务管理. Te ...

  8. java事务处理全解析

    http://blog.csdn.net/huilangeliuxin/article/details/43446177

  9. 《Java面试全解析》505道面试题详解

    <Java面试全解析>是我在 GitChat 发布的一门电子书,全书总共有 15 万字和 505 道 Java 面试题解析,目前来说应该是最实用和最全的 Java 面试题解析了. 我本人是 ...

随机推荐

  1. codefoces round193a

    link: http://codeforces.com/contest/332/problem/A /* ID: zypz4571 LANG: C++ TASK: 193a.cpp */ #inclu ...

  2. 准备开始自己搞企业管理软件,从openerp入手

    公司运行了半年多,人还比较少,只用了一些即时通讯工具,还有svn等基本的工具 记账用的是gnucash 其他的管理急需相应的软件,找了很长时间也没有合适的 想了想,还是从开源的openerp odoo ...

  3. PHP设置图片文件上传大小的具体实现方法

    PHP默认的上传限定是最大2M,想上传超过此设定的文件,需要调整PHP.apache等的一些参数 我们简要介绍一下PHP文件上传涉及到的一些参数: •file_uploads :是否允许通过HTTP上 ...

  4. Linux驱动设计——阻塞和同步

    阻塞和非阻塞是设备访问的两种基本方式,阻塞和非阻塞驱动程序使用时,经常会用到等待队列. 阻塞和非阻塞 阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作.被挂起的 ...

  5. Java——异常

     /* * 异常:   是在运行时期  发生的 不正常情况. *  在java中类的形式对不正常情况进行了描述和封装对象. * * 描述不正常的情况类,就成为异常. * * 问题很多,就意味着描述 ...

  6. RecyclerView使用完全解析

    http://blog.csdn.net/a396901990/article/details/40153759 Android RecyclerView 使用完全解析 体验艺术般的控件 通过这个控件 ...

  7. myeclipse10安装egit和使用

    一.下载egit插件并安装到eclipse 下载egit插件包,然后解压放到Eclipse的dropins文件夹内或者直接放到对应的文件夹下 二.安装成功(window->preferences ...

  8. CentOS怎样强制卸载PHP以及自定义安装PHP

    很无语,CentOS居然php版本才5.1.6,很多开源的CMS无法安装. 查看php版本命令: #php -v 这个命令是删除不干净的 #yum remove php 因为使用这个命令以后再用 #p ...

  9. C#事件(event)解析

    事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂.而这些东西却往往又是编程中常用且非常重要的东西.大家都知道windows消息处理机制的重要,其实C#事件就是基于window ...

  10. 07-Java 中的IO操作

    1.Java IO简介: (1)I/O :in \out 即输入与输出.基本功能:读写. (2)IO流:作用:读写设备上的数据,硬盘文件.内存.键盘.网络-- 根据数据的走向,可分为:输入流.输出流. ...