Spring的事务管理

事务有一系列操作组成,这些操作是一个整体,密不可分,也就是说这些操作要么都执行成功,要么都不会执行。

事务的CAID属性

  • 原子性:一个事务是一个不可分割的最小工作单元。
  • 一致性:数据库总是从一个状态转换到另一个一致性的状态。
  • 隔离性:通常来说,一个事务所做的修改在最终提交之前,对其他事务是不可见的。
  • 持久性:一旦事务提交,其所做的修改就会永久保存到数据库中。

事务的4种隔离级别

每一种隔离级别都规定了在一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。较低的隔离级别通常意味着较高的并发性,系统的开销更低。

  • READ UNCOMMITTED(未提交读):事务中所做的修改,即使没有提交,对其他事务也都是可见的。
  • READ COMMITTED(提交读):事务中所做的修改,在没有提交之前,对其他事务是不可见的。一个事务开始时,只能“看到”已经提交的事务所做的修改。
  • REPEATABLE READ(可重复读):该级别保证了在同一个事务中,多次读取同样记录的结果是一致的。但是理论上,可重复读仍无法解决“幻读”问题,幻读就是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围插入了新的记录,当之前的事务再次读取该范围内的记录时,会产生“幻行”问题。InnoDB通过多版本并发控制(MVCC)解决幻读问题。
  • SERIALIZABLE(可串行化):是最高的隔离级别,通过强制事务串行化执行,避免了前面所说的幻读问题。

事务的隔离级别越高,数据库事务并发执行性能越差,能处理的操作越少。因此在实际项目开发中为了考虑并发性能一般使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。

Spring事务类型

数据库事务类型有本地事务和分布式事务:

  • 本地事务:即普通的事务,CAID限定于一台服务器上。
  • 分布式事务:涉及两个或多个数据库源的事务,即跨越多台同类或异类数据库的事务(由每台数据库的本地事务组成的),分布式事务旨在保证这些本地事务的所有操作的ACID,使事务可以跨越多台数据库。

按是否通过编程实现事务有声明式事务和编程式事务两种:

  • 声明式事务: 通过注解或XML配置文件指定事务信息;
  • 编程式事务:通过编写代码实现事务。

Spring事务管理

Spring核心功能之一就是提供事务管理功能,不管使用Spring JDBC框架还是集成第三方框架使用该API进行事务编程,都提供了一致的编程式事务管理API,并且是无侵入式的事务支持。

Spring有一个事务管理器抽象,对于不同的ORM框架,通过实现策略接口PlatformTransactionManager,从而支持各种ORM的事务管理。

public interface PlatformTransactionManager {
    /**
     * 根据var1定义的事务类型返回一个已经激活的事务或创建一个新的事务,
     * 返回的是TransactionStatus对象代表了当前事务的状态,其中该方法抛出
     * TransactionException(未检查异常)表示事务由于某种原因失败。
     */
    TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;

    // 提交事务
    void commit(TransactionStatus var1) throws TransactionException;

    // 撤销事务
    void rollback(TransactionStatus var1) throws TransactionException;
}

事务定义接口TransactionDefinition:

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;

    // 事务的传播行为
    int getPropagationBehavior();

    // 事务隔离级别
    int getIsolationLevel();

    // 事务超时时间
    int getTimeout();

    boolean isReadOnly();

    String getName();
}

事务状态接口TransactionStatus :

public interface TransactionStatus extends SavepointManager, Flushable {
    // 是否是新事务
    boolean isNewTransaction();

    // 当前事务是否有保存点
    boolean hasSavepoint();

    // 设置事务应该回滚
    void setRollbackOnly();

    // 当前事务是否应该回滚
    boolean isRollbackOnly();

    void flush();

    // 当前事务否已完成
    boolean isCompleted();
}

Spring内置事务管理器实现

  • DataSourceTransactionManager:位于org.springframework.jdbc.datasource包中,数据源事务管理器,提供对单个javax.sql.DataSource事务管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理;
  • JdoTransactionManager:位于org.springframework.orm.jdo包中,提供对单个javax.jdo.PersistenceManagerFactory事务管理,用于集成JDO框架时的事务管理;
  • JpaTransactionManager:位于org.springframework.orm.jpa包中,提供对单个javax.persistence.EntityManagerFactory事务支持,用于集成JPA实现框架时的事务管理;
  • HibernateTransactionManager:位于org.springframework.orm.hibernate3包中,提供对单个org.hibernate.SessionFactory事务支持,用于集成Hibernate框架时的事务管理;该事务管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate 3.2+版本;
  • JtaTransactionManager:位于org.springframework.transaction.jta包中,提供对分布式事务管理的支持,并将事务管理委托给Java EE应用服务器事务管理器;
  • OC4JjtaTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对OC4J10.1.3+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持;
  • WebSphereUowTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对WebSphere 6.0+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持;
  • WebLogicJtaTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对WebLogic 8.1+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持。

声明对本地事务的支持

Spring配置文件如下:

<context:component-scan base-package="com.luo.jdbc"></context:component-scan>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://192.168.1.xxx:3306/zzz"></property>
    <property name="username" value="xxx"></property>
    <property name="password" value="xxx"></property>
</bean>

<!--事务管理器-->
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--JDBC模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource">
        <ref bean="dataSource" />
    </property>
</bean>

然后自定义事务:

@Service
public class MyTransaction1 {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private MyTransaction2 transaction2;

    @Transactional(propagation = Propagation.REQUIRED)
    public void test1() {
        jdbcTemplate.execute("update user set name = '1' where id = 3");
        try {
            transaction2.test2();
        } catch (Exception e) {
            System.out.println("transaction2 throws exception");
        }
    }
}

@Service
public class MyTransaction2 {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(propagation = Propagation.REQUIRED)
    public void test2() {
        jdbcTemplate.execute("update user set name = '2' where id = 3");
        // 如果这里没有抛出异常,则事务就会正常执行完毕
        throw new RuntimeException();
    }
}

public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("springConfig.xml");

    MyTransaction1 transaction1 = ctx.getBean(MyTransaction1.class);
    transaction1.test1();

    System.out.println("hi, spring transaction");
}
输出结果

Spring事务的传播行为

事务传播是Spring事务中一个重要概念,当调用一个基于Spring的Service接口方法时,它将运行于Spring管理的事务环境中,Service接口方法可能会在内部调用其它的Service接口方法以共同完成一个完整的业务操作(比如上面代码中MyTransaction1.test1调用MyTransaction2.test2),因此就会产生服务接口方法嵌套调用的情况, Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:

  • PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
  • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

参考资料:

  1. 【第九章】 Spring的事务 之 9.2 事务管理器 ——跟我学spring3
  2. Spring事务传播机制
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,733评论 6 342
  • 很多人喜欢这篇文章,特此同步过来 由浅入深谈论spring事务 前言 这篇其实也要归纳到《常识》系列中,但这重点又...
    码农戏码阅读 4,704评论 2 59
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,438评论 1 133
  • 1.事务概念 1. 什么是事务 2. 事务特性 原子性 一致性 隔离性 持久性 3. 不考虑隔离性产生读问题 脏读...
    暖熊熊阅读 337评论 0 0