SpringBoot 注解事务声明式事务

简介:

springboot 对新人来说可能上手比springmvc要快,但是对于各位从springmvc转战到springboot的话,有些地方还需要适应下,尤其是xml配置。我个人是比较喜欢注解xml是因为看着方便,查找方便,清晰明了。但是xml完全可以使用注解代替,今天就扒一扒springboot中事务使用注解的玩法。


  springboot的事务也主要分为两大类,一是xml声明式事务,二是注解事务,注解事务也可以实现类似声明式事务的方法,关于注解声明式事务,目前网上搜索不到合适的资料,所以在这里,我将自己查找和总结的几个方法写到这里,大家共同探讨


springboot 之 xml事务

      可以使用 @ImportResource("classpath:transaction.xml") 引入该xml的配置,xml的配置如下


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        
    <bean id="txManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" ></property>
    </bean>
    <tx:advice id="cftxAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="query*" propagation="SUPPORTS" read-only="true" ></tx:method>
            <tx:method name="get*" propagation="SUPPORTS" read-only="true" ></tx:method>
            <tx:method name="select*" propagation="SUPPORTS" read-only="true" ></tx:method>
            <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" ></tx:method>
        </tx:attributes>
    </tx:advice>
     <aop:config>
        <aop:pointcut id="allManagerMethod" expression="execution (* com.exmaple.fm..service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod" order="0" />
    </aop:config>

</beans>

springboot 启动类如下:


package com.example.fm;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
 
@ImportResource("classpath:transaction.xml")
@SpringBootApplication
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
 
}


启动后即可开启事务,不过项目里导入了xml配置,如果不想导入xml配置,可以使用注解的方式。


springboot 之 注解事务

   注解事务讲解之前,需要先了解下spring创建代理的几个类,在spring内部,是通过BeanPostProcessor来完成自动创建代理工作的。BeanPostProcessor接口的实现只是在ApplicationContext初始化的时候才会自动加载,而普通的BeanFactory只能通过编程的方式调用之。根据  匹配规则的不同大致分为三种类别:


    a、匹配Bean的名称自动创建匹配到的Bean的代理,实现类BeanNameAutoProxyCreator


<bean id="testInterceptor" class="com.example.service.config.testInerceptor”></bean>

<bean id="profileAutoProxyCreator" class="org.springframework.aop.framework.
autoproxy.BeanNameAutoProxyProxyCreator">
<bean>
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<value> testInterceptor </value>
</property>
</bean>


b、根据Bean中的AspectJ注解自动创建代理,实现类AnnotationAwareAspectJAutoProxyCreator

<aop:aspectj-autoproxy proxy-target-class="true"/>

<bean id="annotationAwareAspectJAutoProxyCreatorTest" class="com.example.service.AnnotationAwareAspectJAutoProxyCreatorTest"/>
<aop:config>
    <aop:aspect ref="annotationAwareAspectJAutoProxyCreatorTest">
        <aop:around method="process" pointcut="execution (* com.example.service.fm..*.*(..))"/>
    </aop:aspect>
</aop:config>

c、根据Advisor的匹配机制自动创建代理,会对容器中所有的Advisor进行扫描,自动将这些切面应用到匹配的Bean中,实现类DefaultAdvisorAutoProxyCreator


  接下来开讲注解开启事务的方法:


       1、Transactional注解事务


   需要在进行事物管理的方法上添加注解@Transactional,或者偷懒的话直接在类上面添加该注解,使得所有的方法都进行事物的管理,但是依然需要在需要事务管理的类上都添加,工作量比较大,这里只是简单说下,具体的可以google或者bing


       2、注解声明式事务


  Component或Configuration中bean的区别,有时间我会专门写一篇来讲解下


  a.方式1,这里使用Component或Configuration事务都可以生效


package com.exmple.service.fm9.config;
 
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
 
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
 
/**
 * Created by guozp on 2017/8/28.
 */
@Aspect
//@Component 事务依然生效
@Configuration
public class TxAdviceInterceptor {
 
    private static final int TX_METHOD_TIMEOUT = 5;
    private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.alibaba.fm9..service.*.*(..))";
 
    @Autowired
    private PlatformTransactionManager transactionManager;
 
    @Bean
    public TransactionInterceptor txAdvice() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
         /*只读事务,不做更新操作*/
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
        /*当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务*/
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        requiredTx.setRollbackRules(
            Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        requiredTx.setTimeout(TX_METHOD_TIMEOUT);
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        txMap.put("add*", requiredTx);
        txMap.put("save*", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("delete*", requiredTx);
        txMap.put("get*", readOnlyTx);
        txMap.put("query*", readOnlyTx);
        source.setNameMap( txMap );
        TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
        return txAdvice;
    }
 
    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
        //return new DefaultPointcutAdvisor(pointcut, txAdvice);
    }
}


 b.方式1,这里使用Component或Configuration事务都可以生效


package com.exmple.service.fm9.config;
 
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
 
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
 
/**
 * Created by guozp on 2017/8/29.
 */
//@Component 事务依然生效
@Configuration
public class TxAnoConfig {
    /*事务拦截类型*/
    @Bean("txSource")
    public TransactionAttributeSource transactionAttributeSource(){
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
         /*只读事务,不做更新操作*/
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
        /*当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务*/
        //RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        //requiredTx.setRollbackRules(
        //    Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        //requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED,
            Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        requiredTx.setTimeout(5);
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        txMap.put("add*", requiredTx);
        txMap.put("save*", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("delete*", requiredTx);
        txMap.put("get*", readOnlyTx);
        txMap.put("query*", readOnlyTx);
        source.setNameMap( txMap );
 
        return source;
    }
 
    /**切面拦截规则 参数会自动从容器中注入*/
    @Bean
    public AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor){
        AspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor();
        pointcutAdvisor.setAdvice(txInterceptor);
        pointcutAdvisor.setExpression("execution (* com.alibaba.fm9..service.*.*(..))");
        return pointcutAdvisor;
    }
 
    /*事务拦截器*/
    @Bean("txInterceptor")
    TransactionInterceptor getTransactionInterceptor(PlatformTransactionManager tx){
        return new TransactionInterceptor(tx , transactionAttributeSource()) ;
    }
}

 c.方式1,这里使用Component或Configuration事务都可以生效


package com.exmple.service.fm9.config;
 
import java.util.Properties;
 
 
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionInterceptor;
 
/**
 * Created by guozp on 2017/8/28.
 *
 */
//@Component
@Configuration
public class TxConfigBeanName {
 
    @Autowired
    private DataSourceTransactionManager transactionManager;
 
    // 创建事务通知
 
    @Bean(name = "txAdvice")
    public TransactionInterceptor getAdvisor() throws Exception {
 
        Properties properties = new Properties();
        properties.setProperty("get*", "PROPAGATION_REQUIRED,-Exception,readOnly");
        properties.setProperty("add*", "PROPAGATION_REQUIRED,-Exception,readOnly");
        properties.setProperty("save*", "PROPAGATION_REQUIRED,-Exception,readOnly");
        properties.setProperty("update*", "PROPAGATION_REQUIRED,-Exception,readOnly");
        properties.setProperty("delete*", "PROPAGATION_REQUIRED,-Exception,readOnly");
 
        TransactionInterceptor tsi = new TransactionInterceptor(transactionManager,properties);
        return tsi;
 
    }
 
    @Bean
    public BeanNameAutoProxyCreator txProxy() {
        BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
        creator.setInterceptorNames("txAdvice");
        creator.setBeanNames("*Service", "*ServiceImpl");
        creator.setProxyTargetClass(true);
        return creator;
    }
}

d.方式1,这里使用Component或Configuration并不是所有事务都可以生效,例如Configuration的时候如果打开注释部分的而且不把代码都移动到 defaultPointcutAdvisor(),事物会失效,具体原因暂时不明,如果各位有明白的,可以指点我下。


ackage com.alibaba.fm9.config;
 
import java.util.Properties;
 
import javax.sql.DataSource;
 
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.TransactionInterceptor;
 
/**
 * Created by guozp on 2017/8/28.
 *                       ???????
 */
@Configuration //事务失效,都移动到一个方法不失效
//@Component // 事务可行,不用都移动到一个方法
public class TxOtherConfigDefaultBean {
 
    public static final String transactionExecution = "execution (* com.alibaba.fm9..service.*.*(..))";
 
    @Autowired
    private PlatformTransactionManager transactionManager;
 
    //@Bean
    //@ConditionalOnMissingBean
    //public PlatformTransactionManager transactionManager() {
    //    return new DataSourceTransactionManager(dataSource);
    //}
 
 
    @Bean
    public TransactionInterceptor transactionInterceptor() {
        Properties attributes = new Properties();
        attributes.setProperty("get*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("add*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("update*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("delete*", "PROPAGATION_REQUIRED,-Exception");
        //TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager(), attributes);
        TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, attributes);
        return txAdvice;
    }
 
 
    //@Bean
    //public AspectJExpressionPointcut aspectJExpressionPointcut(){
    //    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    //    pointcut.setExpression(transactionExecution);
    //    return pointcut;
    //}
 
    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor(){
        //AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        //pointcut.setExpression(transactionExecution);
        //DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        //advisor.setPointcut(pointcut);
        //advisor.setAdvice(transactionInterceptor());
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(transactionExecution);
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        Properties attributes = new Properties();
        attributes.setProperty("get*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("add*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("update*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("delete*", "PROPAGATION_REQUIRED,-Exception");
        TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, attributes);
        advisor.setAdvice(txAdvice);
        return advisor;
    }
}


简单来说,springboot使用上述注解的几种方式开启事物,可以达到和xml中声明的同样效果,但是却告别了xml,使你的代码远离配置文件。


文章出处:http://www.cnblogs.com/guozp/articles/7446477.html 


相关文章
|
1天前
|
Java API 数据安全/隐私保护
掌握Spring Boot中的@Validated注解
【4月更文挑战第23天】在 Spring Boot 开发中,@Validated 注解是用于开启和利用 Spring 的验证框架的一种方式,特别是在处理控制层的输入验证时。本篇技术博客将详细介绍 @Validated 注解的概念和使用方法,并通过实际的应用示例来展示如何在项目中实现有效的数据验证
26 3
|
1天前
|
前端开发 Java 开发者
深入理解Spring Boot中的@Service注解
【4月更文挑战第22天】在 Spring Boot 应用开发中,@Service 注解扮演着特定的角色,主要用于标识服务层组件。本篇技术博客将全面探讨 @Service 注解的概念,并提供实际的应用示例,帮助开发者理解如何有效地使用这一注解来优化应用的服务层架构
82 1
|
1天前
|
缓存 Java Sentinel
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
|
1天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
1天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
1天前
|
JavaScript Java 开发者
Spring Boot中的@Lazy注解:概念及实战应用
【4月更文挑战第7天】在Spring Framework中,@Lazy注解是一个非常有用的特性,它允许开发者控制Spring容器的bean初始化时机。本文将详细介绍@Lazy注解的概念,并通过一个实际的例子展示如何在Spring Boot应用中使用它。
21 2
|
1天前
|
前端开发 Java
SpringBoot之自定义注解参数校验
SpringBoot之自定义注解参数校验
19 2
|
1天前
|
Java Spring
springboot自带的@Scheduled注解开启定时任务
springboot自带的@Scheduled注解开启定时任务
|
1天前
|
XML JSON Java
【SpringBoot】springboot常用注解
【SpringBoot】springboot常用注解
|
1天前
|
Java 数据库 开发者
了解Spring Boot:重要注解详解
了解Spring Boot:重要注解详解