`
houkai2009
  • 浏览: 226611 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
  • 浪迹随风: 文章是挺好的,不过太杂了。。。信息量也很大。。。很难消化。。。 ...
    EJB 介绍
  • javaersu: yds3300376yd 写道学习了,只是楼主写的有点杂,现在 ...
    EJB 介绍
  • yds3300376yd: 学习了,只是楼主写的有点杂,现在还看不太懂,刚学习EJB,我觉 ...
    EJB 介绍
  • javaersu: 不错,这里也有一篇类似的EJB文章教程http://www.y ...
    EJB 介绍
  • dingding5060: brother , 你贴代码想说明什么???
    enum

数据持久层-----事务管理

    博客分类:
  • ejb
阅读更多

对于J2EE 应用程序而言,事务的处理一般有两种模式:
1. 依赖特定事务资源的事务处理
这是应用开发中最常见的模式,即通过特定资源提供的事务机制进行事务管理。
如通过JDBC、JTA 的rollback、commit方法;Hibernate Transaction 的
rollback、commit方法等。这种方法大家已经相当熟悉。
2. 依赖容器的参数化事务管理
通过容器提供的集约式参数化事务机制,实现事务的外部管理,如EJB 中的事
务管理模式。
如,下面的EJB事务定义中,将SessionBean MySession的doService方
法定义为Required。
也就是说,当MySession.doServer 方法被某个线程调用时,容器将此线程
纳入事务管理容器,方法调用过程中如果发生异常,当前事务将被容器自动回
滚,如果方法正常结束,则容器将自动提交当前事务。
<container-transaction >
<method >
<ejb-name>MySession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doService</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
容器管理的参数化事务为程序开发提供了相当的灵活性,同时因为将事务委
托给容器进行管理,应用逻辑中无需再编写事务代码,大大节省了代码量(特
别是针对需要同时操作多个事务资源的应用),从而提高了生产率。
然而,使用EJB 事务管理的代价相当高昂,撇开EJB 容器不菲的价格,EJB
的学习成本,部署、迁移、维护难度,以及容器本身带来的性能开销(这往往
意味着需要更高的硬件配置)都给我们带来了相当的困惑。此时事务管理所带
来的优势往往还不能抵消上面这些负面影响。
Spring事务管理能给我们带来什么?
对于传统的基于特定事务资源的事务处理而言(如基于JDBC 的数据库访问),
Spring并不会对其产生什么影响,我们照样可以成功编写并运行这样的代码。同时,
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
Spring还提供了一些辅助类可供我们选择使用,这些辅助类简化了传统的数据库操作
流程,在一定程度上节省了工作量,提高了编码效率。
对于依赖容器的参数化事务管理而言,Spring 则表现出了极大的价值。Spring
本身也是一个容器,只是相对EJB容器而言,Spring显得更为轻便小巧。我们无需付
出其他方面的代价,即可通过Spring实现基于容器的事务管理(本质上来讲,Spring
的事务管理是基于动态AOP)。
下面这段xml配置片断展示了Spring中的事务设定方式:
<beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>org.gjt.mm.mysql.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost/sample</value>
</property>
<property name="username">
<value>user</value>
</property>
<property name="password">
<value>mypass</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTr
ansactionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
 
<bean id="userDAOProxy"
class="org.springframework.transaction.interceptor.Tran
sactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="get*">
PROPAGATION_REQUIRED,readOnly
</prop>
</props>
</property>
</bean>
</beans>
配置中包含了dataSource,transactionManager 等资源定义。这些资源都为
一个名为userDAOProxy 的TransactionProxyFactoryBean 服务, 而
userDAOProxy 则对包含实际数据逻辑的userDAO进行了事务性封装。
可以看到,在userDAOProxy 的"transactionAttributes"属性中,我们定义了
针对userDAO 的事务策略,即将所有名称以insert 开始的方法(如
UserDAO.insertUser方法)纳入事务管理范围。如果此方法中抛出异常,则Spring
将当前事务回滚,如果方法正常结束,则提交事务

而对所有名称以get 开始的方法(如UserDAO.getUser 方法)则以只读的事务
处理机制进行处理。(设为只读型事务,可以使持久层尝试对数据操作进行优化,如对
于只读事务Hibernate将不执行flush操作,而某些数据库连接池和JDBC 驱动也

只读型操作进行了特别优化。)
结合上面这段申明带来的感性认知,看看Spring 的事务管理机制与EJB 中事务
管理有何不同,或者有何优势。
这里自然有许多方面可以比较,不过,笔者认为其中
最为关键的两点是:
1. Spring可以将任意Java Class 纳入事务管理
这里的UserDAO只是我们编写的一个普通Java Class,其中包含了一些
基本的数据应用逻辑。通过Spring,我们即可简单的实现事务的可配置
化。也就是说,我们可以随意为某个类的某个方法指定事务管理机制。
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
与之对比,如果使用EJB容器提供的事务管理功能,我们不得不按照EJB
规范编将UserDAO 进行改造,将其转换为一个标准的EJB。
2. Spring事务管理并不依赖特定的事务资源。
EJB 容器必须依赖于JTA 提供事务支持。而Spring 的事务管理则支持
JDBC、JTA 等多种事务资源。这为我们提供了更多的选择,从而也使得
我们的系统部署更加灵活。
对Spring事务管理机制进行简单分析之后,我们将结合持久层封装的具体事务应用机
制,对Spring中的事务管理进行更具实效的探讨。

=====================================

JdbcTemplate与事务
上例中的JdbcTemplate操作采用的是JDBC默认的AutoCommit模式,也就是说我们还
无法保证数据操作的原子性(要么全部生效,要么全部无效),如:

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");
jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = 'erica'");
由于采用了AutoCommit模式,第一个update操作完成之后被自动提交,数据库
中”erica”对应的记录已经被更新,如果第二个操作失败,我们无法使得整个事务回滚到最
初状态。对于这个例子也许无关紧要,但是对于一个金融帐务系统而言,这样的问题将导致
致命错误。
为了实现数据操作的原子性,我们需要在程序中引入事务逻辑,在JdbcTemplate中引入
事务机制,在Spring中有两种方式:
1. 代码控制的事务管理
2. 参数化配置的事务管理
下面就这两种方式进行介绍。
u 代码控制的事务管理
首先,进行以下配置,假设配置文件为(Application-Context.xml):
<beans>
<bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username">
<value>test</value>
</property>
<property name="password">
<value>changeit</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransac
tionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="transactionManager">
<ref local="transactionManager" />
</property>
</bean>
</beans>

配置中包含了三个节点:
Ø dataSource
这里我们采用了apache dhcp组件提供的DataSource实现,并为其配置了
JDBC驱动、数据库URL、用户名和密码等参数。
Ø transactionManager
针对JDBC DataSource类型的数据源,我们选用了
DataSourceTransactionManager
作为事务管理组件。
如果需要使用基于容器的数据源(JNDI),我们可以采用如下配置:

<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/sample</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTrans
actionManager"
/>
Ø userDAO
申明了一个UserDAO Bean,并为其指定了dataSource和
transactionManger资源。

UserDAO对应的代码如下:
public class UserDAO {
private DataSource dataSource;

private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
public DataSource executeTestSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertUser() {
TransactionTemplate tt =
new TransactionTemplate(getTransactionManager());
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update(
"insert into users (username) values ('xiaxin');");
jt.update(
"insert into users (id,username) values(2,
'erica');");
return null;
}
});
}
}

 
可以看到,在insertUser方法中,我们引入了一个新的模板类:
org.springframework.transaction.support.TransactionTemplate。
TransactionTemplate封装了事务管理的功能,包括异常时的事务回滚,以及操作成
后的事务提交。和JdbcTemplate一样,它使得我们无需在琐碎的try/catch/finally代码
徘徊。
在doInTransaction中进行的操作,如果抛出未捕获异常将被自动回滚,如果成功执行,

则将被自动提交。
这里我们故意制造了一些异常来观察数据库操作是否回滚(通过在第二条语句中更新自
增ID字段故意触发一个异常):
编写一个简单的TestCase来观察实际效果:
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
UserDAO userDAO = (UserDAO) factory.getBean("userDAO");
userDAO.insertUser();
相信大家多少觉得上面的代码有点凌乱,Callback类的编写似乎也有悖于日常的编程
习惯(虽然笔者觉得这一方法比较有趣,因为它巧妙的解决了笔者在早期自行开发数据访问
模板中曾经遇到的问题)。

u 参数化配置的事务管理
在上面的Application-Context.xml增加一个事务代理(UserDAOProxy)配置,同时,
由于事务由容器管理,UserDAO不再需要TransactionManager设定,将其移除:
<bean id="UserDAOProxy"
class="org.springframework.transaction.interceptor.Transac
tionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>

上面的配置中,UserDAOProxy节点配置了一个针对userDAO bean的事务代理(由
target属性指定)。
通过transactionAttributes属性,我们指定了事务的管理策略,即对所有以insert
开头的方法进行事务管理,如果被管理方法抛出异常,则自动回滚方法中的事务,如果成功
执行,则在方法完成之后进行事务提交。另
一方面,对于其他方法(通过通配符*表示),
则进行只读事务管理,以获得更好的性能。
与之对应,UserDAO.insertUser的代码修改如下:
public void insertUser(RegisterInfo regInfo) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update("insert into users (username) values ('xiaxin');");
jt.update("insert into users (id,username) values (2,'erica');");
}
测试代码修改如下:
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
//注意这里须通过代理Bean"userDAOProxy"获得引用,而不是直接getBean(“userDAO”)
//此外这里还存在一个有关强制转型的潜在问题,请参见Hibernate in Spring一节后
//关于强制转型的补充描述。
UserDAO userDAO = (UserDAO) factory.getBean("userDAOProxy");

userDAO.insertUser();
可以看到,insertUser变得非常简洁。数据逻辑清晰可见,对比前面代码控制的事务
管理,以及传统的JDBC操作,相信大家会有一些霍然开朗的感觉。
细心的读者会说,这只不过将代码转移到了配置文件,并没有减少太多的工作量。这点
区别也许并不重要,从应用维护的角度而言,配置化的事务管理显然更具优势。何况,实际
开发中,如果前期设计细致,方法的事务特性确定之后一般不会发生大的变动,之后频繁的
维护过程中,我们只需面对代码中的数据逻辑即可

分享到:
评论

相关推荐

    hibernate5--2.数据持久化及事务

    本章节我们将深入探讨Hibernate 5在数据持久化和事务管理方面的特性与用法。 **1. 数据持久化** 数据持久化是通过Hibernate的核心接口Session来实现的。Session提供了对数据库的 CRUD(创建、读取、更新、删除)...

    持久层设计

    - **事务管理**:支持原子性、一致性、隔离性和持久性(ACID属性)的事务处理。 - **性能优化**:通过合理的索引策略、缓存机制等手段提高数据访问效率。 - **安全性**:保护数据免受未经授权的访问和修改。 - **可...

    spring的持久层封装

    事务管理是持久层封装的另一关键方面,用于确保数据操作的一致性和完整性。Spring提供了`DataSourceTransactionManager`类来集成事务管理。 ```xml ``` 在上述配置中,`transactionManager`的`dataSource`...

    数据仓库---初学者使用

    - 支持决策制定:提供快速、准确的数据访问,辅助管理层做出明智的决策。 - 数据一致性:通过集中存储和管理,保证了数据的一致性和准确性。 - 数据安全性:集中化的管理可以更好地控制数据访问和权限。 7. 实施...

    用 Hibernate 和 Spring 开发持久层

    在现代企业级应用开发中,数据持久化是一项核心需求,而使用Hibernate和Spring构建事务持久层成为了许多开发者的选择。Hibernate,作为一款强大的对象关系映射(ORM)框架,简化了Java应用程序与数据库之间的交互,...

    04. SpringBoot整合持久层技术

    在测试持久层代码时,可以使用Spring Boot的`@DataJpaTest`或`@MyBatisTest`注解,它们会自动配置相关数据源和事务管理。性能优化方面,可以关注SQL执行效率、连接池配置、缓存策略等。 综上所述,Spring Boot整合...

    Hibernate数据持久层框架 v6.4.4.zip

    《深入理解Hibernate数据持久层框架 v6.4.4》 Hibernate是一款强大的Java持久层框架,它极大地简化了数据库操作,使得开发者可以更加专注于业务逻辑的实现,而非繁琐的SQL语句编写。Hibernate v6.4.4是该框架的一个...

    基于Hibernate和Spring的数据持久层设计与开发(软件工程课程设计).pdf

    在软件开发中,数据持久层是应用程序与数据库交互的核心部分,负责对象的持久化操作。随着Java技术的发展,ORM(Object-Relational Mapping,对象关系映射)框架如Hibernate和轻量级应用框架Spring的出现,极大地...

    MyBatis数据持久层框架 v3.5.15.zip

    MyBatis是一个流行的Java数据持久层框架,它简化了数据库操作并与对象关系映射(ORM)相结合,使得开发人员能够方便地将SQL语句与Java代码整合在一起。在这个"MyBatis数据持久层框架 v3.5.15.zip"压缩包中,包含的是...

    鲁棒的数据库持久层设计.pdf

    持久层设计是软件架构中负责处理数据持久化(即数据的存储与检索)的部分。它介于业务逻辑层和数据源之间,承担着数据模型与数据库交互的重任。一个好的持久层设计应具备高性能、低耦合、易于维护和扩展的特点。 ##...

    java基于jdbctemplate数据持久层操作封装

    Java中的JdbcTemplate是Spring框架提供的一种用于简化JDBC(Java Database Connectivity)操作的工具,它在数据持久层操作中扮演着重要角色。JdbcTemplate通过消除大量重复的JDBC样板代码,提高了代码的可读性和可...

    Rexdb是一款使用Java语言编写的,开放源代码的持久层框架 提供了查询、更新、批处理、调用、(JTA)事务、数据源管理等功能

    Rexdb是一款使用Java语言编写的,开放源代码的持久层框架。提供了查询、更新、批处理、调用、(JTA)事务、数据源管理等功能,可以取代...高性能的数据持久层(ORM)框架,查询性能是Hibernate的2.3倍,Mybatis的1.7倍。

    面向应用的持久层设计

    5. **事务管理**:事务是持久层的重要特性之一,正确地管理事务能够确保数据的一致性和完整性。因此,事务处理应当被集成到持久层的设计中。 #### 持久化与持久层的区别 虽然“持久化”和“持久层”这两个概念常常...

    用Hibernate和Spring开发事务持久层.rar_spring

    本教程将深入探讨如何结合这两个强大的工具来构建事务持久层,实现高效、灵活的数据访问。 首先,Spring是一个开源的应用框架,它提供了一整套服务,包括依赖注入(DI)、面向切面编程(AOP)、事务管理等,极大地...

    ibatis持久层简单操作

    在IT行业中,持久层框架是数据库操作的重要工具,它简化了数据访问的复杂性,使得开发者可以更加专注于业务逻辑的实现。Ibatis作为一款轻量级的Java持久层框架,深受许多开发者的喜爱。本篇文章将详细介绍Ibatis的...

    商品管理系统持久层五月份作业

    对于"商品管理系统持久层五月份作业",我们可以理解为这是针对商品管理系统的数据存储与检索层面的一个学习或实践项目,可能涉及到数据库设计、ORM框架的使用以及事务管理等内容。 首先,持久层是应用程序与数据库...

    鲁棒的数据库持久层设计

    3. **事务管理**:支持多种事务隔离级别,满足不同的业务需求。 4. **安全性**:保护数据免受非法访问和修改。 5. **可扩展性**:能够轻松地添加新功能或支持新的数据库类型。 6. **兼容性**:支持多种数据库系统,...

    设计健壮的关系数据库持久层

    持久层是指应用程序中的组件或模块,负责将业务逻辑中的数据转换成能够存储在持久化存储设备中的格式,并将持久化存储设备中的数据转换回业务逻辑中可用的格式。在文档中,Scott W. Ambler提到了多种类型的持久层: ...

    Hibernate数据持久层框架 v5.3.36 正式版.zip

    Hibernate是一款开源的Java语言下的数据持久层框架,它极大地简化了数据库操作,使得开发者能够更加专注于业务逻辑,而不是繁琐的SQL语句。该框架的核心功能是对象关系映射(ORM),将Java对象与数据库表之间的关系...

    关于J2EE持久层的文章

    J2EE持久层框架通常提供了一种将应用业务逻辑与底层数据存储分离的方法,这样可以使开发者更加专注于业务逻辑的实现而无需过多关注数据访问的细节。目前较为流行的两种J2EE持久层框架是Enterprise JavaBeans (EJB) ...

Global site tag (gtag.js) - Google Analytics