SpringBoot24-spingboot数据访问-声明式事务

来源:互联网 发布:优化9蒙古入侵 编辑:程序博客网 时间:2024/06/11 14:34

一,spring事务的机制

       所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务,提交事务来完成数据操作,或者在发生错误的时候回滚数据。

     而spring的事务机制是用统一的机制来处理不同数据访问技术的事务处理。spring的事务机制提供了一个PlatformTransactionManager接口,不同的数据访问技术的事务使用不同的接口实现,如下:

数据访问技术及实现:

JDBC  ->DataSourceTransactionManager

JPA  -> JpaTransactionManager

Hibernate   ->HibernateTransactionManager

JDO    ->   JdoTransactionManager

分布式事务   -> JtaTransactionManager



在程序中定义事务管理器的代码如下:

 @Bean    public PlatformTransactionManager transactionManager(){        JpaTransactionManager transactionManager = new JpaTransactionManager();        transactionManager.setDataSource(dataSource);        return transactionManager;    }


二,声明式事务

      Spring支持声明式事务,即使用注解来选择使用事务的方法,它使用@Transactional注解在方法上表明该方法需要事务支持。这是一个基于AOP的实现操作,被注解的方法在被调用时,Spring开启一个新的事务,当方法无异常运行结束后,Spring会提交这个事务。

 @Transactional    public void saveSomething(Integer id,String name){        //数据库操作    }


       在此需要特别注意的是,此@Transactional注解来自org.springframework.transaction.annotation包,而不是javax.transaction

     Spring提供了一个@EnableTransactionManagement注解在此配置类上来开启声明式事务的支持。使用了@EnableTransactionManagement后,Spring容器会自动扫描注解了@Transactional的方法和类。@EnableTransactionManagement的使用方式如下:

package com.example.springboot7transaction.config;import org.springframework.context.annotation.Configuration;import org.springframework.transaction.annotation.EnableTransactionManagement;/** * create by jack 2017/10/8 */@Configuration@EnableTransactionManagementpublic class AppConfig {}


三,注解事务行为

     @Transactional有如下的属性来定制事务行为。

propagation,propagation定义了事务的生命周期,主要有下面选项:

          REQUIRED:方法a调用时没有事务新建一个事务,当方法a调用另外一个方法b的时候,方法b将使用相同的事务;如果方法b发生异常需要回滚的时候,整个事务数据回滚。

         REQUIRED_NEW:对于方法a和b,在方法调用的时候无论是否有事务都开启一个新的事务;这样如果方法b有异常不会导致方法a的数据回滚。

        NESTED:和REQUIRED_NEW类似,但支持JDBC,不支持JPA或hibernate。

        SUPPORTS:方法调用时有事务就用事务,没事务就不用事务。

        NOT_SUPPORTS:强制方法不在事务中执行,若有事务,在方法调用到结束阶段事务都将会被挂起。

        NEVER:强制方法不在事务中执行,若有事务则抛出异常。

        MANDATORY:强制方法在事务中执行,若无事务则抛出异常

        默认:REQUIRED


isolation,isolation(隔离)决定了事务的完整性,处理在多事务对相同数据的处理机制,主要包含下面的隔离级别(当然不可以随便设置,这样看当前数据库是否支持):

        READ_UNCOMMITTED:对于在a事务里修改了一条记录但没有提交事务,在b事务可以读取到修改后的记录。可导致脏读,不可重复以及幻读。

        READ_COMMITTED:只有当在事务a里修改了一条记录且提交事务后,b事务才可以读取到提交的记录;阻止脏读,但可导致不可重复读和幻读。

        REPEATABLE_READ:不仅能实现READ_COMMITTED的功能,而且还能阻止当a事务读取了一条记录,b事务将不允许修改这条记录;阻止脏读和不可重复读,当可出现幻读。

         SERIALIZABLE:此级别下事务是顺序执行的,可避免上述级别的缺陷,但开销较大。

        DEFAULT:使用当前数据库的默认隔离级别,如ORACLE,SQL Server是READ_COMMITTED;Mysql是REPEATABLE_READ

      默认值:DEFAULT


timeout,timeout指事务过期时间,默认当前数据库的事务过期时间,默认值TIMEOUT_DEFAULT。

readOnly,指定当前事务是否是只读事务,默认false。

rollbackFor,指定哪个或者哪些异常可以引起事务回滚,默认为Throwable的子类。

noRollbackFor,指定哪个或者哪些异常不可以引起事务回滚,默认为Throwable的子类


四,类级别使用@Transactional

      @Transactional不仅可以注解在此方法上,也可以注解在类上。当注解在类上的时候意味着此类级别的所有public方法都是开启事务的。如果类级别和方法级别同时使用了@Transactional注解,则使用方法级别注解覆盖类级别注解。


五,Spring Data JPA的事务支持

      Spring Data JPA对所有的默认方法都开启了事务支持,且查询类事务默认启用readOnly=true属性。

       这些我们在SimpleJpaRepository的源码可以看到,下面来看看

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.springframework.data.jpa.repository.support;import java.io.Serializable;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Map.Entry;import javax.persistence.EntityManager;import javax.persistence.LockModeType;import javax.persistence.NoResultException;import javax.persistence.Query;import javax.persistence.TypedQuery;import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Expression;import javax.persistence.criteria.ParameterExpression;import javax.persistence.criteria.Path;import javax.persistence.criteria.Predicate;import javax.persistence.criteria.Root;import org.springframework.dao.EmptyResultDataAccessException;import org.springframework.data.domain.Example;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageImpl;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;import org.springframework.data.jpa.domain.Specification;import org.springframework.data.jpa.provider.PersistenceProvider;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.jpa.repository.JpaSpecificationExecutor;import org.springframework.data.jpa.repository.query.Jpa21Utils;import org.springframework.data.jpa.repository.query.JpaEntityGraph;import org.springframework.data.jpa.repository.query.QueryUtils;import org.springframework.data.repository.support.PageableExecutionUtils;import org.springframework.data.repository.support.PageableExecutionUtils.TotalSupplier;import org.springframework.stereotype.Repository;import org.springframework.transaction.annotation.Transactional;import org.springframework.util.Assert;@Repository@Transactional(    readOnly = true)public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> {    private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!";    private final JpaEntityInformation<T, ?> entityInformation;    private final EntityManager em;    private final PersistenceProvider provider;    private CrudMethodMetadata metadata;    public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {        Assert.notNull(entityInformation, "JpaEntityInformation must not be null!");        Assert.notNull(entityManager, "EntityManager must not be null!");        this.entityInformation = entityInformation;        this.em = entityManager;        this.provider = PersistenceProvider.fromEntityManager(entityManager);    }    public SimpleJpaRepository(Class<T> domainClass, EntityManager em) {        this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);    }    public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {        this.metadata = crudMethodMetadata;    }    protected CrudMethodMetadata getRepositoryMethodMetadata() {        return this.metadata;    }    protected Class<T> getDomainClass() {        return this.entityInformation.getJavaType();    }    private String getDeleteAllQueryString() {        return QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName());    }    private String getCountQueryString() {        String countQuery = String.format("select count(%s) from %s x", this.provider.getCountQueryPlaceholder(), "%s");        return QueryUtils.getQueryString(countQuery, this.entityInformation.getEntityName());    }    @Transactional    public void delete(ID id) {        Assert.notNull(id, "The given id must not be null!");        T entity = this.findOne(id);        if (entity == null) {            throw new EmptyResultDataAccessException(String.format("No %s entity with id %s exists!", this.entityInformation.getJavaType(), id), 1);        } else {            this.delete(entity);        }    }    @Transactional    public void delete(T entity) {        Assert.notNull(entity, "The entity must not be null!");        this.em.remove(this.em.contains(entity) ? entity : this.em.merge(entity));    }    @Transactional    public void delete(Iterable<? extends T> entities) {        Assert.notNull(entities, "The given Iterable of entities not be null!");        Iterator var2 = entities.iterator();        while(var2.hasNext()) {            T entity = var2.next();            this.delete(entity);        }    }    @Transactional    public void deleteInBatch(Iterable<T> entities) {        Assert.notNull(entities, "The given Iterable of entities not be null!");        if (entities.iterator().hasNext()) {            QueryUtils.applyAndBind(QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName()), entities, this.em).executeUpdate();        }    }    @Transactional    public void deleteAll() {        Iterator var1 = this.findAll().iterator();        while(var1.hasNext()) {            T element = var1.next();            this.delete(element);        }    }    @Transactional    public void deleteAllInBatch() {        this.em.createQuery(this.getDeleteAllQueryString()).executeUpdate();    }    public T findOne(ID id) {        Assert.notNull(id, "The given id must not be null!");        Class<T> domainType = this.getDomainClass();        if (this.metadata == null) {            return this.em.find(domainType, id);        } else {            LockModeType type = this.metadata.getLockModeType();            Map<String, Object> hints = this.getQueryHints();            return type == null ? this.em.find(domainType, id, hints) : this.em.find(domainType, id, type, hints);        }    }    protected Map<String, Object> getQueryHints() {        if (this.metadata.getEntityGraph() == null) {            return this.metadata.getQueryHints();        } else {            Map<String, Object> hints = new HashMap();            hints.putAll(this.metadata.getQueryHints());            hints.putAll(Jpa21Utils.tryGetFetchGraphHints(this.em, this.getEntityGraph(), this.getDomainClass()));            return hints;        }    }    private JpaEntityGraph getEntityGraph() {        String fallbackName = this.entityInformation.getEntityName() + "." + this.metadata.getMethod().getName();        return new JpaEntityGraph(this.metadata.getEntityGraph(), fallbackName);    }    public T getOne(ID id) {        Assert.notNull(id, "The given id must not be null!");        return this.em.getReference(this.getDomainClass(), id);    }    public boolean exists(ID id) {        Assert.notNull(id, "The given id must not be null!");        if (this.entityInformation.getIdAttribute() == null) {            return this.findOne(id) != null;        } else {            String placeholder = this.provider.getCountQueryPlaceholder();            String entityName = this.entityInformation.getEntityName();            Iterable<String> idAttributeNames = this.entityInformation.getIdAttributeNames();            String existsQuery = QueryUtils.getExistsQueryString(entityName, placeholder, idAttributeNames);            TypedQuery<Long> query = this.em.createQuery(existsQuery, Long.class);            if (!this.entityInformation.hasCompositeId()) {                query.setParameter((String)idAttributeNames.iterator().next(), id);                return ((Long)query.getSingleResult()).longValue() == 1L;            } else {                Iterator var7 = idAttributeNames.iterator();                while(var7.hasNext()) {                    String idAttributeName = (String)var7.next();                    Object idAttributeValue = this.entityInformation.getCompositeIdAttributeValue(id, idAttributeName);                    boolean complexIdParameterValueDiscovered = idAttributeValue != null && !query.getParameter(idAttributeName).getParameterType().isAssignableFrom(idAttributeValue.getClass());                    if (complexIdParameterValueDiscovered) {                        return this.findOne(id) != null;                    }                    query.setParameter(idAttributeName, idAttributeValue);                }                return ((Long)query.getSingleResult()).longValue() == 1L;            }        }    }    public List<T> findAll() {        return this.getQuery((Specification)null, (Sort)((Sort)null)).getResultList();    }    public List<T> findAll(Iterable<ID> ids) {        if (ids != null && ids.iterator().hasNext()) {            if (!this.entityInformation.hasCompositeId()) {                SimpleJpaRepository.ByIdsSpecification<T> specification = new SimpleJpaRepository.ByIdsSpecification(this.entityInformation);                TypedQuery<T> query = this.getQuery(specification, (Sort)((Sort)null));                return query.setParameter(specification.parameter, ids).getResultList();            } else {                List<T> results = new ArrayList();                Iterator var3 = ids.iterator();                while(var3.hasNext()) {                    ID id = (Serializable)var3.next();                    results.add(this.findOne(id));                }                return results;            }        } else {            return Collections.emptyList();        }    }    public List<T> findAll(Sort sort) {        return this.getQuery((Specification)null, (Sort)sort).getResultList();    }    public Page<T> findAll(Pageable pageable) {        return (Page)(null == pageable ? new PageImpl(this.findAll()) : this.findAll((Specification)null, pageable));    }    public T findOne(Specification<T> spec) {        try {            return this.getQuery(spec, (Sort)null).getSingleResult();        } catch (NoResultException var3) {            return null;        }    }    public List<T> findAll(Specification<T> spec) {        return this.getQuery(spec, (Sort)null).getResultList();    }    public Page<T> findAll(Specification<T> spec, Pageable pageable) {        TypedQuery<T> query = this.getQuery(spec, pageable);        return (Page)(pageable == null ? new PageImpl(query.getResultList()) : this.readPage(query, this.getDomainClass(), pageable, spec));    }    public List<T> findAll(Specification<T> spec, Sort sort) {        return this.getQuery(spec, sort).getResultList();    }    public <S extends T> S findOne(Example<S> example) {        try {            return this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)((Sort)null)).getSingleResult();        } catch (NoResultException var3) {            return null;        }    }    public <S extends T> long count(Example<S> example) {        return executeCountQuery(this.getCountQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType())).longValue();    }    public <S extends T> boolean exists(Example<S> example) {        return !this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)((Sort)null)).getResultList().isEmpty();    }    public <S extends T> List<S> findAll(Example<S> example) {        return this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)((Sort)null)).getResultList();    }    public <S extends T> List<S> findAll(Example<S> example, Sort sort) {        return this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)sort).getResultList();    }    public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {        SimpleJpaRepository.ExampleSpecification<S> spec = new SimpleJpaRepository.ExampleSpecification(example);        Class<S> probeType = example.getProbeType();        TypedQuery<S> query = this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), probeType, (Pageable)pageable);        return (Page)(pageable == null ? new PageImpl(query.getResultList()) : this.readPage(query, probeType, pageable, spec));    }    public long count() {        return ((Long)this.em.createQuery(this.getCountQueryString(), Long.class).getSingleResult()).longValue();    }    public long count(Specification<T> spec) {        return executeCountQuery(this.getCountQuery(spec, this.getDomainClass())).longValue();    }    @Transactional    public <S extends T> S save(S entity) {        if (this.entityInformation.isNew(entity)) {            this.em.persist(entity);            return entity;        } else {            return this.em.merge(entity);        }    }    @Transactional    public <S extends T> S saveAndFlush(S entity) {        S result = this.save(entity);        this.flush();        return result;    }    @Transactional    public <S extends T> List<S> save(Iterable<S> entities) {        List<S> result = new ArrayList();        if (entities == null) {            return result;        } else {            Iterator var3 = entities.iterator();            while(var3.hasNext()) {                S entity = var3.next();                result.add(this.save(entity));            }            return result;        }    }    @Transactional    public void flush() {        this.em.flush();    }    /** @deprecated */    @Deprecated    protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) {        return this.readPage(query, this.getDomainClass(), pageable, spec);    }    protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable, final Specification<S> spec) {        query.setFirstResult(pageable.getOffset());        query.setMaxResults(pageable.getPageSize());        return PageableExecutionUtils.getPage(query.getResultList(), pageable, new TotalSupplier() {            public long get() {                return SimpleJpaRepository.executeCountQuery(SimpleJpaRepository.this.getCountQuery(spec, domainClass)).longValue();            }        });    }    protected TypedQuery<T> getQuery(Specification<T> spec, Pageable pageable) {        Sort sort = pageable == null ? null : pageable.getSort();        return this.getQuery(spec, this.getDomainClass(), sort);    }    protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Pageable pageable) {        Sort sort = pageable == null ? null : pageable.getSort();        return this.getQuery(spec, domainClass, sort);    }    protected TypedQuery<T> getQuery(Specification<T> spec, Sort sort) {        return this.getQuery(spec, this.getDomainClass(), sort);    }    protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Sort sort) {        CriteriaBuilder builder = this.em.getCriteriaBuilder();        CriteriaQuery<S> query = builder.createQuery(domainClass);        Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);        query.select(root);        if (sort != null) {            query.orderBy(QueryUtils.toOrders(sort, root, builder));        }        return this.applyRepositoryMethodMetadata(this.em.createQuery(query));    }    /** @deprecated */    @Deprecated    protected TypedQuery<Long> getCountQuery(Specification<T> spec) {        return this.getCountQuery(spec, this.getDomainClass());    }    protected <S extends T> TypedQuery<Long> getCountQuery(Specification<S> spec, Class<S> domainClass) {        CriteriaBuilder builder = this.em.getCriteriaBuilder();        CriteriaQuery<Long> query = builder.createQuery(Long.class);        Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);        if (query.isDistinct()) {            query.select(builder.countDistinct(root));        } else {            query.select(builder.count(root));        }        query.orderBy(Collections.emptyList());        return this.em.createQuery(query);    }    private <S, U extends T> Root<U> applySpecificationToCriteria(Specification<U> spec, Class<U> domainClass, CriteriaQuery<S> query) {        Assert.notNull(domainClass, "Domain class must not be null!");        Assert.notNull(query, "CriteriaQuery must not be null!");        Root<U> root = query.from(domainClass);        if (spec == null) {            return root;        } else {            CriteriaBuilder builder = this.em.getCriteriaBuilder();            Predicate predicate = spec.toPredicate(root, query, builder);            if (predicate != null) {                query.where(predicate);            }            return root;        }    }    private <S> TypedQuery<S> applyRepositoryMethodMetadata(TypedQuery<S> query) {        if (this.metadata == null) {            return query;        } else {            LockModeType type = this.metadata.getLockModeType();            TypedQuery<S> toReturn = type == null ? query : query.setLockMode(type);            this.applyQueryHints(toReturn);            return toReturn;        }    }    private void applyQueryHints(Query query) {        Iterator var2 = this.getQueryHints().entrySet().iterator();        while(var2.hasNext()) {            Entry<String, Object> hint = (Entry)var2.next();            query.setHint((String)hint.getKey(), hint.getValue());        }    }    private static Long executeCountQuery(TypedQuery<Long> query) {        Assert.notNull(query, "TypedQuery must not be null!");        List<Long> totals = query.getResultList();        Long total = 0L;        Long element;        for(Iterator var3 = totals.iterator(); var3.hasNext(); total = total.longValue() + (element == null ? 0L : element.longValue())) {            element = (Long)var3.next();        }        return total;    }    private static class ExampleSpecification<T> implements Specification<T> {        private final Example<T> example;        public ExampleSpecification(Example<T> example) {            Assert.notNull(example, "Example must not be null!");            this.example = example;        }        public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {            return QueryByExamplePredicateBuilder.getPredicate(root, cb, this.example);        }    }    private static final class ByIdsSpecification<T> implements Specification<T> {        private final JpaEntityInformation<T, ?> entityInformation;        ParameterExpression<Iterable> parameter;        public ByIdsSpecification(JpaEntityInformation<T, ?> entityInformation) {            this.entityInformation = entityInformation;        }        public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {            Path<?> path = root.get(this.entityInformation.getIdAttribute());            this.parameter = cb.parameter(Iterable.class);            return path.in(new Expression[]{this.parameter});        }    }}


     从源码可以看出SimpleJpaRepository在类级别定义了@Transactional(readOnly=true),而在和save,delete相关的操作重写了@Transactional属性,此时的readOnly属性是false,其余查询操作readOnly仍然为true。



六,Spring Boot的事务支持

1,自动配置的事务管理器

     在使用JDBC作为数据访问技术的时候Spring Boot为我们定义了PlatformTransactionManager的实现DataSourceTransactionManager的Bean;配置见org.springframework.boot.autoconfig.jdbc.DataSourceTransactionManagerAutoConfiguration类中的定义:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.springframework.boot.autoconfigure.jdbc;import javax.sql.DataSource;import org.springframework.beans.factory.ObjectProvider;import org.springframework.boot.autoconfigure.AutoConfigureOrder;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import org.springframework.transaction.PlatformTransactionManager;@Configuration@ConditionalOnClass({JdbcTemplate.class, PlatformTransactionManager.class})@AutoConfigureOrder(2147483647)@EnableConfigurationProperties({DataSourceProperties.class})public class DataSourceTransactionManagerAutoConfiguration {    public DataSourceTransactionManagerAutoConfiguration() {    }    @Configuration    @ConditionalOnSingleCandidate(DataSource.class)    static class DataSourceTransactionManagerConfiguration {        private final DataSource dataSource;        private final TransactionManagerCustomizers transactionManagerCustomizers;        DataSourceTransactionManagerConfiguration(DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {            this.dataSource = dataSource;            this.transactionManagerCustomizers = (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable();        }        @Bean        @ConditionalOnMissingBean({PlatformTransactionManager.class})        public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {            DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);            if (this.transactionManagerCustomizers != null) {                this.transactionManagerCustomizers.customize(transactionManager);            }            return transactionManager;        }    }}


      在是用JPA作为数据访问技术的时候,Spring Boot为我们定义了一个PlatformTransactionManager的实现JpaTransactionManager的Bean;配置见org.springframework.boot.autoconfig.orm.jpa.JpaBaseConfiguration.class类中的定义:

@Bean    @ConditionalOnMissingBean({PlatformTransactionManager.class})    public PlatformTransactionManager transactionManager() {        JpaTransactionManager transactionManager = new JpaTransactionManager();        if (this.transactionManagerCustomizers != null) {            this.transactionManagerCustomizers.customize(transactionManager);        }        return transactionManager;    }


2,自动开启注解事务的支持

      Spring Boot专门用于配置事务的类为:org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,此配置类依赖于JpaBaseConfiguratin和DataSourceTransactionManagerAutoConfiguration。

       而在DataSourceTransactionManagerAutoConfiguration配置里还开启了对声名事务的支持,代码如下:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.springframework.boot.autoconfigure.jdbc;import javax.sql.DataSource;import org.springframework.beans.factory.ObjectProvider;import org.springframework.boot.autoconfigure.AutoConfigureOrder;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import org.springframework.transaction.PlatformTransactionManager;@Configuration@ConditionalOnClass({JdbcTemplate.class, PlatformTransactionManager.class})@AutoConfigureOrder(2147483647)@EnableConfigurationProperties({DataSourceProperties.class})public class DataSourceTransactionManagerAutoConfiguration {    public DataSourceTransactionManagerAutoConfiguration() {    }    @Configuration    @ConditionalOnSingleCandidate(DataSource.class)    static class DataSourceTransactionManagerConfiguration {        private final DataSource dataSource;        private final TransactionManagerCustomizers transactionManagerCustomizers;        DataSourceTransactionManagerConfiguration(DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {            this.dataSource = dataSource;            this.transactionManagerCustomizers = (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable();        }        @Bean        @ConditionalOnMissingBean({PlatformTransactionManager.class})        public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {            DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);            if (this.transactionManagerCustomizers != null) {                this.transactionManagerCustomizers.customize(transactionManager);            }            return transactionManager;        }    }}


   所以在Spring Boot中,无须显示开启使用@EnableTransactionManagement注解。



七,实战

    在实际使用中,使用Spring Boot默认的配置就能满足我们绝大多数需求,下面的实战中演示如何使用@Transactional使用异常导致数据回滚和使用异常让数据不回滚。


1,新建spring boot项目,依赖JPA和web,添加mysql的驱动,修改application.yml属性:

pom.xml的代码如下:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>springboot7transaction</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>springboot7transaction</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.7.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mysql连接驱动--><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.39</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>


application.yml里面的配置如下:

server:  port: 9090spring:  datasource:    driver-class-name: com.mysql.jdbc.Driver    url: jdbc:mysql://127.0.0.1:3306/jack    username: root    password: root  jpa:    hibernate:    #hibernate\u63D0\u4F9B\u4E86\u6839\u636E\u5B9E\u4F53\u7C7B\u81EA\u52A8\u7EF4\u62A4\u6570\u636E\u5E93\u8868\u7ED3\u6784\u7684\u529F\u80FD\uFF0C\u53EF\u901A\u8FC7spring.jpa.hibernate.ddl-auto\u6765\u914D\u7F6E\uFF0C\u6709\u4E0B\u5217\u53EF\u9009\u9879    #create\uFF1A\u542F\u52A8\u65F6\u5220\u9664\u4E0A\u4E00\u6B21\u751F\u6210\u7684\u8868\uFF0C\u5E76\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0C\u8868\u4E2D\u6570\u636E\u4F1A\u88AB\u6E05\u7A7A    #create-drop\uFF1A\u542F\u52A8\u65F6\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0CsessionFacotry\u5173\u95ED\u65F6\u8868\u4F1A\u88AB\u5220\u9664    #update\uFF1A\u542F\u52A8\u65F6\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0C\u5F53\u5B9E\u4F53\u7C7B\u5C5E\u6027\u53D8\u52A8\u7684\u65F6\u5019\uFF0C\u8868\u7ED3\u6784\u4E5F\u4F1A\u66F4\u65B0\uFF0C\u5728\u521D\u671F\u5F00\u53D1\u9636\u6BB5\u4F7F\u7528\u6B64\u9879    #validate\uFF1B\u542F\u52A8\u65F6\u9A8C\u8BC1\u5B9E\u4F53\u7C7B\u548C\u6570\u636E\u8868\u662F\u5426\u4E00\u81F4\uFF0C\u5728\u6211\u4EEC\u6570\u636E\u7ED3\u6784\u7A33\u5B9A\u65F6\u91C7\u7528\u6B64\u9009\u9879    #none\uFF1A\u4E0D\u91C7\u53D6\u4EFB\u4F55\u63AA\u65BD      ddl-auto: update    #show-sql\u7528\u6765\u8BBE\u7F6Ehibernate\u64CD\u4F5C\u7684\u65F6\u5019\u5728\u63A7\u5236\u53F0\u663E\u793A\u5176\u771F\u5B9E\u7684sql\u8BED\u53E5    show-sql: true    properties:      hibernate:        dialect: org.hibernate.dialect.MySQL5Dialect  jackson:    serialization:    #\u8BA9\u63A7\u5236\u5668\u8F93\u51FA\u7684json\u5B57\u7B26\u4E32\u683C\u5F0F\u66F4\u7F8E\u89C2      indent_output: true


2,实体类

package com.example.springboot7transaction.entity;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;/** * create by jack 2017/10/3 *///@Entity注解指明这是一个和数据库表映射的实体类@Entitypublic class Person {    /**     * 主键id     * @Id注解指明这个属性映射为数据库的主键     * @GeneratedValue定义主键生成的方式,下面采用的是mysql的自增属性     */    @Id    @GeneratedValue(strategy= GenerationType.AUTO)    private Integer id;    /**     * 姓名     */    private String name;    /**     * 年龄     */    private Integer age;    /**     * 地址     */    private String address;    public Person() {        super();    }    public Person(Integer id, String name, Integer age, String address) {        super();        this.id = id;        this.name = name;        this.age = age;        this.address = address;    }    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }}


3,实体类Repository

package com.example.springboot7transaction.dao;import com.example.springboot7transaction.entity.Person;import org.springframework.data.jpa.repository.JpaRepository;/** * create by jack 2017/10/8 * 实体类 */public interface PersonRepository extends JpaRepository<Person,Integer>{}


4,业务服务Service

1)服务接口

package com.example.springboot7transaction.service;import com.example.springboot7transaction.entity.Person;/** * create by jack 2017/10/8 * 服务接口 */public interface DemoService {    Person savePersonWithRollBack(Person person);    Person savePersonWithoutRollBack(Person person);}

2)服务实现

package com.example.springboot7transaction.impl;import com.example.springboot7transaction.dao.PersonRepository;import com.example.springboot7transaction.entity.Person;import com.example.springboot7transaction.service.DemoService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;/** * create by jack 2017/10/8 */@Servicepublic class DemoServiceImpl implements DemoService{    /**     * 直接注入我们的PersonRepository     */    @Autowired    private PersonRepository personRepository;    /**     * 使用@Transactional注解的rollbackFor属性,指定特定异常时,数据回滚     * @param person     * @return     */    @Transactional(rollbackFor = {IllegalArgumentException.class})    @Override    public Person savePersonWithRollBack(Person person) {        Person p = personRepository.save(person);        if (person.getName().equals("jack7")) {            //抛出异常            throw new IllegalArgumentException("jack7已存在,数据将回滚");        }        return p;    }    /**     * 使用@Transactional注解的noRollbackFor属性,指定特定异常时,数据不回滚     * @param person     * @return     */    @Transactional(noRollbackFor = {IllegalArgumentException.class})    @Override    public Person savePersonWithoutRollBack(Person person) {        Person p = personRepository.save(person);        if ("jack7".equals(person.getName())) {            //抛出异常            throw new IllegalArgumentException("jack7已存在,数据将不会回滚");        }        return p;    }}


5,控制器

package com.example.springboot7transaction.controller;import com.example.springboot7transaction.entity.Person;import com.example.springboot7transaction.service.DemoService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * create by jack 2017/10/8 */@RestController@RequestMapping("transaction")public class TransactionController {    @Autowired    private DemoService demoService;    /**     * 测试回滚情况     * @param person     * @return     */    @RequestMapping("/rollback")    public Person rollback(Person person){        return demoService.savePersonWithRollBack(person);    }    /**     * 测试不回滚情况     * @param person     * @return     */    @RequestMapping("/norollback")    public Person noRollback(Person person){        return demoService.savePersonWithoutRollBack(person);    }}


6,运行测试

  1)回滚

    在postman输入http://localhost:9090/transaction/rollback?name=jack7&age=99,测试回滚情况,输出如下:



java.lang.IllegalArgumentException: jack7已存在,数据将回滚at com.example.springboot7transaction.impl.DemoServiceImpl.savePersonWithRollBack(DemoServiceImpl.java:32) ~[classes/:na]at com.example.springboot7transaction.impl.DemoServiceImpl$$FastClassBySpringCGLIB$$23f3bcdb.invoke(<generated>) ~[classes/:na]at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]at com.example.springboot7transaction.impl.DemoServiceImpl$$EnhancerBySpringCGLIB$$c5ef9eec.savePersonWithRollBack(<generated>) ~[classes/:na]at com.example.springboot7transaction.controller.TransactionController.rollback(TransactionController.java:25) ~[classes/:na]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_111]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.20.jar:8.5.20]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.20.jar:8.5.20]at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]



    查看数据库,发现没有进行数据的插入,数据进行插入的时候进行回滚了。


2)不回滚

     访问http://localhost:9090/transaction/norollback?name=jack7&age=99,虽然我们也抛出了异常,如下图所示,但是数据并没有进行回滚,且数据还新增了一条记录,如下:


java.lang.IllegalArgumentException: jack7已存在,数据将不会回滚at com.example.springboot7transaction.impl.DemoServiceImpl.savePersonWithoutRollBack(DemoServiceImpl.java:48) ~[classes/:na]at com.example.springboot7transaction.impl.DemoServiceImpl$$FastClassBySpringCGLIB$$23f3bcdb.invoke(<generated>) ~[classes/:na]at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]at com.example.springboot7transaction.impl.DemoServiceImpl$$EnhancerBySpringCGLIB$$c5ef9eec.savePersonWithoutRollBack(<generated>) ~[classes/:na]at com.example.springboot7transaction.controller.TransactionController.noRollback(TransactionController.java:35) ~[classes/:na]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_111]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457) [tomcat-embed-core-8.5.20.jar:8.5.20]at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.20.jar:8.5.20]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.20.jar:8.5.20]at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]





源码地址:https://github.com/wj903829182/SpringCloudTwo/tree/master/springboot7transaction




原创粉丝点击