一个Hibernate3+Spring Transaction例子
前言:正如我在blog:Why we are using Spring framework?里面提到的那样,Spring framework通过其aop框架为我们提供了一个容器事务处理的实现,通过使用该容器事务处理,我们可以获得一个轻型的容器事务处理,下面我们通过例子我们来说明这些实现。模型: 现在我们来创建一个网上购物系统,在该系统中用户购物与发送数据单,同时系统还可以记录用户的行为
·
前言:正如我在blog:
Why we are using Spring framework?里面提到的那样,Spring framework通过其aop框架为我们提供了一个容器事务处理的实现,通过使用该容器事务处理,我们可以获得一个轻型的容器事务处理,下面我们通过例子我们来说明这些实现。
模型:
现在我们来创建一个网上购物系统,在该系统中用户购物与发送数据单,同时系统还可以记录用户的行为。现在为了简化这个系统,我们只需要三个商业模型,LineItem,OrderList和AuditObject,如下:
这里,这三个模型对应着两个数据库,一个数据库appfuse1用于管理OrderList和LineItem等用户订单数据,而数据库appfuse2则用于管理AuditObject数据,用于记录用户执行的动作。
现在我们为了测试Spring的事务处理,我们假设一个订单最多只能有两种物品,当数目超出2的时候,会提示需要重新申请一个订单,并回滚,但是相应的记录信息在AuditObject并不回滚,也记录这些信息。
我们的实现是使用容器来管理事务,通过xml文件配置,以下是类之间的相关关系:
具体例子:
(1)开发测试环境:eclipse3.1(支持jdk1.5和JUnit),hibernate3(支持annotation),spring2.0m4,hsql,具体的这些配置请参考用户手册等。
(2)相关知识:
ejb3,hibernate3,spring,hsql
(3)数据库服务器配置:
根据我在blog: 流行开源数据库hsql第四点里面所说的那样,以下是server.properties的配置:
server.database.0=db/appfuse1
server.dbname.0=appfuse1
server.database.1=db/appfuse2
server.dbname.1=appfuse2
(4)具体实现:
1.商业model
模型LineItem.java:
// $Id: LineItem.java 2006-5-6 2:01:17 $
package springh3.transaction.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
@Entity
@Table(name = "app_lineitems")
@NamedQuery(
name = "springh3.transaction.model.lineItemByOrder",
query = "from LineItem as item where item.orderList.id=?")
public class LineItem implements Serializable {
static final long serialVersionUID = -4103866707817178530L;
private Long id;
private String productId;
private int numberOfItems;
private OrderList orderList;
@Id
@Column(name="lineitem_id")
@GeneratedValue(generator = "sys-increment")
@GenericGenerator(name = "sys-increment", strategy = "increment")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public int getNumberOfItems() {
return numberOfItems;
}
public void setNumberOfItems(int numberOfItems) {
this.numberOfItems = numberOfItems;
}
@ManyToOne
@JoinColumn(name = "order_id")
public OrderList getOrderList() {
return orderList;
}
public void setOrderList(OrderList orderList) {
this.orderList = orderList;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
@Override
public String toString() {
return this.productId+"("+this.numberOfItems+")";
}
}
模型OrderList.java:
// $Id: OrderList.java 2006-5-6 2:15:09 $
package springh3.transaction.model;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
@Entity
@Table(name="app_orderlist")
@NamedQuery(
name="springh3.transaction.model.orderByOrderId",
query="from OrderList")
public class OrderList implements Serializable{
static final long serialVersionUID = -2442553988169224982L;
private Long id;
private Set<LineItem> lineItems;
@Id
@Column(name="order_id")
@GeneratedValue(generator="sys-increment")
@GenericGenerator(name="sys-increment",strategy="increment")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@OneToMany(cascade=CascadeType.ALL,mappedBy="orderList")
public Set<LineItem> getLineItems() {
return lineItems;
}
public void setLineItems(Set<LineItem> lineItems) {
this.lineItems = lineItems;
}
}
模型AuditObject.java:
// $Id: AuditObject.java 2006-5-6 2:24:57 $
package springh3.transaction.model;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
@Entity
@Table(name="app_auditobject")
public class AuditObject implements Serializable{
static final long serialVersionUID = -3766298732085358604L;
private Long id;
private String who;
private Date when;
private String resource;
private String action;
public AuditObject(){
}
public AuditObject(String resource,String action){
this.resource=resource;
this.action=action;
this.when=new Date();
this.who=System.getProperties().getProperty("user.name");
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
@Id
@Column(name="audit_id")
@GeneratedValue(generator="sys-increment")
@GenericGenerator(name="sys-increment",strategy="increment")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public Date getWhen() {
return when;
}
public void setWhen(Date when) {
this.when = when;
}
public String getWho() {
return who;
}
public void setWho(String who) {
this.who = who;
}
}
2.DAO接口,(具体实现请下载源代码,连接在最后):
OrderListDAO.java接口:
// $Id: OrderListDAO.java 2006-5-6 3:22:53 $
package springh3.transaction.dao;
import java.util.List;
import springh3.transaction.model.LineItem;
import springh3.transaction.model.OrderList;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public interface OrderListDAO {
List getAllOrderList();
OrderList getOrderList(Long id);
Long createOrderList(OrderList orderList);
Long addLineItem(Long orderId,LineItem lineItem);
List getAllLineItems(Long orderId);
int queryNumberOfLineItems(Long orderId);
}
AuditObjectDAO接口:
// $Id: AuditObjectDAO.java 2006-5-6 3:29:52 $
package springh3.transaction.dao;
import springh3.transaction.model.AuditObject;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public interface AuditObjectDAO {
void log(AuditObject auditObject);
}
3.Transaction Manager接口(具体实现在源代码中):
OrderListManager.java接口:
// $Id: OrderListManager.java 2006-5-6 3:13:28 $
package springh3.transaction.service;
import java.util.List;
import springh3.transaction.exception.FacadeException;
import springh3.transaction.model.LineItem;
import springh3.transaction.model.OrderList;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public interface OrderListManager {
List getAllOrderList();
OrderList getOrderList(Long id);
Long createOrderList(OrderList orderList);
void addLineItem(Long orderId,LineItem lineItem) throws FacadeException;
List getAllLineItems(Long orderId);
int queryNumberOfLineItems(Long orderId);
}
AuditManager.java接口:
// $Id: AuditManager.java 2006-5-6 3:20:47 $
package springh3.transaction.service;
import springh3.transaction.model.AuditObject;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public interface AuditManager {
void log(AuditObject auditObject);
}
4.spring的applicationContext.xml文件:
<?xml version="1.0"?>
<!DOCTYPE beans
PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- JDBC Data Source -->
<bean id="dataSource1"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:hsql://localhost/appfuse1" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="dataSource2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:hsql://localhost/appfuse2" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory1"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="annotatedClasses">
<list>
<value>springh3.transaction.model.LineItem</value>
<value>springh3.transaction.model.OrderList</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="sessionFactory2"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="annotatedClasses">
<list>
<value>springh3.transaction.model.AuditObject</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA)-->
<bean id="transactionManager1"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory1" />
</bean>
<bean id="transactionManager2"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
<!-- DAO Beans -->
<bean id="auditObjectDAO"
class="springh3.transaction.dao.hibernate.AuditObjectDAOHibernate">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
<bean id="orderListDAO"
class="springh3.transaction.dao.hibernate.OrderListDAOHibernate">
<property name="sessionFactory" ref="sessionFactory1" />
</bean>
<!-- Manager -->
<bean id="auditManagerTarget"
class="springh3.transaction.service.impl.AuditManagerImpl">
<property name="auditObjectDAO" ref="auditObjectDAO" />
</bean>
<bean id="auditManager"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager2" />
<property name="target" ref="auditManagerTarget" />
<property name="transactionAttributes">
<props>
<prop key="log">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
<bean id="orderListManagerTarget"
class="springh3.transaction.service.impl.OrderListManagerImpl">
<property name="orderListDAO" ref="orderListDAO" />
<property name="auditManager" ref="auditManager" />
</bean>
<bean id="orderListManager"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager1" />
<property name="target" ref="orderListManagerTarget" />
<property name="transactionAttributes">
<props>
<prop key="addLineItem">
PROPAGATION_REQUIRED,-springh3.transaction.exception.FacadeException
</prop>
<prop key="createOrderList">PROPAGATION_REQUIRED</prop>
<prop key="getAllLineItems">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="getAllOrderList">PROPAGATION_REQUIRED</prop>
<prop key="getOrderList">PROPAGATION_REQUIRED</prop>
<prop key="queryNumberOfLineItems">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
</beans>
5.测试代码OrderListManagerTest.java:
// $Id: OrderListManagerTest.java 2006-5-6 12:46:13 $
package springh3.transaction.test;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springh3.transaction.exception.FacadeException;
import springh3.transaction.model.LineItem;
import springh3.transaction.model.OrderList;
import springh3.transaction.service.OrderListManager;
import junit.framework.TestCase;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public class OrderListManagerTest extends TestCase {
private static Log log = LogFactory.getLog(OrderListManagerTest.class);
private ApplicationContext ctx;
private OrderListManager orderListManager;
@Override
protected void setUp() throws Exception {
String[] paths = { "springh3/transaction/test/applicationContext.xml" };
ctx = new ClassPathXmlApplicationContext(paths);
orderListManager = (OrderListManager) ctx.getBean("orderListManager");
}
@Override
protected void tearDown() throws Exception {
orderListManager = null;
}
public void testCreateOrder() throws Exception {
LineItem lineItem1 = new LineItem();
lineItem1.setProductId("Professional Hibernate");
lineItem1.setNumberOfItems(1);
LineItem lineItem2 = new LineItem();
lineItem2.setProductId("Spring Live");
lineItem2.setNumberOfItems(3);
OrderList orderList1 = new OrderList();
Long orderId1 = orderListManager.createOrderList(orderList1);
log("Created OrderList with id '" + orderId1 + "'...");
orderListManager.addLineItem(orderId1, lineItem1);
orderListManager.addLineItem(orderId1, lineItem2);
int numberOfLineItems1 = orderListManager
.queryNumberOfLineItems(orderId1);
log("Number of LineItems for OrderList with id '" + orderId1 + "' is: "
+ numberOfLineItems1);
List lineItemList1 = orderListManager.getAllLineItems(orderId1);
LineItem lineItemFound1 = null;
if ((lineItemList1 != null) && (lineItemList1.size() != 0)) {
log("/nLine items for Order " + orderId1 + " are:");
}
for (Iterator iter = lineItemList1.iterator(); iter.hasNext();) {
lineItemFound1 = (LineItem) iter.next();
log(lineItemFound1);
}
// Test addLineItem(),
// As we know, when numberOfLineItems>2, we will have an exception, but
// still want to proceed
LineItem lineItem3 = new LineItem();
lineItem3.setProductId("Professional .NET");
lineItem3.setNumberOfItems(3);
LineItem lineItem4 = new LineItem();
lineItem4.setProductId("Architecture Bootcamp");
lineItem4.setNumberOfItems(2);
LineItem lineItem5 = new LineItem();
lineItem5.setProductId(".NET Remoting");
lineItem5.setNumberOfItems(4);
OrderList orderList2 = new OrderList();
Long orderId2 = orderListManager.createOrderList(orderList2);
log("Created OrderList with id '" + orderId2 + "'...");
orderListManager.addLineItem(orderId2, lineItem3);
orderListManager.addLineItem(orderId2, lineItem4);
//
try{
orderListManager.addLineItem(orderId2,lineItem5);
}catch(FacadeException fe){
log("ERROR: "+fe.getMessage());
}
int numberOfLineItems2=orderListManager.queryNumberOfLineItems(orderId2);
log("Number of LineItems for OrderList with id '"+orderId2+"' is: "+numberOfLineItems2);
List lineItemList2 = orderListManager.getAllLineItems(orderId2);
LineItem lineItemFound2 = null;
if ((lineItemList2 != null) && (lineItemList2.size() != 0)) {
log("/nLine items for Order " + orderId2 + " are:");
}
for (Iterator iter = lineItemList2.iterator(); iter.hasNext();) {
lineItemFound2 = (LineItem) iter.next();
log(lineItemFound2);
}
}
private static final void log(Object message) {
System.out.println(message.toString());
}
}
(5)测试:
运行数据服务器,然后在eclipse中通过JUnit运行测试代码,测试成功:
...
2006-5-6 14:47:51 springh3.transaction.service.impl.OrderListManagerImpl addLineItem
信息: Added LineItem 5 to Order 2;But rolling back ***!
...
小结:
从上面可以看出,通过spring,我们可以轻松的进行编码实现我们的数据库事务处理,同时还不用部署在web服务器中就可以完成测试,如此轻松简单的功能确实是我们选择spring作为轻型底层框架的原因。
资源下载:
(1) 本文的源代码(附带hsql数据库)
(2) spring官方网址
(3) hibernate官方网址
(4) eclipse官方网址
感谢你的阅读!
对这篇文章有什么疑问的话,请联系作者。作者联系地址: Sidney.J.Yellow@gmail.com
模型:
现在我们来创建一个网上购物系统,在该系统中用户购物与发送数据单,同时系统还可以记录用户的行为。现在为了简化这个系统,我们只需要三个商业模型,LineItem,OrderList和AuditObject,如下:
这里,这三个模型对应着两个数据库,一个数据库appfuse1用于管理OrderList和LineItem等用户订单数据,而数据库appfuse2则用于管理AuditObject数据,用于记录用户执行的动作。
现在我们为了测试Spring的事务处理,我们假设一个订单最多只能有两种物品,当数目超出2的时候,会提示需要重新申请一个订单,并回滚,但是相应的记录信息在AuditObject并不回滚,也记录这些信息。
我们的实现是使用容器来管理事务,通过xml文件配置,以下是类之间的相关关系:
具体例子:
(1)开发测试环境:eclipse3.1(支持jdk1.5和JUnit),hibernate3(支持annotation),spring2.0m4,hsql,具体的这些配置请参考用户手册等。
(2)相关知识:
ejb3,hibernate3,spring,hsql
(3)数据库服务器配置:
根据我在blog: 流行开源数据库hsql第四点里面所说的那样,以下是server.properties的配置:
server.database.0=db/appfuse1
server.dbname.0=appfuse1
server.database.1=db/appfuse2
server.dbname.1=appfuse2
(4)具体实现:
1.商业model
模型LineItem.java:
// $Id: LineItem.java 2006-5-6 2:01:17 $
package springh3.transaction.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
@Entity
@Table(name = "app_lineitems")
@NamedQuery(
name = "springh3.transaction.model.lineItemByOrder",
query = "from LineItem as item where item.orderList.id=?")
public class LineItem implements Serializable {
static final long serialVersionUID = -4103866707817178530L;
private Long id;
private String productId;
private int numberOfItems;
private OrderList orderList;
@Id
@Column(name="lineitem_id")
@GeneratedValue(generator = "sys-increment")
@GenericGenerator(name = "sys-increment", strategy = "increment")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public int getNumberOfItems() {
return numberOfItems;
}
public void setNumberOfItems(int numberOfItems) {
this.numberOfItems = numberOfItems;
}
@ManyToOne
@JoinColumn(name = "order_id")
public OrderList getOrderList() {
return orderList;
}
public void setOrderList(OrderList orderList) {
this.orderList = orderList;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
@Override
public String toString() {
return this.productId+"("+this.numberOfItems+")";
}
}
模型OrderList.java:
// $Id: OrderList.java 2006-5-6 2:15:09 $
package springh3.transaction.model;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
@Entity
@Table(name="app_orderlist")
@NamedQuery(
name="springh3.transaction.model.orderByOrderId",
query="from OrderList")
public class OrderList implements Serializable{
static final long serialVersionUID = -2442553988169224982L;
private Long id;
private Set<LineItem> lineItems;
@Id
@Column(name="order_id")
@GeneratedValue(generator="sys-increment")
@GenericGenerator(name="sys-increment",strategy="increment")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@OneToMany(cascade=CascadeType.ALL,mappedBy="orderList")
public Set<LineItem> getLineItems() {
return lineItems;
}
public void setLineItems(Set<LineItem> lineItems) {
this.lineItems = lineItems;
}
}
模型AuditObject.java:
// $Id: AuditObject.java 2006-5-6 2:24:57 $
package springh3.transaction.model;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
@Entity
@Table(name="app_auditobject")
public class AuditObject implements Serializable{
static final long serialVersionUID = -3766298732085358604L;
private Long id;
private String who;
private Date when;
private String resource;
private String action;
public AuditObject(){
}
public AuditObject(String resource,String action){
this.resource=resource;
this.action=action;
this.when=new Date();
this.who=System.getProperties().getProperty("user.name");
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
@Id
@Column(name="audit_id")
@GeneratedValue(generator="sys-increment")
@GenericGenerator(name="sys-increment",strategy="increment")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public Date getWhen() {
return when;
}
public void setWhen(Date when) {
this.when = when;
}
public String getWho() {
return who;
}
public void setWho(String who) {
this.who = who;
}
}
2.DAO接口,(具体实现请下载源代码,连接在最后):
OrderListDAO.java接口:
// $Id: OrderListDAO.java 2006-5-6 3:22:53 $
package springh3.transaction.dao;
import java.util.List;
import springh3.transaction.model.LineItem;
import springh3.transaction.model.OrderList;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public interface OrderListDAO {
List getAllOrderList();
OrderList getOrderList(Long id);
Long createOrderList(OrderList orderList);
Long addLineItem(Long orderId,LineItem lineItem);
List getAllLineItems(Long orderId);
int queryNumberOfLineItems(Long orderId);
}
AuditObjectDAO接口:
// $Id: AuditObjectDAO.java 2006-5-6 3:29:52 $
package springh3.transaction.dao;
import springh3.transaction.model.AuditObject;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public interface AuditObjectDAO {
void log(AuditObject auditObject);
}
3.Transaction Manager接口(具体实现在源代码中):
OrderListManager.java接口:
// $Id: OrderListManager.java 2006-5-6 3:13:28 $
package springh3.transaction.service;
import java.util.List;
import springh3.transaction.exception.FacadeException;
import springh3.transaction.model.LineItem;
import springh3.transaction.model.OrderList;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public interface OrderListManager {
List getAllOrderList();
OrderList getOrderList(Long id);
Long createOrderList(OrderList orderList);
void addLineItem(Long orderId,LineItem lineItem) throws FacadeException;
List getAllLineItems(Long orderId);
int queryNumberOfLineItems(Long orderId);
}
AuditManager.java接口:
// $Id: AuditManager.java 2006-5-6 3:20:47 $
package springh3.transaction.service;
import springh3.transaction.model.AuditObject;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public interface AuditManager {
void log(AuditObject auditObject);
}
4.spring的applicationContext.xml文件:
<?xml version="1.0"?>
<!DOCTYPE beans
PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- JDBC Data Source -->
<bean id="dataSource1"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:hsql://localhost/appfuse1" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="dataSource2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:hsql://localhost/appfuse2" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory1"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="annotatedClasses">
<list>
<value>springh3.transaction.model.LineItem</value>
<value>springh3.transaction.model.OrderList</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="sessionFactory2"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="annotatedClasses">
<list>
<value>springh3.transaction.model.AuditObject</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA)-->
<bean id="transactionManager1"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory1" />
</bean>
<bean id="transactionManager2"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
<!-- DAO Beans -->
<bean id="auditObjectDAO"
class="springh3.transaction.dao.hibernate.AuditObjectDAOHibernate">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
<bean id="orderListDAO"
class="springh3.transaction.dao.hibernate.OrderListDAOHibernate">
<property name="sessionFactory" ref="sessionFactory1" />
</bean>
<!-- Manager -->
<bean id="auditManagerTarget"
class="springh3.transaction.service.impl.AuditManagerImpl">
<property name="auditObjectDAO" ref="auditObjectDAO" />
</bean>
<bean id="auditManager"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager2" />
<property name="target" ref="auditManagerTarget" />
<property name="transactionAttributes">
<props>
<prop key="log">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
<bean id="orderListManagerTarget"
class="springh3.transaction.service.impl.OrderListManagerImpl">
<property name="orderListDAO" ref="orderListDAO" />
<property name="auditManager" ref="auditManager" />
</bean>
<bean id="orderListManager"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager1" />
<property name="target" ref="orderListManagerTarget" />
<property name="transactionAttributes">
<props>
<prop key="addLineItem">
PROPAGATION_REQUIRED,-springh3.transaction.exception.FacadeException
</prop>
<prop key="createOrderList">PROPAGATION_REQUIRED</prop>
<prop key="getAllLineItems">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="getAllOrderList">PROPAGATION_REQUIRED</prop>
<prop key="getOrderList">PROPAGATION_REQUIRED</prop>
<prop key="queryNumberOfLineItems">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
</beans>
5.测试代码OrderListManagerTest.java:
// $Id: OrderListManagerTest.java 2006-5-6 12:46:13 $
package springh3.transaction.test;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springh3.transaction.exception.FacadeException;
import springh3.transaction.model.LineItem;
import springh3.transaction.model.OrderList;
import springh3.transaction.service.OrderListManager;
import junit.framework.TestCase;
/**
* @author Sidney J.Yellow(Sidney.J.Yellow@gmail.com)
*/
public class OrderListManagerTest extends TestCase {
private static Log log = LogFactory.getLog(OrderListManagerTest.class);
private ApplicationContext ctx;
private OrderListManager orderListManager;
@Override
protected void setUp() throws Exception {
String[] paths = { "springh3/transaction/test/applicationContext.xml" };
ctx = new ClassPathXmlApplicationContext(paths);
orderListManager = (OrderListManager) ctx.getBean("orderListManager");
}
@Override
protected void tearDown() throws Exception {
orderListManager = null;
}
public void testCreateOrder() throws Exception {
LineItem lineItem1 = new LineItem();
lineItem1.setProductId("Professional Hibernate");
lineItem1.setNumberOfItems(1);
LineItem lineItem2 = new LineItem();
lineItem2.setProductId("Spring Live");
lineItem2.setNumberOfItems(3);
OrderList orderList1 = new OrderList();
Long orderId1 = orderListManager.createOrderList(orderList1);
log("Created OrderList with id '" + orderId1 + "'...");
orderListManager.addLineItem(orderId1, lineItem1);
orderListManager.addLineItem(orderId1, lineItem2);
int numberOfLineItems1 = orderListManager
.queryNumberOfLineItems(orderId1);
log("Number of LineItems for OrderList with id '" + orderId1 + "' is: "
+ numberOfLineItems1);
List lineItemList1 = orderListManager.getAllLineItems(orderId1);
LineItem lineItemFound1 = null;
if ((lineItemList1 != null) && (lineItemList1.size() != 0)) {
log("/nLine items for Order " + orderId1 + " are:");
}
for (Iterator iter = lineItemList1.iterator(); iter.hasNext();) {
lineItemFound1 = (LineItem) iter.next();
log(lineItemFound1);
}
// Test addLineItem(),
// As we know, when numberOfLineItems>2, we will have an exception, but
// still want to proceed
LineItem lineItem3 = new LineItem();
lineItem3.setProductId("Professional .NET");
lineItem3.setNumberOfItems(3);
LineItem lineItem4 = new LineItem();
lineItem4.setProductId("Architecture Bootcamp");
lineItem4.setNumberOfItems(2);
LineItem lineItem5 = new LineItem();
lineItem5.setProductId(".NET Remoting");
lineItem5.setNumberOfItems(4);
OrderList orderList2 = new OrderList();
Long orderId2 = orderListManager.createOrderList(orderList2);
log("Created OrderList with id '" + orderId2 + "'...");
orderListManager.addLineItem(orderId2, lineItem3);
orderListManager.addLineItem(orderId2, lineItem4);
//
try{
orderListManager.addLineItem(orderId2,lineItem5);
}catch(FacadeException fe){
log("ERROR: "+fe.getMessage());
}
int numberOfLineItems2=orderListManager.queryNumberOfLineItems(orderId2);
log("Number of LineItems for OrderList with id '"+orderId2+"' is: "+numberOfLineItems2);
List lineItemList2 = orderListManager.getAllLineItems(orderId2);
LineItem lineItemFound2 = null;
if ((lineItemList2 != null) && (lineItemList2.size() != 0)) {
log("/nLine items for Order " + orderId2 + " are:");
}
for (Iterator iter = lineItemList2.iterator(); iter.hasNext();) {
lineItemFound2 = (LineItem) iter.next();
log(lineItemFound2);
}
}
private static final void log(Object message) {
System.out.println(message.toString());
}
}
(5)测试:
运行数据服务器,然后在eclipse中通过JUnit运行测试代码,测试成功:
...
2006-5-6 14:47:51 springh3.transaction.service.impl.OrderListManagerImpl addLineItem
信息: Added LineItem 5 to Order 2;But rolling back ***!
...
小结:
从上面可以看出,通过spring,我们可以轻松的进行编码实现我们的数据库事务处理,同时还不用部署在web服务器中就可以完成测试,如此轻松简单的功能确实是我们选择spring作为轻型底层框架的原因。
资源下载:
(1) 本文的源代码(附带hsql数据库)
(2) spring官方网址
(3) hibernate官方网址
(4) eclipse官方网址
感谢你的阅读!
对这篇文章有什么疑问的话,请联系作者。作者联系地址: Sidney.J.Yellow@gmail.com
更多推荐
已为社区贡献2条内容
所有评论(0)