Spring AOP在Hibernate事务管理 - Spring教程
事务管理是用来以确保数据库中数据的完整性和一致性。Spring AOP技术允许开发者管理事务的声明。这里有一个例子来说明如何使用Spring AOP 来管理 Hibernate 事务。整个工程的文件结构如下所示:
P.S 这里很多Hibernate和Spring配置文件是隐藏的,只有一些重要的文件显示,如果你想看全部文件,请在文章的结尾下载完整的项目代码。
1.创建表
MySQL表的脚本,一个“product”表
CREATE TABLE `yiibai`.`product` (
`PRODUCT_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`PRODUCT_CODE` varchar(20) NOT NULL,
`PRODUCT_DESC` varchar(255) NOT NULL,
PRIMARY KEY (`PRODUCT_ID`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `yiibai`.`product_qoh` (
`QOH_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`PRODUCT_ID` bigint(20) unsigned NOT NULL,
`QTY` int(10) unsigned NOT NULL,
PRIMARY KEY (`QOH_ID`),
KEY `FK_product_qoh_product_id` (`PRODUCT_ID`),
CONSTRAINT `FK_product_qoh_product_id` FOREIGN KEY (`PRODUCT_ID`)
REFERENCES `product` (`PRODUCT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2.产品业务对象
在这个“productBo”实现save()方法将插入记录到“product“通过“ProductDao”,并通过“productQohBo”类库存量到“productQoh'表。
package com.yiibai.product.bo.impl;
import com.yiibai.product.bo.ProductBo;
import com.yiibai.product.bo.ProductQohBo;
import com.yiibai.product.dao.ProductDao;
import com.yiibai.product.model.Product;
import com.yiibai.product.model.ProductQoh;
public class ProductBoImpl implements ProductBo{
ProductDao productDao;
ProductQohBo productQohBo;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
public void setProductQohBo(ProductQohBo productQohBo) {
this.productQohBo = productQohBo;
}
//this method need to be transactional
public void save(Product product, int qoh){
productDao.save(product);
System.out.println("Product Inserted");
ProductQoh productQoh = new ProductQoh();
productQoh.setProductId(product.getProductId());
productQoh.setQty(qoh);
productQohBo.save(productQoh);
System.out.println("ProductQoh Inserted");
}
}
Spring 的 bean 配置文件。
<!-- Product business object -->
<bean id="productBo" class="com.yiibai.product.bo.impl.ProductBoImpl" >
<property name="productDao" ref="productDao" />
<property name="productQohBo" ref="productQohBo" />
</bean>
<!-- Product Data Access Object -->
<bean id="productDao" class="com.yiibai.product.dao.impl.ProductDaoImpl" >
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
运行它
Product product = new Product();
product.setProductCode("ABC");
product.setProductDesc("This is product ABC");
ProductBo productBo = (ProductBo)appContext.getBean("productBo");
productBo.save(product, 100);
假设save() 不具有事务功能,如果异常抛出由productQohBo.save(),钭只插入一条记录到“product”表,没有记录将被插入到“productQoh'表。这是一个严重的问题,在数据库中打破数据一致性。
3.事务管理
声明“TransactionInterceptor' bean,以及”HibernateTransactionManager' Hibernate事务,并且通过必要的属性。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="save">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="dataSource" ref="dataSource" />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
事务属性
在事务拦截器,必须定义的事务的属性“传播行为”应使用。这意味着,如果一个事务“ProductBoImpl.save()方法被调用另外的”productQohBo.save()'方法,事务应该怎么传播?它能继续在现有的事务中运行?或者为自己开始一个新的事务。
由Spring支持传播的 7种类型:
- PROPAGATION_REQUIRED – 支持当前事务;如果不存在则创建一个新的。
- PROPAGATION_SUPPORTS – 支持当前事务;如果不存在执行非事务。
- PROPAGATION_MANDATORY – 支持当前事务;如果当前不存在事务抛出异常。
- PROPAGATION_REQUIRES_NEW – 创建一个新的事务,如果当前事务暂停。
- PROPAGATION_NOT_SUPPORTED – 不支持当前的事务;而始终执行非事务。
- PROPAGATION_NEVER – 不支持当前的事务;如果当前事务存在则抛出异常。
- PROPAGATION_NESTED – 如果当前存在事务嵌套事务中执行,表现与 PROPAGATION_REQUIRED 一样。
在大多数情况下,可能只需要使用PROPAGATION_REQUIRED。此外,必须定义方法来支持这个事务属性。方法名支持通配符格式,save*会匹配所有的方法名 以save(...)开始的方法 。
事务管理器
在Hibernate事务,需要使用 HibernateTransactionManager 。 如果只对付纯JDBC,useDataSourceTransactionManager; 而如果是 JTA,需要使用 JtaTransactionManager 。
4.代理工厂bean
创建一个新的代理工厂bean的ProductBo,并设置“interceptorNames”属性。
<!-- Product business object -->
<bean id="productBo" class="com.yiibai.product.bo.impl.ProductBoImpl" >
<property name="productDao" ref="productDao" />
<property name="productQohBo" ref="productQohBo" />
</bean>
<!-- Product Data Access Object -->
<bean id="productDao" class="com.yiibai.product.dao.impl.ProductDaoImpl" >
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="productBoProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="productBo" />
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
运行它
Product product = new Product();
product.setProductCode("ABC");
product.setProductDesc("This is product ABC");
ProductBo productBo = (ProductBo)appContext.getBean("productBoProxy");
productBo.save(product, 100);
代理 bean' productBoProxy'和 save()方法是支持事务,现在,里面productBo.save()方法任何异常会导致整个事务回滚,没有数据会被插入到数据库中。下载代码 – http://pan.baidu.com/s/1qXynbo4