`
ielts0909
  • 浏览: 11612 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论
阅读更多
Java Transactions

说到事务我们很容易能想到ACID这四个特性,以及一系列在违反ACID原则时会产生的各种情况和问题。可能在传统的引入式教学中,我们都会拿数据库的例子来做这部分讲解,所以给人的一种感觉就是只有对数据库的一系列操作会引发脏读、幻读等问题,其实这类事务在分类中属于本地事务模型,而Java中的事务类型可以分为三种:本地事务模型(Local Transaction Model),编程式事务模型(Programmatic Transaction Model)和声明式事务模型(Declarative Transaction Model)。

本地事务模型(Local Transaction Model),事实上不是编程框架本身来管理事务,事务由本地资源管理器(Local resource manager)来管理。资源管理器是用于通信的数据源的提供者。对于数据库,资源管理器是通过数据库驱动和数据库管理系统(DBMS)来实现的。这一部分,我们可以想到JDBC操作数据库时,对事务的管理。
编程式事务模型(Programmatic Transaction Model),利用java事务API(Java Transaction API)及其底层事务服务实现技术支持。这里编程也用到了我们常用的commit()、rollback()等方法来管理事务。这一部分,我们可以很容易的联想到Hibernate编程中,对session的事务管理。
声明式事务模型(Declarative Transaction Model),在spring编程中,我们可以通过配置applicationContext.xml文件来管理事务,配置事务的传播特性。

下面先关心一下ACID:Atomicity、Consistency、Isolation、Durability,以及违反ACID可能出现的问题:
脏读:指一个事务读取到了另一个事务未提交的数据。
不可重复读:在一个事务内,多次读取,前后读取的值不同(一个事务读取到另一个事务已提交的数据)。
幻读:前后两次读的结果不一样。
对开发人员可用的事务设置是事务的隔离级别。事务隔离(transaction isolation)是指交织在一起发生的事务之间相互影响的程度。它决定了在其他事务访问和更新同一份数据时,一个事务对更新所允许的可见程度。关系数据库、Spring都允许设定事务的隔离级别,这样的设置是数据库和应用服务器实现相互依赖的。应用服务器可能支持多种隔离级别,对应的数据库必须支持这些同样的隔离级别,这些设置才可能真正生效。
一般数据库的隔离级别如下:
Serializable:可避免脏读、幻读、不可重复读。一般应用于统计时。
Repeatable Read:可避免脏读、不可重复读。MySQL默认。
Read Committed:可避免脏读。一般用于查询。
Read Uncommitted
其中Oracle支持read committed和Serializable。

本地事务模型
在这一部分我们很可以在JDBC编程时使用,我们只要手动开启事务就能手动管理事务了。
conn=DButils.getConnection();
conn.setAutoCommit(false);
conn.commit();
conn.rollback();


编程式事务模型
编程式事务模型与本地事务模型最大的不同是,开发的时候,管理的是事务而不是连接。编程式事务通常的应用环境是客户端发起事务(client-initiated transaction)的情形。即客户端为一个业务做多次远程方法调用的时候。另一个场景是使用本地的JTA事务(localized JTA transaction)和长时间运行的JTA事务。

声明式事务模型
这一部分将以Spring为例。在Spring的事务声明中,一般都通过applicationContext.xml进行配置。通常可有六种事务属性的设置:required、supports、mandatory、requires_new、Not_supported和never。Spring还有一个附加的Nested属性。该属性告知Spring进行事务嵌套,并采用required属性。一个简单的事务配置如下:
<!-- 配置事务管理器 -->
	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory">
			<ref bean="sessionFactory"/>
		</property>
	</bean>
	
	<!-- 配置事务的传播特性 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
		<tx:method name="add" propagation="REQUIRED"/>
		<tx:method name="del" propagation="REQUIRED"/>
		<tx:method name="modify" propagation="REQUIRED"/>
		<tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- 哪些类的哪些方法参与事务 -->
	<aop:config>
		<aop:pointcut id="allManagerMethod" expression="execution(* com.a2.usermgr.manager.*.*(..))"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod"/>
	</aop:config>


事务的设计模式(Transaction Design Pattern)
事务设计模式的划分基于组件责任模型,基于有关模型某个应用组件类型拥有开启和管理事务的责任。一般可分为:客户端拥有事务的设计模式(client owner transaction design pattern),领域服务拥有事务的设计模式(domain service owner transaction design pattern)和服务器端代理拥有事务的设计模式(server delegate owner transaction design pattern)。


上周做了个实验,JDBC插MySQL数据库,默认采用InnDB(transaction safe, disk based storage engine with row locking),每秒能插入个几百条(数据是从磁盘读的,还做了相关处理),同样的情况下,若采用MylSAM(very fast, disk based storage engine without support for transaction),每秒能插入一万条以上的数据。所以……没有所以了。

以上只是一种思路,具体的实现网上应该都有成篇的代码。个人愚见,谢谢观看。

本文原创,部分引用InfoQ中相关文章,转载请指明出处,谢谢。
2
3
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics