- 浏览: 261960 次
- 性别:
- 来自: 多伦多
文章分类
- 全部博客 (127)
- Java 基础 (46)
- Java EE (3)
- Clouds (1)
- Spring 编程 (7)
- Spring Batch 编程 (1)
- Quartz 编程 (9)
- Seam 编程 (4)
- Hibernate 编程 (1)
- JSF 编程 (3)
- jQuery 编程 (3)
- Interview Question 汇总 (3)
- 日常应用 (3)
- Maven 编程 (2)
- WebService 编程 (10)
- Scala 编程 (5)
- Coherence 编程 (8)
- OO 编程 (1)
- Java 线程 (6)
- DB 编程 (2)
- WebService 安全 (4)
- Oracle Fusion 编程 (2)
- JavsScript/Ajax 编程 (1)
最新评论
-
chainal:
赞,说的很好
Scala 有趣的Trait -
wuliupo:
RRRR-MM-DD HH24:MI:SS
如何让Oracle SQL Developer显示的包含在日期字段中的时间 -
pengain:
...
使用Spring Roo ,感受ROR式的开发 -
zeng1990:
def getPersonInfo() = {
(&quo ...
Java 的继位人? - Scala简介 -
zeng1990:
我使用的是2.9.2版本的!
Java 的继位人? - Scala简介
来自:http://webservices.ctocio.com.cn/tips/344/6115844.shtml
本文主要探讨怎么用Spring来装配组件及其事务管理。在J2EE工程里连接到一个简单的数据库并不是什么难题,但是如果要综合组装企业类的组件就变得复杂了。一个简单的组件有一个或多个数据库支撑,所以,我们说到整合两个或多个的组件时,我们希望能够维持跨组件的许多数据库的运作的原子性。 J2EE提供了这些组件的容器,可以保证处理的原子性和独立性。在没有J2EE的情况下我们可以用Spring。Spring基于IoC模式(即反转模式),不仅可以配置组件服务,还可以配置相应的方法。为了更好的实现本文的目的,我们使用Hibernate来做相应的后台开发。 装配组件事务
假设在组件库里,我们已经有一个审核组件(audit component),里面有可以被客户端调用的方法。接着,当我们想要构建一个处理订单的体系,我们发现设计需要的OrderListManager组件服务同样需要审核组件服务。OrderListManager创建和管理订单,每一个服务都含有自己的事务属性。当这时调用审核组件,就可以把OrderListManager的处理内容传给它。也许将来新的业务服务(business service)同样需要审核组件,那这时它调用的事务内容已经不一样了。在网络上的结果就是,虽然审核的功能保持不变,但是可以和别的事件功能组合在一起,用这些方法属性来提供不同的运行时的处理参数。 在图1中有两个分开的调用流程。在流程1里,如果客户端含有一个TX内容,OrderListManager 要由一个新的TX开始或者参与其中,取决于客户端在不在TX里以及OrderListManager方法指定的TX属性。这在它调用AuditManager方法的时候仍然适用。 图1. 装配组件事务 EJB体系通过装配者声明正确的事务属性来获得这种适应性。我们不是在探讨是否声明事务管理,因为这会使运行时的事务参数代码发生改变。几乎所有的J2EE工程提供了分布的事务管理来配合提交协议例如X/Open XA specification。 现在的问题是我们能不能不用EJB来获得相同的功能?Spring是其中一种解决方案。来看一下Spring如何处理这样的问题: 用Spring来管理事务
我们将看到的是一个轻量级的事务机制,实际上,它可以管理组件层的事务集成。Spring就是如此。它的优点是我们可以不用捆绑在J2EE的服务例如JNDI数据库。最棒的是如果我们想把这个事务机制与已经存在的J2EE框架组合在一起,没有任何问题,就好像我们找到了杠杆中完美的支撑点一样。 Spring的另一个机制是使用了AOP框架。这个框架使用了一个可以使用AOP的Spring bean factory。在Spring特定的配置文件applicationContext.xml里通过特定的组件层的事件来指定。 <beans>
<!-- other code goes here... -->
<bean id="orderListManager" </beans>
一旦我们在服务层指定了事务属性,它们就被一个继承org.springframework.transaction.PlatformTransactionManager 接口的类截获. 这个接口如下: public interface PlatformTransactionManager{ Hibernate事务管理
一旦我们决定了使用Hibernate作为ORM工具,我们下一步要做的就是用Hibernate特定的事务管理实例来配置。 <beans>
<!-- other code goes here... -->
<bean id="transactionManager1" </beans>
我们来看看什么是“装配组件事务”,你也许注意到了那个OrderListManager 特有的TX属性,那个服务层的组件。我们的工程的主要的东西在表2的BDOM里: 图 2. 业务领域对象模型 (BDOM) 为了用实例说明,我们来列出工程里的非功能需求(NFR): ---事务在数据库appfuse1里保存。 出于以上的考虑,我们决定了OrderListManager 服务将委托任何审核记录来调用已有的AuditManager 组件.这产生了表3这样更细致的结构: 图 3. 组件服务结构设计 值得注意的是,由于我们的NFR,我们要映射OrderListManager相关的事物到appfuse1 数据库里去,而审核相关的到appfuse2。这样,任何审核的时候 OrderListManager 组件都会调用AuditManager 组件。我们认为OrderListManager 组件里的所有方法都要执行, 因为我们通过服务来创建次序和具体项目。那么AuditManager 组件里的服务呢? 因为它做的是审核的动作,我们关心的是为系统里所有的事务记录审核情况。这样的需求是,“即使事务事件失败了,我们也要记录登录的审核情况”。AuditManager 组件同样要有自己的事件,因为它同样与自己的数据库有关联。如下所示: <beans>
<!—其他代码在这里--> </beans>
我们现在把注意力放到这两个事务createOrderList 和 addLineItem中来,作为我们的试验。同时注意我们并没有要求最好的设计——你可能注意到了 addLineItem 方法抛出了 FacadeException, 而 createOrderList 没有。在产品设计中,你也许希望每一个方法都处理异常。 public class OrderListManagerImpl private AuditManager auditManager;
public Long createOrderList public void addLineItem Long lineItemId = orderListDAO. //其他代码在这里
}
要创建一个这个试验的异常,我们已经介绍了其他事务规则规定一个特定的次序不能在同一行里包含两个项目。我们应该注意到createOrderList 和 addLineItem调用了auditManager.log() 方法。你应该也注意到了上面方法中的事务属性。 <bean id="orderListManager" <bean id="auditManager" class="org. PROPAGATION_REQUIRED 和 TX_REQUIRED相同,而PROPAGATION_REQUIRES_NEW 和在EJB里的 TX_REQUIRES_NEW 相同。如果我们想让方法一直在事务里运行,可以用PROPAGATION_REQUIRED。这时,如果有一个TX已经运行了,bean的方法就会加入到TX里,或者Spring的TX管理器给你新建一个。如果我们想一旦方法被调用,就创建一个新的事务实例,我们可以用PROPAGATION_REQUIRES_NEW 属性。 我们同样要让addLineItem 一直都在抛出FacadeException异常时回滚事务。在我们有异常的情况下,使得我们可以很好的控制TX结束达到了另一个级别。前缀-符号表示回滚TX,而+ 符号表示提交TX。 接下来的问题是为什么我们给log方法设置一个PROPAGATION_REQUIRES_NEW呢?这是因为我们要做的是无论主函数怎么运行,我们都要为所有订单的创建和项目的添加记录审核情况。就是说即使在运行createOrderList 和 addLineItem 的时候抛出了异常也要记录。这仅在我们开始一个新的TX并调用log的时候起作用。这就是为什么要给它设置的原因: 如果调用auditManager.log(new AuditObject(LINE_ITEM + lineItemId, CREATE));成功了, auditManager.log() 将在新的TX里发生,这样auditManager.log() 成功的话就会被提交 (前提是不抛出异常)。 设置试验工程的环境
为了运行这个工程,我们来按Spring Live 这本书的流程进行: 1. 下载并安装以下组件,注意版本,不然会引起一系列的问题 o JDK 1_5_0_01 或更高 2. 配置系统环境变量: o JAVA_HOME 3. 把下列目录添加到你的PATH变量中去或者用绝对路径来运行你的程序: o JAVA_HOME\bin 4. 要配置Tomcat, 打开 $CATALINA_HOME/conf/tomcat-users.xml 确保里面有下面这段文字,如果没有就手动添加进去: <role rolename="manager"/><user username="admin" password="admin" roles="manager"/>
5. 要创建基于Struts,Spring, 和 Hibernate的web工程,我们要用Equinox来构建一个空白的框架,这将包含上面提到的文件结构,所有需要用到的jar文件,还有ant构建脚本。把Equinox解压到一个文件夹中,将创建一个equinox文件夹。到equinox文件夹里去,输入命令ANT_HOME\bin\ant new -Dapp.name=myusers。这样就会创建一个和equinox结构一样的文件夹myusers 。具体内容如下: 图 4. Equinox myusers 工程文件夹 6. 删掉myusers\web\WEB-INF目录下所有的xml文件。 7. 复制 equinox\extras\struts\web\WEB-INF\lib\struts*.jar 到 myusers\web\WEB-INF\lib,这样这个工程就可以用struts了。 8. 用本文最后的资源里的代码, 解压myusersextra.zip 到相应位置。 把目录下的所有内容拷贝到myusers目录下。 9. 打开命令行转到myusers目录下。输入CATALINA_HOME\bin\startup 从myusers 目录启动Tomcat可以保证数据库在myusers 文件夹里创建,这样可以避免在运行build.xml里定义的任务发生错误。 10. 再次打开命令行转到myusers。执行 Execute ANT_HOME\bin\ant install。这样将创建整个工程并把它部署到Tomcat里。这时我们可以看到myusers 里多了一个 db 目录,里面存放数据库 appfuse1 和 appfuse2。 11. 打开浏览器确定myusers 工程部署在http://localhost:8080/myusers/ 12. 要重建工程,执行ANT_HOME\bin\ant remove,用CATALINA_HOME\bin\shutdown关掉Tomcat.并在CATALINA_HOME\webapps里删掉 myusers 文件夹。然后用CATALINA_HOME\bin\startup 重启Tomcat然后用ANT_HOME\bin\ant install重构工程。 执行工程
如果要测试,OrderListManagerTest,在myusers\test\com\example\service 目录下可以运行作为JUnit测试。要运行的话,在构建工程时加入以下代码: CATALINA_HOME\bin\ant test -Dtestcase=OrderListManager
测试工程分为两个主要部分:第一个部分创建两行项目的一个排列,并把这两个链接到排列中。如下所示,可以成功运行: OrderList orderList1 = new OrderList(); 另一个执行类似的事件,但是这时我们添加三行到排列中去,将产生一个异常 OrderList orderList2 = new OrderList(); 输出窗口如图5所示: 图 5. 客户端输出 我们创建了Order1,添加了两个ID是1和2的项目到里面去。然后创建Order2, 试图添加3个项目,前两个(ID是3和4)成功了,如图5所示添加ID为5的项目时抛出了异常。然后,事务回滚,数据库里没有ID为5的项目。执行以下代码从图6和图7可以看出: CATALINA_HOME\bin\ant browse1 图 6. appfuse1 数据库里的排列 图 7. appfuse1里的项目 接下来,试验中可以看出次序和项目存在appfuse1 里,而审核部分在appfuse2里. OrderListManager 同时访问两个数据库。打开 appfuse2 数据库,看审核记录的细节: CATALINA_HOME\bin\ant browse2 图 8. appfuse2数据库里的审核记录, 包括失败的TX 表8最后一列尤其值得注意,RESOURCE这一栏上显示这一行对应着LineItem5。 但是当我们回过来看图7,却发现并没有这种对应。这是个错误吗?事实上,没有问题,图7里没有的那行其实是这篇文章的精华所在,让我们来看看是怎么回事。 首先addLineItem() 方法有 PROPAGATION_REQUIRED 属性而 log() 方法有PROPAGATION_REQUIRES_NEW。进而, addLineItem() 在内部调用log() 方法。所以我们往第二个排列里添加第三个表项时,发生了异常 (由于我们的事务规则),就将这个创建过程和链接都回滚了。但是,因为已经调用了log(),而log()有PROPAGATION_REQUIRES_NEW TX 属性,回滚了addLineItem() 不会回滚 log(), 因为 log() 是在一个新的TX里。 让我们现在改变一下log()的TX属性。把PROPAGATION_REQUIRES_NEW 替换成PROPAGATION_SUPPORTS。ROPAGATION_SUPPORTS 属性允许方法在客户端的TX里运行,如果客户端有TX,否则就不用TX。你需要重建工程让这些变化自动被刷新。请按照设置工程环境的第12步。 重新开始的话,我们会发现有一点不同。这次,我们在往排列2添加第三项时依然有异常。发生回滚。这时方法调用了log()方法。由于它有着PROPAGATION_SUPPORTSTX属性, log() 将在同一个addLineItem() 方法环境下调用。由于 addLineItem() 回滚,log() 也回滚了,没有留下审核记录。所以在图9里没有这项失败的记录! Figure 9. appfuse2数据库的审核记录,没有失败的TX 我们所改变的仅仅是TX属性,如下所示: <bean id="auditManager" 这是生成实例管理的效果,自从我们接触EJB以来就开始寻找杠杆的最佳位置。我们需要一个高端的应用服务器 来管理我们的our EJB组件。现在我们不用EJB服务器就达到了一样的结果,用Spring。 这篇文章介绍了J2EE里十分强大的组合之一:Spring 和 Hibernate。通过两者的有机结合,我们现在多了对Container-Managed Persistence (CMP), Container-Managed Relationships (CMR), 和生成实例管理的新选择。虽然Spring不能完全代替EJB,但是它提供了很多功能,例如一般Java程序的实例生成,使得用户可以在大部分工程中和EJB搭配使用。 我们不是要为了寻找EJB的代替品,而是对于现在的问题得出一个最理想的解决方案。我们仍然要寻找Spring 和 Hibernate组合的更多优点,这就留给我们的读者去探索了。
class="org.springframework.transaction
.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager1"/>
</property>
<property name="target">
<ref local="orderListManagerTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="getAllOrderList">
PROPAGATION_REQUIRED
</prop>
<prop key="getOrderList">
PROPAGATION_REQUIRED
</prop>
<prop key="createOrderList">
PROPAGATION_REQUIRED
</prop>
<prop key="addLineItem">
PROPAGATION_REQUIRED,
-com.example.exception.FacadeException
</prop>
<prop key="getAllLineItems">
PROPAGATION_REQUIRED,readOnly
</prop>
<prop key="queryNumberOfLineItems">
PROPAGATION_REQUIRED,readOnly
</prop>
</props>
</property>
</bean>
TransactionStatus getTransaction
(TransactionDefinition definition);
void commit(TransactionStatus status);
void rollback(TransactionStatus status);
}
class="org.springframework.orm.hibernate.
HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory1"/>
</property>
</bean>
---审核时要登入到另一个数据库appfuse2里,出于安全的考虑,数据库有防火墙保护。
---事务组件可以重用。
---所有访问事件必须经过在事务服务层的审核。
<bean id="auditManager"
class="org.springframework.transaction.
interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager2"/>
</property>
<property name="target">
<ref local="auditManagerTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="log">
PROPAGATION_REQUIRES_NEW
</prop>
</props>
</property>
</bean>
implements OrderListManager{
(OrderList orderList){
Long orderId = orderListDAO.
createOrderList(orderList);
auditManager.log(new AuditObject
(ORDER + orderId, CREATE));
return orderId;
}
(Long orderId, LineItem lineItem)
throws FacadeException{
addLineItem(orderId, lineItem);
auditManager.log(new AuditObject
(LINE_ITEM + lineItemId, CREATE));
int numberOfLineItems = orderListDAO.
queryNumberOfLineItems(orderId);
if(numberOfLineItems > 2){
log("Added LineItem " + lineItemId +
" to Order " + orderId + ";
But rolling back *** !");
throw new FacadeException("Make a new
Order for this line item");
}
else{
log("Added LineItem " + lineItemId +
" to Order " + orderId + ".");
}
}
class="org.springframework.transaction.
interceptor.TransactionProxyFactoryBean">
<property name="transactionAttributes">
<props>
<prop key="createOrderList">
PROPAGATION_REQUIRED
</prop>
<prop key="addLineItem">
PROPAGATION_REQUIRED,-com.
example.exception.FacadeException
</prop>
</props>
</property>
</bean>
springframework.transaction.interceptor.
TransactionProxyFactoryBean">
<property name="transactionAttributes">
<props>
<prop key="log">
PROPAGATION_REQUIRES_NEW
</prop>
</props>
</property>
</bean>
o Apache Tomcat 5.5.7
o Apache Ant 1.6.2
o Equinox 1.2
o CATALINA_HOME
o ANT_HOME
o CATALINA_HOME\bin
o ANT_HOME\bin
Long orderId1 = orderListManager.
createOrderList(orderList1);
log("Created OrderList with id '"
+ orderId1 + "'...");
orderListManager.addLineItem(orderId1,lineItem1);
orderListManager.addLineItem(orderId1,lineItem2);
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 facadeException){
log("ERROR : " + facadeException.getMessage());
}
class="org.springframework.transaction.
interceptor.TransactionProxyFactoryBean">
<property name="transactionAttributes">
<props>
<!-- prop key="log">
PROPAGATION_REQUIRES_NEW
</prop -->
<prop key="log">
PROPAGATION_SUPPORTS
</prop>
</props>
</property>
</bean>
发表评论
-
Spring roo
2010-11-25 06:25 2864转自 http://nottiansyf ... -
使用Spring Roo ,感受ROR式的开发
2010-11-25 06:22 3315Roo是一种 Spring 开发的辅助工具,使用 ... -
What is Spring Roo?
2010-11-25 06:21 1853转自 http://wangzaixiang.blo ... -
Spring HTTP Invoker
2010-11-25 05:46 2357转自 http://zhenggm.ite ... -
Spring实现分布式事务处理(两阶段提交事务)
2010-05-21 05:02 10592来自:http://www.iteye.com/topic/8 ... -
Spring本地事务与JTA事务实现解析
2010-05-21 02:39 1507来自:http://www.blogjava.net/luoq ...
相关推荐
在Spring框架中配置Hibernate事务管理是一项关键任务,它允许开发者以声明式的方式处理数据库操作的事务性,确保数据的一致性和完整性。以下是如何在Spring中配置Hibernate事务的详细步骤和概念解释。 首先,理解...
总结,本项目展示了如何在Spring MVC和Hibernate环境中实现事务管理,通过MyEclipse自动生成的包和配置文件,简化了开发流程。在实际应用中,这样的整合能够提供高效且易于维护的Web应用,同时,声明式事务管理极大...
4. **配置DataSource**:同样在Spring配置文件中,定义一个DataSource Bean,这通常是连接池的实现,如Apache DBCP或C3P0,用于管理数据库连接。 5. **配置Hibernate SessionFactory Bean**:使用`...
在上面的例子中,`saveUser`方法会在一个事务中执行,如果发生异常,整个事务会被回滚,确保数据的一致性。 总结一下,`Spring Hibernate事务实例`涵盖了以下核心知识点: 1. Spring框架的声明式事务管理:通过`...
最后,我们可以在测试类中使用`@RunWith(SpringJUnit4ClassRunner.class)`和`@ContextConfiguration`注解来加载Spring配置,并进行事务相关的测试。 总的来说,Spring 3和Hibernate 4结合使用声明式事务管理,使得...
要启用注解事务管理,需要在Spring配置文件中添加`<tx:annotation-driven/>`元素,并配置数据源和事务管理器,如`PlatformTransactionManager`。 2. **Spring整合Hibernate实现事务处理 - XML方式** 对于不熟悉...
以下是一段示例代码,展示了如何在Spring中配置Hibernate事务管理: ```xml <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <!-- Hibernate配置 --> ...
5. **配置Spring和Hibernate**:在Spring 3中,我们需要配置Hibernate SessionFactory,并将其与Spring的事务管理器相结合。这通常通过XML配置文件或Java配置类完成。同时,需要为数据源、SessionFactory和事务管理...
3. 配置事务管理器:在Spring配置文件中,定义一个PlatformTransactionManager类型的bean,通常是HibernateTransactionManager,它将与SessionFactory配合处理事务。 4. 使用AOP声明事务:在DAO方法上使用`@...
7. **测试验证**:编写测试用例,检查在分布式事务中的正常操作和异常情况,确保事务管理的正确性。 以上就是Spring结合Druid和Hibernate,使用Atomikos实现JTA配置分布式事务的基本流程。在实际应用中,还需要考虑...
3. **Hibernate事务配置:**在Spring中,需要配置Hibernate SessionFactory,并将其注入到需要进行数据库操作的服务中。同时,通过`PlatformTransactionManager`接口(如HibernateTransactionManager)配置事务管理...
- 首先,我们需要在Spring配置文件中启用事务管理器,通常是`HibernateTransactionManager`,并配置数据源。 - 然后,启用AOP代理,以便Spring可以在适当的时候处理事务。 2. **配置Hibernate**: - 创建...
通过声明式事务管理,我们只需在方法上添加`@Transactional`注解,即可声明该方法在一个事务中执行。 接下来,我们将深入讨论Spring中的声明式事务管理。在Spring配置文件中,我们需要开启事务管理器,并在需要事务...
4. **集成Hibernate**:配置Hibernate的SessionFactory,并将其注入到业务层的DAO(数据访问对象)中,用于数据库操作。 在项目实践中,`bankmoney`可能代表了一个银行资金管理的模块,可能包含相关的DAO、Service...
本篇将详细介绍如何在Spring 3和Hibernate 4中配置声明式事务管理,采用注解方式。 一、Spring的事务管理 Spring提供了两种事务管理方式:编程式事务管理和声明式事务管理。编程式事务管理需要在代码中显式地调用...
标题中的“memcache也spring,hibernate的配置”指的是如何在Java开发环境中,结合Memcached缓存系统、Spring框架和Hibernate持久化框架进行集成配置。Memcached是一种高性能的分布式内存对象缓存系统,用于加速动态...
2. **Hibernate事务**: Hibernate本身也提供了一种事务管理机制,但在Spring环境中,我们通常使用Spring的事务管理器来协调。当@Transactional注解应用于方法上,Spring会在该方法执行前后自动管理事务的开始和结束...
为了整合这两个库,你需要在Spring配置文件中定义Hibernate的SessionFactory,并配置数据源。Spring通过`LocalSessionFactoryBean`来创建SessionFactory,它会读取Hibernate的配置文件(如hibernate.cfg.xml),并...
3. Spring与Hibernate集成:如何在Spring应用中配置和使用Hibernate,包括SessionFactory的配置、事务管理、数据源的设置等。 4. ORM实践:使用Hibernate注解进行对象关系映射,以及HQL和Criteria查询的使用。 5. ...