欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot 注解事务声明式事务的方式

程序员文章站 2024-02-26 19:36:58
 springboot 对新人来说可能上手比springmvc要快,但是对于各位从springmvc转战到springboot的话,有些地方还需要适应下,尤其是xml配置。...

 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,使你的代码远离配置文件。

总结

以上所述是小编给大家介绍的springboot 注解事务声明式事务的方式,希望对大家有所帮助