java中使用事务案例_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类如下:

packagedavenkin.step2_ugly;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.sql.SQLException;public classUglyBankDao

{public void withdraw(int bankId, int amount, Connection connection) throwsSQLException

{

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类:

packagedavenkin.step2_ugly;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.sql.SQLException;public classUglyInsuranceDao

{public void deposit(int insuranceId, int amount, Connection connection) throwsSQLException

{

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类如下:

packagedavenkin.step2_ugly;importdavenkin.BankService;importjavax.sql.DataSource;importjava.sql.Connection;importjava.sql.SQLException;public class UglyBankService implementsBankService

{privateDataSource dataSource;privateUglyBankDao uglyBankDao;privateUglyInsuranceDao uglyInsuranceDao;publicUglyBankService(DataSource dataSource)

{this.dataSource =dataSource;

}public void transfer(int fromId, int toId, intamount)

{

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 voidsetUglyBankDao(UglyBankDao uglyBankDao)

{this.uglyBankDao =uglyBankDao;

}public voidsetUglyInsuranceDao(UglyInsuranceDao uglyInsuranceDao)

{this.uglyInsuranceDao =uglyInsuranceDao;

}

}

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值