【Spring】Spring使用XML配置声明式事务

林炳文Evankaka原创作品。转载请注明出处

一、事务介绍

事务简介:

事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性

事务就是一系列的动作,它们被当作一个单独的工作单元。这些动作要么全部完成,要么全部不起作用。

事务的四个关键属性(ACID)

① 原子性(atomicity):事务室一个原子操作,有一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用② 一致性(consistency):一旦所有事务动作完成,事务就被提交。数据和资源就处于一种满足业务规则的一致性状态中③ 隔离性(isolation):可能有许多事务会同时处理相同的数据,因此每个事物都应该与其他事务隔离开来,防止数据损坏④ 持久性(durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响。通常情况下,事务的结果被写到持久化存储器中

数据隔离级别

隔离级别脏读不可重复读幻象读第一类丢失更新第二类丢失更新

READ UNCOMMITED允许允许允许不允许允许

READ COMMITED不允许允许允许不允许允许

REPEATABLE READ不允许不允许允许不允许不允许

SERIALIZABLE不允许不允许不允许不允许不允许

SqlServer2008R2的默认隔离级别是“READ COMMITED”,MySQL的默认隔离级别是“REPEATABLE READ”。

Spring中的事务管理

作为企业级应用程序框架,Spring在不同的事务管理API之上定义了一个抽象层。而应用程序开发人员不必了解底层的事务管理API,就可以使用Spring的事务管理机制。

Spring既支持编程式事务管理,也支持声明式的事务管理

编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,在编程式事务中,必须在每个业务操作中包含额外的事务管理代码

声明式事务管理:大多数情况下比编程式事务管理更好用。它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点,可以通过AOP方法模块化。Spring通过Spring AOP框架支持声明式事务管理。

Spring事务的传播属性:

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

事务的传播行为可以由传播属性指定。Spring定义了7种传播行为:

PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务,加入到这个事务中。这是最常见的选择。

PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

并发事务所导致的问题

在同一个应用程序或者不同应用程序中的多个事务在同一个数据集上并发执行时,可能会出现许多意外的问题。

并发事务所导致的问题可以分为以下三类:

① 脏读:脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。

② 不可重复读:不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间更新了数据

③ 幻读:幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录

二、实例开发

Spring声明式事务让我们从复杂的事务处理中得到解脱,使得我们再也不必去处理获得连接、关闭连接、事务提交和回滚等这些操作,再也无需我们在与事务相关的方法中处理大量的try…catch…finally代码。 我们在使用Spring声明式事务时,有一个非常重要的概念就是事务属性。事务属性通常由事务的传播行为、事务的隔离级别、事务的超时值、事务只读标志组成。我们在进行事务划分时,需要进行事务定义,也就是配置事务的属性。 Spring在TransactionDefinition接口中定义这些属性,以供PlatfromTransactionManager使用,PlatfromTransactionManager是spring事务管理的核心接口。

下面用一个例子来说明Spring事务管理的好处

新建立一个java工程,导入相关的包,,事个工程最终目录如下:

这里应用到了mysql,需要建立数据库test及其下的数据表book_table

create database test;use test;CREATE TABLE book_table (bookname varchar(100) NOT NULL, bookid int(11) NOT NULL PRIMARY KEY) ;

1、数据表对应的model类:

package com.mucfc.model;public class Book {private String bookName;private int bookId;public Book(String bookName, int bookId) {super();this.bookName = bookName;this.bookId = bookId;}public Book(){}@Overridepublic String toString() {return "Book [bookName=" + bookName + ", bookId=" + bookId + "]";}public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public int getBookId() {return bookId;}public void setBookId(int bookId) {this.bookId = bookId;}}2、接着是DAO层:package com.mucfc.dao;import com.mucfc.model.Book;/** * 图书馆DAO抽象类 * @author linbingwen * @2015年5月8日10:36:29 */public interface LibraryDao {/** * 取得书 * @param name * @return book */public Book getBook(String name);/** * 增加书* @param book */public void addBook(Book book);/** * 删除书* @param book */public void deleteBook(String name);}实现类:package com.mucfc.dao;import java.sql.ResultSet;import java.sql.SQLException;import java.util.*;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import com.mucfc.model.Book;/** * 图书馆DAO实现类 * @author linbingwen * @2015年5月8日10:36:29 */public class LibraryDaoImpl implements LibraryDao{private JdbcTemplate jdbcTemplate;public JdbcTemplate getJdbcTemplate() {return jdbcTemplate;}public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic Book getBook(String name) {String sql="SELECT * FROM book_table WHERE bookname=?";Book mBook = (Book)jdbcTemplate.queryForObject(sql,new Object[]{name},new RowMapper<Object>(){@Overridepublic Object mapRow(ResultSet arg0, int arg1) throws SQLException {Book book=new Book();book.setBookId(arg0.getInt("bookid"));book.setBookName(arg0.getString("bookname"));return book;}});return mBook;}@Overridepublic void addBook(Book book) { String sql="INSERT INTO book_table VALUES(?,?)";jdbcTemplate.update(sql, book.getBookName(),book.getBookId());// jdbcTemplate.update(sql, book.getBookName(),book.getBookId());}@Overridepublic void deleteBook(String name) {String sql="DELETE FROM book_table WHERE bookname=?"; jdbcTemplate.update(sql,name);}}3、事务配置<?xml version="1.0" encoding="UTF-8"?><beans xmlns=""xmlns:xsi="" xmlns:context=""xmlns:aop="" xmlns:p=""xsi:schemaLocation=""><!– 配置数据源 –><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/test" /><property name="username" value="root" /><property name="password" value="christmas258@" /></bean><!–配置一个JdbcTemplate实例,并将这个“共享的”,“安全的”实例注入到不同的DAO类中去 –><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean><!– 声明事务管理器 –><bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!– 需要实施事务增强的目标业务Bean –><bean id="libraryTarget" class="com.mucfc.dao.LibraryDaoImpl"p:jdbcTemplate-ref="jdbcTemplate" /><!– 使用事务代理工厂类为目标业务Bean提供事务增强 –><bean id="libraryFactory"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"p:transactionManager-ref="txManager" p:target-ref="libraryTarget"><!– 事务属性配置 –><property name="transactionAttributes"><props><!– 以get开头的方法采用只读型事务控制类型 –><prop key="get*">PROPAGATION_REQUIRED,readOnly</prop><!– 所有方法均进行事务控制,如果当前没有事务,则新建一个事务 –><prop key="addBook">PROPAGATION_REQUIRED</prop></props></property></bean></beans>4、测试使用:package com.mucfc.service;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.mucfc.dao.LibraryDao;import com.mucfc.model.Book;public class Test {public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml"); Book book1=new Book("西游记",1); Book book2=new Book("红楼梦",2); Book book3=new Book("金瓶梅",3); Book book4=new Book("三国演义",4); Book book5=new Book("水浒传",5); LibraryDao libraryDaoImpl=(LibraryDao)ctx.getBean("libraryFactory");libraryDaoImpl.addBook(book1);System.out.println(libraryDaoImpl.getBook("西游记"));}}输出结果:

这里只输出了一条

数据库中的结果:

5、上面是正常时的情况,现在我们想让它出现异常,并自动回滚。简单。

总结失败的原因能够让人越来越谨慎。

【Spring】Spring使用XML配置声明式事务

相关文章:

你感兴趣的文章:

标签云: