记录使用Spring事务管理的坑
本文的内容持续更新
- 一号坑:如何将Hibernate配置到Spring进行事务管理
- 二号坑:为何Spring的事务管理不起作用
- 三号坑:为何DAO的事务起作用,把DAO放到Service里就crash了
一号坑:如何将Hibernate配置到Spring进行事务管理
Hibernate的配置比较简单,Spring的配置也简单,但是我第一次将它们结合在一起就不知所措了,因为它们单独的配置步骤都很确定,几乎人人都遵循,但是结合在一起配置时就有很多版本了,这里记录我认为比较好的一种版本。
- 先引入Spring和Hibernate所需的jar包,Build Path
- 创建properties文件,存储数据库的配置信息
- 创建Hibernate的cfg.xml文件,不需包含数据库配置信息,不要包含 CurrentSessionContext(原因见二号坑)
- 创建DAO和对应的hbm.xml映射文件
- 配置Spring.xml中的context:property-placeholder,指定之前写好的properties文件
- 配置Spring.xml文件中的dataSource,需要c3p0的jar
- 配置Spring.xml文件中的sessionFactory,对应class与Hibernate引用包版本一致
- 配置Spring.xml文件中的transactionManager,使用HibernateTransactionManager,对应class与Hibernate引用包版本一致
- 配置Spring.xml文件中的tx:annotation-driven,开启注解@Transactional
二号坑:为何Spring的事务管理不起作用
在练习的时候,我配置正确了Spring和Hibernate的环境,但是事务一直失败,下面是我Service类的代码:
在测试类中,我对每个方法对进行了测试,运行都正确。但涉及到事务的方法:getMoney和transaction,虽然能正常情况下运行,但是没有起到事务的作用,尽管我己经加了注解@Transaction在类的接口上。 它们都涉及了下面这条语句:
`bankDAOImpl.substructCustomerMoney(id, amount);
这是substructCustomerMoney的代码
如果指定id账户钱不够,那我就抛出RuntimeException,但是在transaction()方法里却出现,收钱方收到钱,但是扣钱方没有扣除的情况,这表明事务执行失败。
我找了很多资料,最后看到这么一个回答:
说cfg.xml中的CurrentSessionContext 会影响Spring事务整合,应该去掉,否则事务不能成功,确实我在cfg.xml中把这个属性去掉就成功了。
三号坑:为何DAO的事务起作用,把DAO放到Service里就crash了
是这样的我在DAO包下面写了代码BankDAO,然后在DAOImpl包里面写了对应的实现类BankDAOImpl,加上@Repository和@Transactional都允许完美。
图:
然后我写了一个Service,把这个BankDAOImpl放进去,上面加上@Autowired表示取值注入就crash了。
JUnit报异常这么说:
百思不得其解,我把Service类删了又可以运行了。明明就可以找到bean,为啥找不到呢,然后我把Service中的BankDAOImpl改成它对应的接口BankDAO,然后就可以了。
在StackOverflow上查,有人说在Spring中,如果一个bean继承了某了接口,应该向上转型为对应的接口。