Spring3.1学习笔记之——事务

来源:互联网 发布:郭天祥51单片机百度云 编辑:程序博客网 时间:2024/05/01 13:05

一、事务介绍

事务指作为单个逻辑工作单元执行的一系列操作,事务处理的目的就是保证这一系列操作产生的影响或者结果要么都成功,要么都失败,这样才能保证系统的稳定性、正确性。

一个事务满足以下的四个基本的特性,简称ACID:

原子性(atomicity)——事务的所有操作在数据库中要么全部正确成功,要么全部不成功。

一致性(consistency)——事务在完成时,必须保证受操作影响的所有的数据都保持一致状态。

隔离性(isolation)——事务是并发提交的,事务之间必须是隔离的,也就是一个事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。

持久性(durability)——事务完成之后,它对于系统的影响,不管是正确的影响还是错误的影响都必须是永久性的。

并发事务带来的影响:

丢失数据修改——当两个以上事务通过读取一条数据并进行修改时,会发生丢失更新问题,因为每个事务都不知道其它事务的存在,最后更新的事务将重写由其它事务所做的更新,这将导致数据丢失。

读“脏”数据——是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被除撤消,而此时T1把已修改过的数据又恢复原值,T2读到的数据与数据库的数据不一致,则T2读到的数据就为“脏”数据,即不正确的数据。

不可重复读——指事务T1读取数据后,事务T2执行更新操作,使T1无法读取前一次结果。

产生幽灵数据——按一定条件从数据库中读取了某些记录后,T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录消失;或者2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。

事务分类:全局事务和本地事务

全局事务——全局事务可以使用多个事务源,应用服务器通过JTA来管理全局事务,为了使用JTA,必须使用JNDI定义数据源。全局事务的局限性表现在复杂的JTA和限制了应用程序代码的重用,因为一个JTA只对特定的应用服务器环境有效。

使用全局事务通常的方法是通过EJB CMT(Container Managed Transaction),EJB CMT是一种声明式事务管理,它虽然要使用JNDI,但是它不需要事务相关的JNDI 查找,EJBCMT也减少了事务控制编码的编写量,EJB CMT最大的负面就是它必须和JTA、特定的应用服务器绑定。EJBEJB由于太笨重,以至于在有了spring之后,它不是一个比较好的选择。

本地事务——本事务是一种特定事务,比如和JDBC相关的事务,本事务虽然比较容易使用,但是他最大的局限就是不能使用多个事务源。

二、Spring 事务管理:

Spring事务管理很好的解决了全局事务和本地事务的局限性,能让应用程序开发者在任何环境下都使用一致的编程模型来实现事务管理。只要写一次代码,就可以在不同的环境中受益于不同的事务管理策略。

Spring提供了声明式事务管理和编程式事务管理,推荐使用声明式事务管理,它能降低代码的编写量和代码的耦合度。

对于编程式事务管理,开发人员必须和Spring的事务抽象打交道,Spring的事务抽象可以运行在任何底层的事务基础结构之上。

对于声明式事务管理,开发人员写很少或者不需要写任何和事务关的代码,更不需要依赖于任何Spring事务的API,或者其他事务的API。

Spring的事务抽象的关键是一个事务策略的概念,一个事务策略通过接口org.springframework.transaction.PlatformTransactionManager定义,PlatformTransactionManager不被绑定到具体一个查找策略(如JNDI),它能像其他bean一样在Spring的IOC容器里定义,就这一点就使得Spring的事务成为一个很有价值的抽象,不管是否有在使用JTA。使用Spring编写的事务代码比直接使用JTA编写的事务代码更容易测试。

getTransaction(..)返回一个TransactionStatus对象,依赖于TransactionDefinition参数。一个TransactionStatus对象可以代表一个新事务;或者如果一个匹配的事务已经在当前的调用堆栈存在了,那么TransactionStatus对象就代表这个已经存在的事务。TransactionStatus对象和一个执行线程相关的。

TransactionDefinition接口说明:

        Isolation:事务隔离程度

        Propagation:为存在的事务执行指定行为,如代码在存在的事务里继续执行,或者存在事务暂停,创建一个新的事务。

        Timeout:事务在超时或者通过底层事务框架回滚之前运行了多长时间。

        Read-only status:只读状态,如果代码只需读取数据而不需要修改数据,那就可以使用只读事务,在一些情况,只读事务是非常有用的优化,如Hibernate。

不管使用声明式事务管理还是编程式事务管理,定义一个正确的PlatformTransactionManager是绝对必要的,可以通过依赖注入(dependency injection)来定义这个实现。针对不同的需求,PlatformTransactionManager有不同的实现,如JDBC, JTA, Hibernate等等。

JDBC的PlatformTransactionManager定义如下:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

JTA的PlatformTransactionManager定义如下:

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

JTA通过是用JNDI来获取容器里的数据源,JtaTransactionManager不用指定具体的数据源,因为它使用容器的全局事务管理,能自动获取到事务源。JTA也和其他数据访问技术(JDBC, Hibernate,JPA等等)无关。

Hibernate的PlatformTransactionManager定义如下:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

同步数据:高级同步和低级同步

高级同步——首选的方法是使用基于持久化集成API的Spring高级template(如JdbcTemplate,HibernateTemplate)和原生的ORM框架的API。

低级同步——使用DataSourceUtils (for JDBC), EntityManagerFactoryUtils (for JPA),SessionFactoryUtils (for Hibernate),PersistenceManagerFactoryUtils (for JDO)等等类

原创粉丝点击