【第九章】 Spring的事务 之 9.3 编程式事务

9.3.1  编程式事务概述

        所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。

       Spring框架提供一致的事务抽象,因此对于JDBC还是JTA事务都是采用相同的API进行编程。

Connection conn = null;  
UserTransaction tx = null;  
try {  
    tx = getUserTransaction();                       //1.获取事务  
    tx.begin();                                    //2.开启JTA事务  
    conn = getDataSource().getConnection();           //3.获取JDBC  
    //4.声明SQL  
    String sql = "select * from INFORMATION_SCHEMA.SYSTEM_TABLES";  
    PreparedStatement pstmt = conn.prepareStatement(sql);//5.预编译SQL  
    ResultSet rs = pstmt.executeQuery();               //6.执行SQL  
    process(rs);                                   //7.处理结果集  
    closeResultSet(rs);                             //8.释放结果集  
    tx.commit();                                  //7.提交事务  
} catch (Exception e) {  
    tx.rollback();                                 //8.回滚事务  
    throw e;  
} finally {  
   conn.close();                                //关闭连接  
} 

 

9.3.2   Spring对编程式事务的支持

Spring中的事务分为物理事务和逻辑事务;

  • 物理事务:就是底层数据库提供的事务支持,如JDBC或JTA提供的事务;
  • 逻辑事务:是Spring管理的事务,不同于物理事务,逻辑事务提供更丰富的控制,而且如果想得到Spring事务管理的好处,必须使用逻辑事务,因此在Spring中如果没特别强调一般就是逻辑事务

    逻辑事务即支持非常低级别的控制,也有高级别解决方案:

  • 低级别解决方案:

  工具类:使用工具类获取连接(会话)和释放连接(会话),如使用org.springframework.jdbc.datasource包中的 DataSourceUtils 类来获取和释放具有逻辑事务功能的连接。当然对集成第三方ORM框架也提供了类似的工具类,如对Hibernate提供了SessionFactoryUtils工具类,JPA的EntityManagerFactoryUtils等,其他工具类都是使用类似***Utils命名;

//获取具有Spring事务(逻辑事务)管理功能的连接  
DataSourceUtils. getConnection(DataSource dataSource)  
//释放具有Spring事务(逻辑事务)管理功能的连接  
DataSourceUtils. releaseConnection(Connection con, DataSource dataSource)

         TransactionAwareDataSourceProxy使用该数据源代理类包装需要Spring事务管理支持的数据源,该包装类必须位于最外层,主要用于遗留项目中可能直接使用数据源获取连接和释放连接支持或希望在Spring中进行混合使用各种持久化框架时使用,其内部实际使用 DataSourceUtils 工具类获取和释放真正连接;

  
  
      
  

        通过如上方式包装数据源后,可以在项目中使用物理事务编码的方式来获得逻辑事务的支持,即支持直接从DataSource获取连接和释放连接,且这些连接自动支持Spring逻辑事务;

  • 高级别解决方案:

         模板类:使用Spring提供的模板类,如JdbcTemplate、HibernateTemplate和JpaTemplate模板类等,而这些模板类内部其实是使用了低级别解决方案中的工具类来管理连接或会话;

     Spring提供两种编程式事务支持:直接使用PlatformTransactionManager实现和使用TransactionTemplate模板类,用于支持逻辑事务管理。

如果采用编程式事务推荐使用TransactionTemplate模板类和高级别解决方案。

9.3.3  使用PlatformTransactionManager

首先让我们看下如何使用PlatformTransactionManager实现来进行事务管理:

1、数据源定义,此处使用第7章的配置文件,即“chapter7/ applicationContext-resources.xml”文件。

2、事务管理器定义(chapter9/applicationContext-jdbc.xml):

    
      
  

3、 准备测试环境:

3.1、首先准备测试时使用的SQL

package cn.javass.spring.chapter9;  
//省略import  
public class TransactionTest {  
    //id自增主键从0开始  
    private static final String CREATE_TABLE_SQL = "create table test" +  
    "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " +  
    "name varchar(100))";  
    private static final String DROP_TABLE_SQL = "drop table test";  
    private static final String INSERT_SQL = "insert into test(name) values(?)";  
    private static final String COUNT_SQL = "select count(*) from test";  
    ……  
}  

3.2、初始化Spring容器

package cn.javass.spring.chapter9;  
//省略import  
public class TransactionTest {  
    private static ApplicationContext ctx;  
    private static PlatformTransactionManager txManager;  
    private static DataSource dataSource;  
    private static JdbcTemplate jdbcTemplate;  
    ……  
    @BeforeClass  
    public static void setUpClass() {  
        String[] configLocations = new String[] {  
                "classpath:chapter7/applicationContext-resources.xml",  
                "classpath:chapter9/applicationContext-jdbc.xml"};  
        ctx = new ClassPathXmlApplicationContext(configLocations);  
        txManager = ctx.getBean(PlatformTransactionManager.class);  
        dataSource = ctx.getBean(DataSource.class);  
        jdbcTemplate = new JdbcTemplate(dataSource);  
    }   
    ……  
}  

3.3、使用高级别方案JdbcTemplate来进行事务管理器测试:

@Test  
public void testPlatformTransactionManager() {  
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();  
    def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  
    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  
    TransactionStatus status = txManager.getTransaction(def);  
    jdbcTemplate.execute(CREATE_TABLE_SQL);  
    try {  
        jdbcTemplate.update(INSERT_SQL, "test");  
        txManager.commit(status);  
    } catch (RuntimeException e) {  
        txManager.rollback(status);  
    }  
    jdbcTemplate.execute(DROP_TABLE_SQL);  
} 
  • DefaultTransactionDefinition事务定义,定义如隔离级别、传播行为等,即在本示例中隔离级别为ISOLATION_READ_COMMITTED(提交读),传播行为为PROPAGATION_REQUIRED(必须有事务支持,即如果当前没有事务,就新建一个事务,如果已经存在一个事务中,就加入到这个事务中)。
  • TransactionStatus事务状态类,通过PlatformTransactionManager的getTransaction方法根据事务定义获取;获取事务状态后,Spring根据传播行为来决定如何开启事务;
  • JdbcTemplate:通过JdbcTemplate对象执行相应的SQL操作,且自动享受到事务支持,注意事务是线程绑定的,因此事务管理器可以运行在多线程环境;
  • txManager.commit(status):提交status对象绑定的事务;
  • txManager.rollback(status):当遇到异常时回滚status对象绑定的事务。

3.4、使用低级别解决方案来进行事务管理器测试:

@Test  
public void testPlatformTransactionManagerForLowLevel1() {  
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  
  TransactionStatus status = txManager.getTransaction(def);  
  Connection conn = DataSourceUtils.getConnection(dataSource);  
  try {  
      conn.prepareStatement(CREATE_TABLE_SQL).execute();  
      PreparedStatement pstmt = conn.prepareStatement(INSERT_SQL);  
      pstmt.setString(1, "test");  
      pstmt.execute();  
      conn.prepareStatement(DROP_TABLE_SQL).execute();  
      txManager.commit(status);  
  } catch (Exception e) {  
      status.setRollbackOnly();  
      txManager.rollback(status);  
  } finally {  
      DataSourceUtils.releaseConnection(conn, dataSource);  
}  
}  

        低级别方案中使用DataSourceUtils获取和释放连接,使用txManager开管理事务,而且面向JDBC编程,比起模板类方式来繁琐和复杂的多,因此不推荐使用该方式。在此就不介绍数据源代理类使用了,需要请参考platformTransactionManagerForLowLevelTest2测试方法。

       到此事务管理是不是还很繁琐?必须手工提交或回滚事务,有没有更好的解决方案呢?Spring提供了TransactionTemplate模板类来简化事务管理。

9.3.4  使用TransactionTemplate

         TransactionTemplate模板类用于简化事务管理,事务管理由模板类定义,而具体操作需要通过TransactionCallback回调接口或TransactionCallbackWithoutResult回调接口指定,通过调用模板类的参数类型为TransactionCallback或TransactionCallbackWithoutResult的execute方法来自动享受事务管理。

TransactionTemplate模板类使用的回调接口:

  • TransactionCallback:通过实现该接口的“T doInTransaction(TransactionStatus status) ”方法来定义需要事务管理的操作代码;
  • TransactionCallbackWithoutResult:继承TransactionCallback接口,提供“void doInTransactionWithoutResult(TransactionStatus status)”便利接口用于方便那些不需要返回值的事务操作代码。

1、接下来演示一下TransactionTemplate模板类如何使用:

@Test  
public void testTransactionTemplate() {//位于TransactionTest类中  
  jdbcTemplate.execute(CREATE_TABLE_SQL);  
  TransactionTemplate transactionTemplate = new TransactionTemplate(txManager);  
  transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  
  transactionTemplate.execute(new TransactionCallbackWithoutResult() {  
      @Override  
      protected void doInTransactionWithoutResult(TransactionStatus status) {  
         jdbcTemplate.update(INSERT_SQL, "test");  
  }});  
  jdbcTemplate.execute(DROP_TABLE_SQL);  
}  
  • TransactionTemplate :通过new TransactionTemplate(txManager)创建事务模板类,其中构造器参数为PlatformTransactionManager实现,并通过其相应方法设置事务定义,如事务隔离级别、传播行为等,此处未指定传播行为,其默认为PROPAGATION_REQUIRED;
  • TransactionCallbackWithoutResult:此处使用不带返回的回调实现,其doInTransactionWithoutResult方法实现中定义了需要事务管理的操作;
  • transactionTemplate.execute():通过该方法执行需要事务管理的回调。

这样是不是简单多了,没有事务管理代码,而是由模板类来完成事务管理。

注:对于抛出Exception类型的异常且需要回滚时,需要捕获异常并通过调用status对象的setRollbackOnly()方法告知事务管理器当前事务需要回滚,如下所示:

try {  
    //业务操作  
} catch (Exception e) { //可使用具体业务异常代替  
    status.setRollbackOnly();  
}  

2、前边已经演示了JDBC事务管理,接下来演示一下JTA分布式事务管理:

@Test  
public void testJtaTransactionTemplate() {  
    String[] configLocations = new String[] {  
      "classpath:chapter9/applicationContext-jta-derby.xml"};  
    ctx = new ClassPathXmlApplicationContext(configLocations);  
    final PlatformTransactionManager jtaTXManager = ctx.getBean(PlatformTransactionManager.class);  
    final DataSource derbyDataSource1 = ctx.getBean("dataSource1", DataSource.class);  
    final DataSource derbyDataSource2 = ctx.getBean("dataSource2", DataSource.class);  
    final JdbcTemplate jdbcTemplate1 = new JdbcTemplate(derbyDataSource1);  
    final JdbcTemplate jdbcTemplate2 = new JdbcTemplate(derbyDataSource2);  
    TransactionTemplate transactionTemplate = new TransactionTemplate(jtaTXManager);   
    transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  
    jdbcTemplate1.update(CREATE_TABLE_SQL);  
    int originalCount = jdbcTemplate1.queryForInt(COUNT_SQL);  
    try {  
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {  
            @Override  
            protected void doInTransactionWithoutResult(TransactionStatus status) {  
                jdbcTemplate1.update(INSERT_SQL, "test");  
               //因为数据库2没有创建数据库表因此会回滚事务  
              jdbcTemplate2.update(INSERT_SQL, "test");  
          }});  
    } catch (RuntimeException e) {  
        int count = jdbcTemplate1.queryForInt(COUNT_SQL);  
        Assert.assertEquals(originalCount, count);  
    }  
    jdbcTemplate1.update(DROP_TABLE_SQL);  
}  
  • 配置文件:使用此前定义的chapter9/applicationContext-jta-derby.xml;
  • jtaTXManager: JTA事务管理器;
  • derbyDataSource1和derbyDataSource2:derby数据源1和derby数据源2;
  • jdbcTemplate1和jdbcTemplate2:分别使用derbyDataSource1和derbyDataSource2构造的JDBC模板类;
  • transactionTemplate:使用jtaTXManager事务管理器的事务管理模板类,其隔离级别为提交读,传播行为默认为PROPAGATION_REQUIRED(必须有事务支持,即如果当前没有事务,就新建一个事务,如果已经存在一个事务中,就加入到这个事务中);
  • jdbcTemplate1.update(CREATE_TABLE_SQL):此处只有derbyDataSource1所代表的数据库创建了“test”表,而derbyDataSource2所代表的数据库没有此表;
  • TransactionCallbackWithoutResult:在此接口实现中定义了需要事务支持的操作:

         jdbcTemplate1.update(INSERT_SQL, "test"):表示向数据库1中的test表中插入数据;

         jdbcTemplate2.update(INSERT_SQL, "test"):表示向数据库2中的test表中插入数据,但数据库2没有此表将抛出异常,且JTA分布式事务将回滚;

  • Assert.assertEquals(originalCount, count):用来验证事务是否回滚,验证结果返回为true,说明分布式事务回滚了。

        到此我们已经会使用PlatformTransactionManager和TransactionTemplate进行简单事务处理了,那如何应用到实际项目中去呢?接下来让我们看下如何在实际项目中应用Spring管理事务。

        接下来看一下如何将Spring管理事务应用到实际项目中,为简化演示,此处只定义最简单的模型对象和不完整的Dao层接口和Service层接口:

1、 首先定义项目中的模型对象,本示例使用用户模型和用户地址模型:模型对象一般放在项目中的model包里。

package cn.javass.spring.chapter9.model;  
public class UserModel {  
    private int id;  
    private String name;  
    private AddressModel address;  
    //省略getter和setter  
} 
package cn.javass.spring.chapter9.model;  
public class AddressModel {  
    private int id;  
    private String province;  
    private String city;  
    private String street;  
    private int userId;  
    //省略getter和setter  
}  

2.1、定义Dao层接口:

package cn.javass.spring.chapter9.service;  
import cn.javass.spring.chapter9.model.UserModel;  
public interface IUserService {  
    public void save(UserModel user);  
    public int countAll();  
}  
package cn.javass.spring.chapter9.service;  
import cn.javass.spring.chapter9.model.AddressModel;  
public interface IAddressService {  
    public void save(AddressModel address);  
    public int countAll();  
}  

2.2、定义Dao层实现:

package cn.javass.spring.chapter9.dao.jdbc;  
//省略import,注意model要引用chapter包里的  
public class UserJdbcDaoImpl extends NamedParameterJdbcDaoSupport implements IUserDao {  
    private final String INSERT_SQL = "insert into user(name) values(:name)";  
    private final String COUNT_ALL_SQL = "select count(*) from user";  
    @Override  
    public void save(UserModel user) {  
        KeyHolder generatedKeyHolder = new GeneratedKeyHolder();  
        SqlParameterSource paramSource = new BeanPropertySqlParameterSource(user);  
        getNamedParameterJdbcTemplate().update(INSERT_SQL, paramSource, generatedKeyHolder);  
        user.setId(generatedKeyHolder.getKey().intValue());  
    }  
    @Override  
    public int countAll() {  
       return getJdbcTemplate().queryForInt(COUNT_ALL_SQL);  
    }  

3.1、定义Service层接口,一般使用“I×××Service”命名:

package cn.javass.spring.chapter9.service;  
import cn.javass.spring.chapter9.model.UserModel;  
public interface IUserService {  
    public void save(UserModel user);  
    public int countAll();  
}  
  
  
package cn.javass.spring.chapter9.service;  
import cn.javass.spring.chapter9.model.AddressModel;  
public interface IAddressService {  
    public void save(AddressModel address);  
    public int countAll();  
} 

3.2、定义Service层实现,一般使用“×××ServiceImpl”或“×××Service”命名:

package cn.javass.spring.chapter9.service.impl;  
//省略import,注意model要引用chapter包里的  
public class AddressServiceImpl implements IAddressService {  
    private IAddressDao addressDao;  
    private PlatformTransactionManager txManager;  
    public void setAddressDao(IAddressDao addressDao) {  
        this.addressDao = addressDao;  
    }  
    public void setTxManager(PlatformTransactionManager txManager) {  
        this.txManager = txManager;  
    }  
    @Override  
    public void save(final AddressModel address) {  
        TransactionTemplate transactionTemplate = TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);  
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {  
           @Override  
           protected void doInTransactionWithoutResult(TransactionStatus status) {  
                addressDao.save(address);  
           }  
        });  
    }  
    @Override  
    public int countAll() {  
        return addressDao.countAll();  
    }  
}  
package cn.javass.spring.chapter9.service.impl;  
//省略import,注意model要引用chapter包里的  
public class UserServiceImpl implements IUserService {  
    private IUserDao userDao;  
    private IAddressService addressService;  
    private PlatformTransactionManager txManager;  
    public void setUserDao(IUserDao userDao) {  
        this.userDao = userDao;  
    }  
    public void setTxManager(PlatformTransactionManager txManager) {  
        this.txManager = txManager;  
    }  
    public void setAddressService(IAddressService addressService) {  
        this.addressService = addressService;  
    }  
    @Override  
    public void save(final UserModel user) {  
        TransactionTemplate transactionTemplate =  
            TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);  
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {  
        @Override  
           protected void doInTransactionWithoutResult(TransactionStatus status) {  
                userDao.save(user);  
                user.getAddress().setUserId(user.getId());  
                addressService.save(user.getAddress());  
           }  
        });  
    }  
    @Override  
    public int countAll() {  
        return userDao.countAll();  
    }  
}  

Service实现中需要Spring事务管理的部分应该使用TransactionTemplate模板类来包装执行。

4、定义TransactionTemplateUtils,用于简化获取TransactionTemplate模板类,工具类一般放在util包中:

package cn.javass.spring.chapter9.util;  
//省略import  
public class TransactionTemplateUtils {  
    public static TransactionTemplate getTransactionTemplate(  
            PlatformTransactionManager txManager,  
            int propagationBehavior,  
            int isolationLevel) {  
        
        TransactionTemplate transactionTemplate = new TransactionTemplate(txManager);  
        transactionTemplate.setPropagationBehavior(propagationBehavior);  
        transactionTemplate.setIsolationLevel(isolationLevel);  
        return transactionTemplate;  
    }  
     
    public static TransactionTemplate getDefaultTransactionTemplate(PlatformTransactionManager txManager) {  
        return getTransactionTemplate(  
                txManager,  
                TransactionDefinition.PROPAGATION_REQUIRED,  
                TransactionDefinition.ISOLATION_READ_COMMITTED);  
    }  
}  

getDefaultTransactionTemplate用于获取传播行为为PROPAGATION_REQUIRED,隔离级别为ISOLATION_READ_COMMITTED的模板类。

5、数据源配置定义,此处使用第7章的配置文件,即“chapter7/ applicationContext-resources.xml”文件。

6、Dao层配置定义(chapter9/dao/applicationContext-jdbc.xml):

    
      
  
  
      
  
  
 

7、Service层配置定义(chapter9/service/applicationContext-service.xml):

  
      
      
      
  
  
      
      
  

8、准备测试需要的表创建语句,在TransactionTest测试类中添加如下静态变量:

private static final String CREATE_USER_TABLE_SQL =  
    "create table user" +  
    "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " +  
    "name varchar(100))";  
private static final String DROP_USER_TABLE_SQL = "drop table user";  
   
private static final String CREATE_ADDRESS_TABLE_SQL =  
    "create table address" +  
    "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " +  
    "province varchar(100), city varchar(100), street varchar(100), user_id int)";  
private static final String DROP_ADDRESS_TABLE_SQL = "drop table address";

9、 测试一下吧:

@Test  
    public void testServiceTransaction() {  
        String[] configLocations = new String[] {  
        "classpath:chapter7/applicationContext-resources.xml",  
        "classpath:chapter9/dao/applicationContext-jdbc.xml",  
        "classpath:chapter9/service/applicationContext-service.xml"};  
        ApplicationContext ctx2 = new ClassPathXmlApplicationContext(configLocations);  
         
        DataSource dataSource2 = ctx2.getBean(DataSource.class);  
        JdbcTemplate jdbcTemplate2 = new JdbcTemplate(dataSource2);  
        jdbcTemplate2.update(CREATE_USER_TABLE_SQL);  
        jdbcTemplate2.update(CREATE_ADDRESS_TABLE_SQL);  
         
        IUserService userService = ctx2.getBean("userService", IUserService.class);  
        IAddressService addressService = ctx2.getBean("addressService", IAddressService.class);  
        UserModel user = createDefaultUserModel();  
        userService.save(user);  
        Assert.assertEquals(1, userService.countAll());  
        Assert.assertEquals(1, addressService.countAll());  
        jdbcTemplate2.update(DROP_USER_TABLE_SQL);  
        jdbcTemplate2.update(DROP_ADDRESS_TABLE_SQL);  
}  
private UserModel createDefaultUserModel() {  
    UserModel user = new UserModel();  
    user.setName("test");  
    AddressModel address = new AddressModel();  
    address.setProvince("beijing");  
    address.setCity("beijing");  
    address.setStreet("haidian");  
    user.setAddress(address);  
    return user;  
} 

     从Spring容器中获取Service层对象,调用Service层对象持久化对象,大家有没有注意到Spring事务全部在Service层定义,为什么会在Service层定义,而不是Dao层定义呢?这是因为在服务层可能牵扯到业务逻辑,而每个业务逻辑可能调用多个Dao层方法,为保证这些操作的原子性,必须在Service层定义事务。

    还有大家有没有注意到如果Service层的事务管理相当令人头疼,而且是侵入式的,有没有办法消除这些冗长的事务管理代码呢?这就需要Spring声明式事务支持,下一节将介绍无侵入式的声明式事务。

可能大家对事务定义中的各种属性有点困惑,如传播行为到底干什么用的?接下来将详细讲解一下事务属性。

9.3.5  事务属性

事务属性通过TransactionDefinition接口实现定义,主要有事务隔离级别、事务传播行为、事务超时时间、事务是否只读

       Spring提供TransactionDefinition接口默认实现DefaultTransactionDefinition,可以通过该实现类指定这些事务属性。

  • 事务隔离级别:用来解决并发事务时出现的问题,其使用TransactionDefinition中的静态变量来指定:

         ISOLATION_DEFAULT:默认隔离级别,即使用底层数据库默认的隔离级别;

         ISOLATION_READ_UNCOMMITTED:未提交读;

         ISOLATION_READ_COMMITTED:提交读,一般情况下我们使用这个;

         ISOLATION_REPEATABLE_READ:可重复读;

         ISOLATION_SERIALIZABLE:序列化。

可以使用DefaultTransactionDefinition类的setIsolationLevel(TransactionDefinition. ISOLATION_READ_COMMITTED)来指定隔离级别,其中此处表示隔离级别为提交读,也可以使用或setIsolationLevelName(“ISOLATION_READ_COMMITTED”)方式指定,其中参数就是隔离级别静态变量的名字,但不推荐这种方式。

  • 事务传播行为:Spring管理的事务是逻辑事务,而且物理事务和逻辑事务最大差别就在于事务传播行为,事务传播行为用于指定在多个事务方法间调用时,事务是如何在这些方法间传播的,Spring共支持7种传播行为:

Required:必须有逻辑事务,否则新建一个事务,使用PROPAGATION_REQUIRED指定,表示如果当前存在一个逻辑事务,则加入该逻辑事务,否则将新建一个逻辑事务。

RequiresNew:创建新的逻辑事务,使用PROPAGATION_REQUIRES_NEW指定,表示每次都创建新的逻辑事务(物理事务也是不同的)

Supports:支持当前事务,使用PROPAGATION_SUPPORTS指定,指如果当前存在逻辑事务,就加入到该逻辑事务,如果当前没有逻辑事务,就以非事务方式执行。

NotSupported:不支持事务,如果当前存在事务则暂停该事务,使用PROPAGATION_NOT_SUPPORTED指定,即以非事务方式执行。

Mandatory:必须有事务,否则抛出异常,使用PROPAGATION_MANDATORY指定,使用当前事务执行,如果当前没有事务,则抛出异常(IllegalTransactionStateException)。

Never:不支持事务,如果当前存在是事务则抛出异常,使用PROPAGATION_NEVER指定,即以非事务方式执行,如果当前存在事务,则抛出异常(IllegalTransactionStateException)

Nested:嵌套事务支持,使用PROPAGATION_NESTED指定,如果当前存在事务,则在嵌套事务内执行,如果当前不存在事务,则创建一个新的事务,嵌套事务使用数据库中的保存点来实现,即嵌套事务回滚不影响外部事务,但外部事务回滚将导致嵌套事务回滚

  • 事务超时:设置事务的超时时间,单位为秒,默认为-1表示使用底层事务的超时时间;

          使用如setTimeout(100)来设置超时时间,如果事务超时将抛出org.springframework.transaction.TransactionTimedOutException异常并将当前事务标记为应该回滚,即超时后事务被自动回滚;

         可以使用具体事务管理器实现的defaultTimeout属性设置默认的事务超时时间,如DataSourceTransactionManager. setDefaultTimeout(10)。

  • 事务只读:将事务标识为只读,只读事务不修改任何数据;

你可能感兴趣的:(spring)