赞
踩
所有的数据访问技术都有事务处理机制,这些技术提供了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
- @EnableTransactionManagement
- public 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不仅可以注解在此方法上,也可以注解在类上。当注解在类上的时候意味着此类级别的所有public方法都是开启事务的。如果类级别和方法级别同时使用了@Transactional注解,则使用方法级别注解覆盖类级别注解。
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。
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: 9090
spring:
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注解指明这是一个和数据库表映射的实体类
- @Entity
- public 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);
- }
- 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
- */
- @Service
- public 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。