码迷,mamicode.com
首页 > 编程语言 > 详细

spring事务的传播特性

时间:2019-04-01 20:05:54      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:host   var   默认   数据库   接口   .repo   nstat   color   超出   

  spring事务分为本地事务和分布式事务,其中本地事务其实就是数据库事务,Spring事务有三个核心类:TransactionDefinition、PlatformTransactionManager、TransactionStatus。

  首先来看事务定义类TransactionDefinition,其中定义了事务的7种传播特性和5种隔离级别:

  PROPAGATION_REQUIRED  需要事务,如果当前没有事务则新建一个事务

  PROPAGATION_SUPPORTS 支持事务,如果当前有事务则加入到这个事务,没有则以非事务的方式运行,默认值

  PROPAGATION_MANDATORY 需要事务,如果当前没有事务则抛出异常

  PROPAGATION_REQUIRES_NEW 开启一个新事物,如果当前有事务则挂起

  PROPAGATION_NOT_SUPPORTED 不支持事务,总是以非事务的方式运行

  PROPAGATION_NEVER 不支持事务,如果当前有事务则抛出异常

  PROPAGATION_NESTED 嵌套事务

  ISOLATION_DEFAULT 默认隔离级别,取决于本地数据库设置的隔离级别

  ISOLATION_READ_UNCOMMITTED 读未提交

  ISOLATION_READ_COMMITTED 读已提交

  ISOLATION_REPEATABLE_READ 可重复读

  ISOLATION_SERIALIZABLE 串行化

  接着看PlatformTransactionManager接口,它定义了spring事务的基本操作,随着我们使用的orm框架的不同对应有不同的实现类

  TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException; 获取事务

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

  void rollback(TransactionStatus status) throws TransactionException;回滚事务

  随着我们使用的orm框架的不同对应有不同的实现类,例如spring jdbc的DataSourceTransactionManager,jpa的JpaTransactionManager等

  最后一个TransactionStatus,定义了事务的4中状态

  boolean isNewTransaction(); 是否为新事物

  boolean hasSavepoint(); 是否有保存点

  boolean isRollbackOnly(); 是否只回滚

  boolean isCompleted() 是否完成

  在日常开发中,我们常用到的传播特性就是PROPAGATION_SUPPORTS、PROPAGATION_REQUIRED和PROPAGATION_REQUIRES_NEW,隔离级别一般为默认值,而readOnly则是查询语句为ture,其他为false。下面来测一下三种传播行为下的事务是如何执行的,方便期间,使用springboot构建项目,加入jdbc的starter依赖

  新建两个测试表,语句如下:

CREATE TABLE role
(
    id integer NOT NULL,
    rolename character varying(4) COLLATE pg_catalog."default",
    CONSTRAINT role_pkey PRIMARY KEY (id)
)
CREATE TABLE txuser
(
    id integer NOT NULL,
    name character varying(5) COLLATE pg_catalog."default",
    CONSTRAINT txuser_pkey PRIMARY KEY (id)
)

  使用postgresql数据库,加入配置

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/test01
spring.datasource.username=postgres
spring.datasource.password=123456

  dao层

package com.example.tx.dao;

import com.example.tx.model.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class RoleReposity {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int addRole(Role role){

        return  jdbcTemplate.update("insert into role(id,rolename) values (?,?)",role.getId(),role.getRolename());
    }
}
package com.example.tx.dao;

import com.example.tx.model.Txuser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class TxuserReposity {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int addUser(Txuser user){
        return jdbcTemplate.update("insert into txuser(id,name) values(?,?)",user.getId(),user.getName());
    }

}

  service层

package com.example.tx.service;

import com.example.tx.dao.RoleReposity;
import com.example.tx.model.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class RoleService {

@Autowired
private RoleReposity roleReposity;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addRole(Role role1,Role role2){
roleReposity.addRole(role1);
roleReposity.addRole(role2);
}
}
package com.example.tx.service;

import com.example.tx.dao.TxuserReposity;
import com.example.tx.model.Role;
import com.example.tx.model.Txuser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {


@Autowired
private RoleService roleService;

@Autowired
private TxuserReposity txuserReposity;

@Transactional(propagation = Propagation.REQUIRED)
public void addUser (Txuser user1, Txuser user2,Role role1,Role role2){
txuserReposity.addUser(user1);
roleService.addRole(role1,role2);
txuserReposity.addUser(user2);
}


}

  测试代码

package com.example.tx;

import com.example.tx.model.Role;
import com.example.tx.model.Txuser;
import com.example.tx.service.UserService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TxApplicationTests {

@Autowired
private UserService userService;


@Test
public void contextLoads() {

Txuser user1 = new Txuser();
user1.setId(1);
user1.setName("mike");

Txuser user2 = new Txuser();
user2.setId(2);
user2.setName("zhangsan");

Role role1 = new Role();
role1.setId(1);
role1.setRolename("aaa");


Role role2 = new Role();
role2.setId(2);
role2.setRolename("bbb");

userService.addUser(user1,user2, role1,role2);
}


}

  在测试代码中将user2的name超过限制(txuser中设置name长度为5),其它实体正常,测试如下:

  1、当RoleService方法上事务传播特性为SUPPORTS,测试结果为全部回滚。

  2、当RoleService方法上事务传播特性为REQUIRED,测试结果为全部回滚。

  3、当RoleService方法上事务传播特性为REQUIRES_NEW,测试结果为两条role记录添加成功。

  修改user2的name为"asd",role2中name为"useradmin"(超出role中限制)

  1、当RoleService方法上事务传播特性为SUPPORTS,测试结果为全部回滚。

  2、当RoleService方法上事务传播特性为REQUIRED,测试结果为全部回滚。

  3、当RoleService方法上事务传播特性为REQUIRES_NEW,测试结果为全部回滚。

  从以上结果可以看出当内层事务的传播特性为SUPPORTS或者REQUIRED时,只要发生异常就全部回滚,这是因为两个事务获取的是同一个数据库连接;当内层事务的传播特性为REQUIRES_NEW时,当外层事务发生异常时,内层事务不受影响,当内层事务发生异常,则全部回滚,此时两个事务获取的是不同的数据库连接对象,内层事务出现异常是会传播给外层,而外层事务异常时,内层事务则不受影响。

  此外我们在使用Spring事务是一定要注意同类间的方法调用,如果是直接调用,则被调用方法的事务是不起作用的,这是因为此时为对象内的调用,并不会使用spring为我们创建的代理对象,此时需要我们在调用方法内获取代理对象,使用代理对象去调用同类中的其它事务方法,如下:

public void testPropagation(Txuser user, Role role){
        System.out.println(1231231);
        UserService userService = (UserService)AopContext.currentProxy();
        userService.addUser(user1,user2, role1,role2);
    }

 

 

 

 

 

 

  

 

spring事务的传播特性

标签:host   var   默认   数据库   接口   .repo   nstat   color   超出   

原文地址:https://www.cnblogs.com/hhhshct/p/10638489.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!