六Spring事务--1事务的概念及使用

六Spring事务--1事务的概念及使用

6.1 相关概念

spring事务涉及的知识点:

image-20230310132052529

(1)ACID

img

Spring 支持编程式和声明式事务管理,在不需要应用程序服务器的情况下实现

(2)局部事务、全局事务

局部事务是特定于一个单一的事务资源,如一个 JDBC 连接,而全局事务可以跨多个事务资源事务,如在一个分布式系统中的事务。

(4)编程式事务和声明式事务

Spring支撑两种类型事务管理:

编程式事务管理:

这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护

声明式事务管理:

你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。

事务管理,作为一种横切关注点,声明式事务,可以使用AOP方法进行模块化。Spring支持使用springAOP框架的声明式事务管理。

(5)spring事务管理的接口方法

Spring事务的关键接口,是org.springframework.transaction.PlatformTransactionManager

如下:

img

涉及到的类:

PlatformTransactionManager:

该接口,提供对事务的管理,如新建事务、提交、回滚

TransactionDdfinition:

该接口,作为spring中事务的核心接口,主要定义了查询事务的相关信息属性,如查询事务的执行类型、查询隔离级别、查询事务名称、查询事务需要在什么时间点执行完成、查询事务是否是只读的

TransactionStatus

提供方法,控制事务的执行以及查询当前事务执行状态,如是否有保存点、事务是否完成、事务是否是新的、事务是否被标记为rollback-only、设置事务未rollback-only。

(a)PlatformTransactionManager:

该接口,提供对事务的对应的执行,如新建事务、提交、回滚

img

TransactionStatus getTransaction(TransactionDefinition definition)

根据指定的传播行为,该方法返回当前活动事务或创建一个新的事务。

void commit(TransactionStatus status)

该方法提交给定的事务和关于它的状态。

void rollback(TransactionStatus status)

该方法执行一个给定事务的回滚。

(b)TransactionDefinition:

该接口,作为spring中事务的核心接口,主要定义了查询事务的相关信息属性,如查询事务的执行类型(传播类型)、查询隔离级别、查询事务名称、查询事务需要在什么时间点执行完成、查询事务是否是只读的

img

事务隔离级别

img

事务传播类型:

img

(c)TransactionStatus

提供方法,控制事务的执行以及查询当前事务执行状态,如是否有保存点、事务是否完成、事务是否是新的、事务是否被标记为rollback-only、设置事务未rollback-only。

img

6.1.1 spring的编程式事务:

教程中使用了spring jdbc的示例,因此,仅仅把关键地方列出来。

步骤:

(一)在需要执行事务的方法所在class内,创建事务对象transactionManager。

img

如图,使用set属性方法,在XML中配置,则依赖注入对象

img

该处,transactionManager的类,使用spring的jdbc下面的管理数据源的事务管理类,其中的属性DataSource,此处,ref引用XML中的bean.。(事务使用相应工具提供的TransactionManager)

(二)在事务类中,需要事务执行的方法中(该示例为create方法,写入数据库,因此需要事务执行),创建TransactionDefinition对象;然后并使用transactionManager创建出TransactionStatus对象

这个例子中,我们使用默认的 transaction 属性简单的创建了 DefaultTransactionDefinition 的一个实例。

当 TransactionDefinition 创建后,你可以通过调用 getTransaction() 方法来开始你的事务,该方法会返回 TransactionStatus 的一个实例。

img

(三)TransactionStatus 对象帮助追踪当前的事务状态,并且最终,如果一切运行顺利,你可以使用 TransactionManagercommit() 方法来提交这个事务,否则的话,你可以使用 rollback() 方法来回滚整个操作。

img

追踪事务状态,运行顺利,则提交事务,否则,回滚事务。

(springboot中@transactional的使用、以及springboot的事务传播)

6.1.2 spring声明式事务管理

在配置的协助下管理事务。使得将事务管理从事务代码中隔离出来。Bean的配置会制定事务型方法。

示例:

Beans.xml

img

事务执行操作内,的try 、catch方法块

img

步骤解释:

(一)我们使用标签,它创建一个事务处理的建议(增强)advice

img

对于事务对应的transactionManager,则bean依赖注入,配置如下:(该处选择数据库带的事务管理)

img

(二)同时,我们定义一个匹配所有方法的切入点,我们希望这些方法是事务型。并且会引用事务型的建议advice(aop:advisor,部分,配置了两部分,一个是advice-ref,制定事务建议;另一个参数,是pointcut-ref,就是需要事务执行的方法切入点)

img

(三)如果在事务型配置中包含了一个方法的名称,那么创建的建议在调用方法之前就会在事务中开始进行(就是Main调用该方法前,就会在事务中提前进行,检查事务执行状态)

img

(四)目标方法会在 try / catch 块中执行。

(五)方法正常结束,AOP通知,会成功的提交事务,否则回滚操作。

举例如下:(事务与try/catch的配合)

注意:transactional标注的事务,其中不应该try和catch异常,这样会使得事务无法获取异常。

业务:新增用户时,需要对用户详细信息进行保存USER表,还要对用户的角色进行保存USER_ROLE表(一对多)。

此时就需要对新增用户进行事务控制,避免二者不能同时更新成功。

项目采用SpringBoot+Mybatis

SpringBoot不用单独的去配置事务管理,使用@Transactional即可,但是在service层方法上加上@Transactional后发现事务并没有生效。代码如下:

image-20220416063600990

此时新增用户成功,新增角色时抛出异常,但是用户成功被添加了。

后来发现时由于@Transactional在抛出异常时需要进行回滚,但是try catch已经把异常捕获了,@Transactional没办法获取异常,也不知道在哪发生的异常,所以失效了。对代码进行修改,如下:

Controller:

image-20220416063617217

Service:

image-20220416063632404

异常捕获在Controller去做,这样在Service层中 @Transactional在发生异常时可以正常进行回滚操作

事务部分,需要再看书,详细补充。

6.1.3 spring事务的配置使用

6.1.4 Transactional使用注意项

后续补充

6.1.5 Spring中@Transactional调用自身

public class InjectBeanSelfProcessor implements BeanPostProcessor, ApplicationContextAware{

ApplicationContext context;

private static Log log = LogFactory.getLog(com/netease/lottery/base/common/BeanSelf/InjectBeanSelfProcessor);

public InjectBeanSelfProcessor(){
}

public void setApplicationContext(ApplicationContext context) throws BeansException{
this.context = context;
}

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException{

  //如果Bean实现了BeanSelfAware标识接口,就将代理对象注入
if(bean instanceof BeanSelfAware){//1
BeanSelfAware myBean = (BeanSelfAware)bean;
Class cls = bean.getClass();

  //如果bean不是AopProxy代理类
if(!AopUtils.isAopProxy(bean)){ //2
Class c = bean.getClass();
  //获取被@service注解的类上的信息(如service注解上的所有属性信息)
Service serviceAnnotation = (Service)c.getAnnotation(org/springframework/stereotype/Service);
  //表明当前bean被@service注释
if(serviceAnnotation != null)
try{ //3
  //重新获取bean
bean = context.getBean(beanName);
if(AopUtils.isAopProxy(bean));
}//3 
  catch(BeanCurrentlyInCreationException beancurrentlyincreationexception) { 
}
catch(Exception ex){
log.fatal((new StringBuilder()).append("No Proxy Bean for service ").append(bean.getClass()).append(" ").append(ex.getMessage()).toString(), ex);
}
  
} //2 
  //如果bean是AopProxy代理类----这里处理aware的setter方法
myBean.setSelf(bean);
return myBean;

} //1
  //如果bean没有实现BeanSelfAware接口
  else{
return bean;
}
}

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException{
return bean;
}
posted @ 2023-03-10 17:17  LeasonXue  阅读(253)  评论(0)    收藏  举报