当前位置:   article > 正文

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

springboot entityinformation

一,spring事务的机制

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

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

数据访问技术及实现:

JDBC  ->DataSourceTransactionManager

JPA  -> JpaTransactionManager

Hibernate   ->HibernateTransactionManager

JDO    ->   JdoTransactionManager

分布式事务   -> JtaTransactionManager



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

  1. @Bean
  2. public PlatformTransactionManager transactionManager(){
  3. JpaTransactionManager transactionManager = new JpaTransactionManager();
  4. transactionManager.setDataSource(dataSource);
  5. return transactionManager;
  6. }


二,声明式事务

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

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


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

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

  1. package com.example.springboot7transaction.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.transaction.annotation.EnableTransactionManagement;
  4. /**
  5. * create by jack 2017/10/8
  6. */
  7. @Configuration
  8. @EnableTransactionManagement
  9. public class AppConfig {
  10. }


三,注解事务行为

     @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的源码可以看到,下面来看看

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package org.springframework.data.jpa.repository.support;
  6. import java.io.Serializable;
  7. import java.util.ArrayList;
  8. import java.util.Collections;
  9. import java.util.HashMap;
  10. import java.util.Iterator;
  11. import java.util.List;
  12. import java.util.Map;
  13. import java.util.Map.Entry;
  14. import javax.persistence.EntityManager;
  15. import javax.persistence.LockModeType;
  16. import javax.persistence.NoResultException;
  17. import javax.persistence.Query;
  18. import javax.persistence.TypedQuery;
  19. import javax.persistence.criteria.CriteriaBuilder;
  20. import javax.persistence.criteria.CriteriaQuery;
  21. import javax.persistence.criteria.Expression;
  22. import javax.persistence.criteria.ParameterExpression;
  23. import javax.persistence.criteria.Path;
  24. import javax.persistence.criteria.Predicate;
  25. import javax.persistence.criteria.Root;
  26. import org.springframework.dao.EmptyResultDataAccessException;
  27. import org.springframework.data.domain.Example;
  28. import org.springframework.data.domain.Page;
  29. import org.springframework.data.domain.PageImpl;
  30. import org.springframework.data.domain.Pageable;
  31. import org.springframework.data.domain.Sort;
  32. import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
  33. import org.springframework.data.jpa.domain.Specification;
  34. import org.springframework.data.jpa.provider.PersistenceProvider;
  35. import org.springframework.data.jpa.repository.JpaRepository;
  36. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  37. import org.springframework.data.jpa.repository.query.Jpa21Utils;
  38. import org.springframework.data.jpa.repository.query.JpaEntityGraph;
  39. import org.springframework.data.jpa.repository.query.QueryUtils;
  40. import org.springframework.data.repository.support.PageableExecutionUtils;
  41. import org.springframework.data.repository.support.PageableExecutionUtils.TotalSupplier;
  42. import org.springframework.stereotype.Repository;
  43. import org.springframework.transaction.annotation.Transactional;
  44. import org.springframework.util.Assert;
  45. @Repository
  46. @Transactional(
  47. readOnly = true
  48. )
  49. public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
  50. private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!";
  51. private final JpaEntityInformation<T, ?> entityInformation;
  52. private final EntityManager em;
  53. private final PersistenceProvider provider;
  54. private CrudMethodMetadata metadata;
  55. public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
  56. Assert.notNull(entityInformation, "JpaEntityInformation must not be null!");
  57. Assert.notNull(entityManager, "EntityManager must not be null!");
  58. this.entityInformation = entityInformation;
  59. this.em = entityManager;
  60. this.provider = PersistenceProvider.fromEntityManager(entityManager);
  61. }
  62. public SimpleJpaRepository(Class<T> domainClass, EntityManager em) {
  63. this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
  64. }
  65. public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {
  66. this.metadata = crudMethodMetadata;
  67. }
  68. protected CrudMethodMetadata getRepositoryMethodMetadata() {
  69. return this.metadata;
  70. }
  71. protected Class<T> getDomainClass() {
  72. return this.entityInformation.getJavaType();
  73. }
  74. private String getDeleteAllQueryString() {
  75. return QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName());
  76. }
  77. private String getCountQueryString() {
  78. String countQuery = String.format("select count(%s) from %s x", this.provider.getCountQueryPlaceholder(), "%s");
  79. return QueryUtils.getQueryString(countQuery, this.entityInformation.getEntityName());
  80. }
  81. @Transactional
  82. public void delete(ID id) {
  83. Assert.notNull(id, "The given id must not be null!");
  84. T entity = this.findOne(id);
  85. if (entity == null) {
  86. throw new EmptyResultDataAccessException(String.format("No %s entity with id %s exists!", this.entityInformation.getJavaType(), id), 1);
  87. } else {
  88. this.delete(entity);
  89. }
  90. }
  91. @Transactional
  92. public void delete(T entity) {
  93. Assert.notNull(entity, "The entity must not be null!");
  94. this.em.remove(this.em.contains(entity) ? entity : this.em.merge(entity));
  95. }
  96. @Transactional
  97. public void delete(Iterable<? extends T> entities) {
  98. Assert.notNull(entities, "The given Iterable of entities not be null!");
  99. Iterator var2 = entities.iterator();
  100. while(var2.hasNext()) {
  101. T entity = var2.next();
  102. this.delete(entity);
  103. }
  104. }
  105. @Transactional
  106. public void deleteInBatch(Iterable<T> entities) {
  107. Assert.notNull(entities, "The given Iterable of entities not be null!");
  108. if (entities.iterator().hasNext()) {
  109. QueryUtils.applyAndBind(QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName()), entities, this.em).executeUpdate();
  110. }
  111. }
  112. @Transactional
  113. public void deleteAll() {
  114. Iterator var1 = this.findAll().iterator();
  115. while(var1.hasNext()) {
  116. T element = var1.next();
  117. this.delete(element);
  118. }
  119. }
  120. @Transactional
  121. public void deleteAllInBatch() {
  122. this.em.createQuery(this.getDeleteAllQueryString()).executeUpdate();
  123. }
  124. public T findOne(ID id) {
  125. Assert.notNull(id, "The given id must not be null!");
  126. Class<T> domainType = this.getDomainClass();
  127. if (this.metadata == null) {
  128. return this.em.find(domainType, id);
  129. } else {
  130. LockModeType type = this.metadata.getLockModeType();
  131. Map<String, Object> hints = this.getQueryHints();
  132. return type == null ? this.em.find(domainType, id, hints) : this.em.find(domainType, id, type, hints);
  133. }
  134. }
  135. protected Map<String, Object> getQueryHints() {
  136. if (this.metadata.getEntityGraph() == null) {
  137. return this.metadata.getQueryHints();
  138. } else {
  139. Map<String, Object> hints = new HashMap();
  140. hints.putAll(this.metadata.getQueryHints());
  141. hints.putAll(Jpa21Utils.tryGetFetchGraphHints(this.em, this.getEntityGraph(), this.getDomainClass()));
  142. return hints;
  143. }
  144. }
  145. private JpaEntityGraph getEntityGraph() {
  146. String fallbackName = this.entityInformation.getEntityName() + "." + this.metadata.getMethod().getName();
  147. return new JpaEntityGraph(this.metadata.getEntityGraph(), fallbackName);
  148. }
  149. public T getOne(ID id) {
  150. Assert.notNull(id, "The given id must not be null!");
  151. return this.em.getReference(this.getDomainClass(), id);
  152. }
  153. public boolean exists(ID id) {
  154. Assert.notNull(id, "The given id must not be null!");
  155. if (this.entityInformation.getIdAttribute() == null) {
  156. return this.findOne(id) != null;
  157. } else {
  158. String placeholder = this.provider.getCountQueryPlaceholder();
  159. String entityName = this.entityInformation.getEntityName();
  160. Iterable<String> idAttributeNames = this.entityInformation.getIdAttributeNames();
  161. String existsQuery = QueryUtils.getExistsQueryString(entityName, placeholder, idAttributeNames);
  162. TypedQuery<Long> query = this.em.createQuery(existsQuery, Long.class);
  163. if (!this.entityInformation.hasCompositeId()) {
  164. query.setParameter((String)idAttributeNames.iterator().next(), id);
  165. return ((Long)query.getSingleResult()).longValue() == 1L;
  166. } else {
  167. Iterator var7 = idAttributeNames.iterator();
  168. while(var7.hasNext()) {
  169. String idAttributeName = (String)var7.next();
  170. Object idAttributeValue = this.entityInformation.getCompositeIdAttributeValue(id, idAttributeName);
  171. boolean complexIdParameterValueDiscovered = idAttributeValue != null && !query.getParameter(idAttributeName).getParameterType().isAssignableFrom(idAttributeValue.getClass());
  172. if (complexIdParameterValueDiscovered) {
  173. return this.findOne(id) != null;
  174. }
  175. query.setParameter(idAttributeName, idAttributeValue);
  176. }
  177. return ((Long)query.getSingleResult()).longValue() == 1L;
  178. }
  179. }
  180. }
  181. public List<T> findAll() {
  182. return this.getQuery((Specification)null, (Sort)((Sort)null)).getResultList();
  183. }
  184. public List<T> findAll(Iterable<ID> ids) {
  185. if (ids != null && ids.iterator().hasNext()) {
  186. if (!this.entityInformation.hasCompositeId()) {
  187. SimpleJpaRepository.ByIdsSpecification<T> specification = new SimpleJpaRepository.ByIdsSpecification(this.entityInformation);
  188. TypedQuery<T> query = this.getQuery(specification, (Sort)((Sort)null));
  189. return query.setParameter(specification.parameter, ids).getResultList();
  190. } else {
  191. List<T> results = new ArrayList();
  192. Iterator var3 = ids.iterator();
  193. while(var3.hasNext()) {
  194. ID id = (Serializable)var3.next();
  195. results.add(this.findOne(id));
  196. }
  197. return results;
  198. }
  199. } else {
  200. return Collections.emptyList();
  201. }
  202. }
  203. public List<T> findAll(Sort sort) {
  204. return this.getQuery((Specification)null, (Sort)sort).getResultList();
  205. }
  206. public Page<T> findAll(Pageable pageable) {
  207. return (Page)(null == pageable ? new PageImpl(this.findAll()) : this.findAll((Specification)null, pageable));
  208. }
  209. public T findOne(Specification<T> spec) {
  210. try {
  211. return this.getQuery(spec, (Sort)null).getSingleResult();
  212. } catch (NoResultException var3) {
  213. return null;
  214. }
  215. }
  216. public List<T> findAll(Specification<T> spec) {
  217. return this.getQuery(spec, (Sort)null).getResultList();
  218. }
  219. public Page<T> findAll(Specification<T> spec, Pageable pageable) {
  220. TypedQuery<T> query = this.getQuery(spec, pageable);
  221. return (Page)(pageable == null ? new PageImpl(query.getResultList()) : this.readPage(query, this.getDomainClass(), pageable, spec));
  222. }
  223. public List<T> findAll(Specification<T> spec, Sort sort) {
  224. return this.getQuery(spec, sort).getResultList();
  225. }
  226. public <S extends T> S findOne(Example<S> example) {
  227. try {
  228. return this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)((Sort)null)).getSingleResult();
  229. } catch (NoResultException var3) {
  230. return null;
  231. }
  232. }
  233. public <S extends T> long count(Example<S> example) {
  234. return executeCountQuery(this.getCountQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType())).longValue();
  235. }
  236. public <S extends T> boolean exists(Example<S> example) {
  237. return !this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)((Sort)null)).getResultList().isEmpty();
  238. }
  239. public <S extends T> List<S> findAll(Example<S> example) {
  240. return this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)((Sort)null)).getResultList();
  241. }
  242. public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
  243. return this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), example.getProbeType(), (Sort)sort).getResultList();
  244. }
  245. public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
  246. SimpleJpaRepository.ExampleSpecification<S> spec = new SimpleJpaRepository.ExampleSpecification(example);
  247. Class<S> probeType = example.getProbeType();
  248. TypedQuery<S> query = this.getQuery(new SimpleJpaRepository.ExampleSpecification(example), probeType, (Pageable)pageable);
  249. return (Page)(pageable == null ? new PageImpl(query.getResultList()) : this.readPage(query, probeType, pageable, spec));
  250. }
  251. public long count() {
  252. return ((Long)this.em.createQuery(this.getCountQueryString(), Long.class).getSingleResult()).longValue();
  253. }
  254. public long count(Specification<T> spec) {
  255. return executeCountQuery(this.getCountQuery(spec, this.getDomainClass())).longValue();
  256. }
  257. @Transactional
  258. public <S extends T> S save(S entity) {
  259. if (this.entityInformation.isNew(entity)) {
  260. this.em.persist(entity);
  261. return entity;
  262. } else {
  263. return this.em.merge(entity);
  264. }
  265. }
  266. @Transactional
  267. public <S extends T> S saveAndFlush(S entity) {
  268. S result = this.save(entity);
  269. this.flush();
  270. return result;
  271. }
  272. @Transactional
  273. public <S extends T> List<S> save(Iterable<S> entities) {
  274. List<S> result = new ArrayList();
  275. if (entities == null) {
  276. return result;
  277. } else {
  278. Iterator var3 = entities.iterator();
  279. while(var3.hasNext()) {
  280. S entity = var3.next();
  281. result.add(this.save(entity));
  282. }
  283. return result;
  284. }
  285. }
  286. @Transactional
  287. public void flush() {
  288. this.em.flush();
  289. }
  290. /** @deprecated */
  291. @Deprecated
  292. protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) {
  293. return this.readPage(query, this.getDomainClass(), pageable, spec);
  294. }
  295. protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable, final Specification<S> spec) {
  296. query.setFirstResult(pageable.getOffset());
  297. query.setMaxResults(pageable.getPageSize());
  298. return PageableExecutionUtils.getPage(query.getResultList(), pageable, new TotalSupplier() {
  299. public long get() {
  300. return SimpleJpaRepository.executeCountQuery(SimpleJpaRepository.this.getCountQuery(spec, domainClass)).longValue();
  301. }
  302. });
  303. }
  304. protected TypedQuery<T> getQuery(Specification<T> spec, Pageable pageable) {
  305. Sort sort = pageable == null ? null : pageable.getSort();
  306. return this.getQuery(spec, this.getDomainClass(), sort);
  307. }
  308. protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Pageable pageable) {
  309. Sort sort = pageable == null ? null : pageable.getSort();
  310. return this.getQuery(spec, domainClass, sort);
  311. }
  312. protected TypedQuery<T> getQuery(Specification<T> spec, Sort sort) {
  313. return this.getQuery(spec, this.getDomainClass(), sort);
  314. }
  315. protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Sort sort) {
  316. CriteriaBuilder builder = this.em.getCriteriaBuilder();
  317. CriteriaQuery<S> query = builder.createQuery(domainClass);
  318. Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);
  319. query.select(root);
  320. if (sort != null) {
  321. query.orderBy(QueryUtils.toOrders(sort, root, builder));
  322. }
  323. return this.applyRepositoryMethodMetadata(this.em.createQuery(query));
  324. }
  325. /** @deprecated */
  326. @Deprecated
  327. protected TypedQuery<Long> getCountQuery(Specification<T> spec) {
  328. return this.getCountQuery(spec, this.getDomainClass());
  329. }
  330. protected <S extends T> TypedQuery<Long> getCountQuery(Specification<S> spec, Class<S> domainClass) {
  331. CriteriaBuilder builder = this.em.getCriteriaBuilder();
  332. CriteriaQuery<Long> query = builder.createQuery(Long.class);
  333. Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);
  334. if (query.isDistinct()) {
  335. query.select(builder.countDistinct(root));
  336. } else {
  337. query.select(builder.count(root));
  338. }
  339. query.orderBy(Collections.emptyList());
  340. return this.em.createQuery(query);
  341. }
  342. private <S, U extends T> Root<U> applySpecificationToCriteria(Specification<U> spec, Class<U> domainClass, CriteriaQuery<S> query) {
  343. Assert.notNull(domainClass, "Domain class must not be null!");
  344. Assert.notNull(query, "CriteriaQuery must not be null!");
  345. Root<U> root = query.from(domainClass);
  346. if (spec == null) {
  347. return root;
  348. } else {
  349. CriteriaBuilder builder = this.em.getCriteriaBuilder();
  350. Predicate predicate = spec.toPredicate(root, query, builder);
  351. if (predicate != null) {
  352. query.where(predicate);
  353. }
  354. return root;
  355. }
  356. }
  357. private <S> TypedQuery<S> applyRepositoryMethodMetadata(TypedQuery<S> query) {
  358. if (this.metadata == null) {
  359. return query;
  360. } else {
  361. LockModeType type = this.metadata.getLockModeType();
  362. TypedQuery<S> toReturn = type == null ? query : query.setLockMode(type);
  363. this.applyQueryHints(toReturn);
  364. return toReturn;
  365. }
  366. }
  367. private void applyQueryHints(Query query) {
  368. Iterator var2 = this.getQueryHints().entrySet().iterator();
  369. while(var2.hasNext()) {
  370. Entry<String, Object> hint = (Entry)var2.next();
  371. query.setHint((String)hint.getKey(), hint.getValue());
  372. }
  373. }
  374. private static Long executeCountQuery(TypedQuery<Long> query) {
  375. Assert.notNull(query, "TypedQuery must not be null!");
  376. List<Long> totals = query.getResultList();
  377. Long total = 0L;
  378. Long element;
  379. for(Iterator var3 = totals.iterator(); var3.hasNext(); total = total.longValue() + (element == null ? 0L : element.longValue())) {
  380. element = (Long)var3.next();
  381. }
  382. return total;
  383. }
  384. private static class ExampleSpecification<T> implements Specification<T> {
  385. private final Example<T> example;
  386. public ExampleSpecification(Example<T> example) {
  387. Assert.notNull(example, "Example must not be null!");
  388. this.example = example;
  389. }
  390. public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  391. return QueryByExamplePredicateBuilder.getPredicate(root, cb, this.example);
  392. }
  393. }
  394. private static final class ByIdsSpecification<T> implements Specification<T> {
  395. private final JpaEntityInformation<T, ?> entityInformation;
  396. ParameterExpression<Iterable> parameter;
  397. public ByIdsSpecification(JpaEntityInformation<T, ?> entityInformation) {
  398. this.entityInformation = entityInformation;
  399. }
  400. public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  401. Path<?> path = root.get(this.entityInformation.getIdAttribute());
  402. this.parameter = cb.parameter(Iterable.class);
  403. return path.in(new Expression[]{this.parameter});
  404. }
  405. }
  406. }


     从源码可以看出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类中的定义:

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package org.springframework.boot.autoconfigure.jdbc;
  6. import javax.sql.DataSource;
  7. import org.springframework.beans.factory.ObjectProvider;
  8. import org.springframework.boot.autoconfigure.AutoConfigureOrder;
  9. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  10. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  11. import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
  12. import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
  13. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  14. import org.springframework.context.annotation.Bean;
  15. import org.springframework.context.annotation.Configuration;
  16. import org.springframework.jdbc.core.JdbcTemplate;
  17. import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  18. import org.springframework.transaction.PlatformTransactionManager;
  19. @Configuration
  20. @ConditionalOnClass({JdbcTemplate.class, PlatformTransactionManager.class})
  21. @AutoConfigureOrder(2147483647)
  22. @EnableConfigurationProperties({DataSourceProperties.class})
  23. public class DataSourceTransactionManagerAutoConfiguration {
  24. public DataSourceTransactionManagerAutoConfiguration() {
  25. }
  26. @Configuration
  27. @ConditionalOnSingleCandidate(DataSource.class)
  28. static class DataSourceTransactionManagerConfiguration {
  29. private final DataSource dataSource;
  30. private final TransactionManagerCustomizers transactionManagerCustomizers;
  31. DataSourceTransactionManagerConfiguration(DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
  32. this.dataSource = dataSource;
  33. this.transactionManagerCustomizers = (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable();
  34. }
  35. @Bean
  36. @ConditionalOnMissingBean({PlatformTransactionManager.class})
  37. public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {
  38. DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);
  39. if (this.transactionManagerCustomizers != null) {
  40. this.transactionManagerCustomizers.customize(transactionManager);
  41. }
  42. return transactionManager;
  43. }
  44. }
  45. }


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

  1. @Bean
  2. @ConditionalOnMissingBean({PlatformTransactionManager.class})
  3. public PlatformTransactionManager transactionManager() {
  4. JpaTransactionManager transactionManager = new JpaTransactionManager();
  5. if (this.transactionManagerCustomizers != null) {
  6. this.transactionManagerCustomizers.customize(transactionManager);
  7. }
  8. return transactionManager;
  9. }


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

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

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

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package org.springframework.boot.autoconfigure.jdbc;
  6. import javax.sql.DataSource;
  7. import org.springframework.beans.factory.ObjectProvider;
  8. import org.springframework.boot.autoconfigure.AutoConfigureOrder;
  9. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  10. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  11. import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
  12. import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
  13. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  14. import org.springframework.context.annotation.Bean;
  15. import org.springframework.context.annotation.Configuration;
  16. import org.springframework.jdbc.core.JdbcTemplate;
  17. import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  18. import org.springframework.transaction.PlatformTransactionManager;
  19. @Configuration
  20. @ConditionalOnClass({JdbcTemplate.class, PlatformTransactionManager.class})
  21. @AutoConfigureOrder(2147483647)
  22. @EnableConfigurationProperties({DataSourceProperties.class})
  23. public class DataSourceTransactionManagerAutoConfiguration {
  24. public DataSourceTransactionManagerAutoConfiguration() {
  25. }
  26. @Configuration
  27. @ConditionalOnSingleCandidate(DataSource.class)
  28. static class DataSourceTransactionManagerConfiguration {
  29. private final DataSource dataSource;
  30. private final TransactionManagerCustomizers transactionManagerCustomizers;
  31. DataSourceTransactionManagerConfiguration(DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
  32. this.dataSource = dataSource;
  33. this.transactionManagerCustomizers = (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable();
  34. }
  35. @Bean
  36. @ConditionalOnMissingBean({PlatformTransactionManager.class})
  37. public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {
  38. DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);
  39. if (this.transactionManagerCustomizers != null) {
  40. this.transactionManagerCustomizers.customize(transactionManager);
  41. }
  42. return transactionManager;
  43. }
  44. }
  45. }


   所以在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,实体类

  1. package com.example.springboot7transaction.entity;
  2. import javax.persistence.Entity;
  3. import javax.persistence.GeneratedValue;
  4. import javax.persistence.GenerationType;
  5. import javax.persistence.Id;
  6. /**
  7. * create by jack 2017/10/3
  8. */
  9. //@Entity注解指明这是一个和数据库表映射的实体类
  10. @Entity
  11. public class Person {
  12. /**
  13. * 主键id
  14. * @Id注解指明这个属性映射为数据库的主键
  15. * @GeneratedValue定义主键生成的方式,下面采用的是mysql的自增属性
  16. */
  17. @Id
  18. @GeneratedValue(strategy= GenerationType.AUTO)
  19. private Integer id;
  20. /**
  21. * 姓名
  22. */
  23. private String name;
  24. /**
  25. * 年龄
  26. */
  27. private Integer age;
  28. /**
  29. * 地址
  30. */
  31. private String address;
  32. public Person() {
  33. super();
  34. }
  35. public Person(Integer id, String name, Integer age, String address) {
  36. super();
  37. this.id = id;
  38. this.name = name;
  39. this.age = age;
  40. this.address = address;
  41. }
  42. public Integer getId() {
  43. return id;
  44. }
  45. public void setId(Integer id) {
  46. this.id = id;
  47. }
  48. public String getName() {
  49. return name;
  50. }
  51. public void setName(String name) {
  52. this.name = name;
  53. }
  54. public Integer getAge() {
  55. return age;
  56. }
  57. public void setAge(Integer age) {
  58. this.age = age;
  59. }
  60. public String getAddress() {
  61. return address;
  62. }
  63. public void setAddress(String address) {
  64. this.address = address;
  65. }
  66. }


3,实体类Repository

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


4,业务服务Service

1)服务接口

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

2)服务实现

  1. package com.example.springboot7transaction.impl;
  2. import com.example.springboot7transaction.dao.PersonRepository;
  3. import com.example.springboot7transaction.entity.Person;
  4. import com.example.springboot7transaction.service.DemoService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. import org.springframework.transaction.annotation.Transactional;
  8. /**
  9. * create by jack 2017/10/8
  10. */
  11. @Service
  12. public class DemoServiceImpl implements DemoService{
  13. /**
  14. * 直接注入我们的PersonRepository
  15. */
  16. @Autowired
  17. private PersonRepository personRepository;
  18. /**
  19. * 使用@Transactional注解的rollbackFor属性,指定特定异常时,数据回滚
  20. * @param person
  21. * @return
  22. */
  23. @Transactional(rollbackFor = {IllegalArgumentException.class})
  24. @Override
  25. public Person savePersonWithRollBack(Person person) {
  26. Person p = personRepository.save(person);
  27. if (person.getName().equals("jack7")) {
  28. //抛出异常
  29. throw new IllegalArgumentException("jack7已存在,数据将回滚");
  30. }
  31. return p;
  32. }
  33. /**
  34. * 使用@Transactional注解的noRollbackFor属性,指定特定异常时,数据不回滚
  35. * @param person
  36. * @return
  37. */
  38. @Transactional(noRollbackFor = {IllegalArgumentException.class})
  39. @Override
  40. public Person savePersonWithoutRollBack(Person person) {
  41. Person p = personRepository.save(person);
  42. if ("jack7".equals(person.getName())) {
  43. //抛出异常
  44. throw new IllegalArgumentException("jack7已存在,数据将不会回滚");
  45. }
  46. return p;
  47. }
  48. }


5,控制器

  1. package com.example.springboot7transaction.controller;
  2. import com.example.springboot7transaction.entity.Person;
  3. import com.example.springboot7transaction.service.DemoService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. /**
  8. * create by jack 2017/10/8
  9. */
  10. @RestController
  11. @RequestMapping("transaction")
  12. public class TransactionController {
  13. @Autowired
  14. private DemoService demoService;
  15. /**
  16. * 测试回滚情况
  17. * @param person
  18. * @return
  19. */
  20. @RequestMapping("/rollback")
  21. public Person rollback(Person person){
  22. return demoService.savePersonWithRollBack(person);
  23. }
  24. /**
  25. * 测试不回滚情况
  26. * @param person
  27. * @return
  28. */
  29. @RequestMapping("/norollback")
  30. public Person noRollback(Person person){
  31. return demoService.savePersonWithoutRollBack(person);
  32. }
  33. }


6,运行测试

  1)回滚

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



  1. java.lang.IllegalArgumentException: jack7已存在,数据将回滚
  2. at com.example.springboot7transaction.impl.DemoServiceImpl.savePersonWithRollBack(DemoServiceImpl.java:32) ~[classes/:na]
  3. at com.example.springboot7transaction.impl.DemoServiceImpl$$FastClassBySpringCGLIB$$23f3bcdb.invoke(<generated>) ~[classes/:na]
  4. at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  5. at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  6. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  7. at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  8. at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  9. at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  10. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  11. at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  12. at com.example.springboot7transaction.impl.DemoServiceImpl$$EnhancerBySpringCGLIB$$c5ef9eec.savePersonWithRollBack(<generated>) ~[classes/:na]
  13. at com.example.springboot7transaction.controller.TransactionController.rollback(TransactionController.java:25) ~[classes/:na]
  14. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]
  15. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_111]
  16. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]
  17. at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]
  18. at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  19. at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  20. at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  21. at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  22. at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  23. at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  24. at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  25. at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  26. at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  27. at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  28. at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  29. at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  30. at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  31. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  32. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  33. at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.20.jar:8.5.20]
  34. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  35. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  36. at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  37. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  38. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  39. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  40. at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  41. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  42. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  43. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  44. at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  45. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  46. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  47. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  48. at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  49. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  50. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  51. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  52. at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  53. at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.20.jar:8.5.20]
  54. at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.20.jar:8.5.20]
  55. at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.20.jar:8.5.20]
  56. at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.20.jar:8.5.20]
  57. at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.20.jar:8.5.20]
  58. at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.20.jar:8.5.20]
  59. at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.20.jar:8.5.20]
  60. at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.20.jar:8.5.20]
  61. at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.20.jar:8.5.20]
  62. at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457) [tomcat-embed-core-8.5.20.jar:8.5.20]
  63. at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.20.jar:8.5.20]
  64. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]
  65. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
  66. at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.20.jar:8.5.20]
  67. at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]



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


2)不回滚

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


  1. java.lang.IllegalArgumentException: jack7已存在,数据将不会回滚
  2. at com.example.springboot7transaction.impl.DemoServiceImpl.savePersonWithoutRollBack(DemoServiceImpl.java:48) ~[classes/:na]
  3. at com.example.springboot7transaction.impl.DemoServiceImpl$$FastClassBySpringCGLIB$$23f3bcdb.invoke(<generated>) ~[classes/:na]
  4. at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  5. at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  6. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  7. at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  8. at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  9. at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  10. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  11. at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  12. at com.example.springboot7transaction.impl.DemoServiceImpl$$EnhancerBySpringCGLIB$$c5ef9eec.savePersonWithoutRollBack(<generated>) ~[classes/:na]
  13. at com.example.springboot7transaction.controller.TransactionController.noRollback(TransactionController.java:35) ~[classes/:na]
  14. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]
  15. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_111]
  16. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]
  17. at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]
  18. at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  19. at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  20. at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  21. at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  22. at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  23. at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  24. at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  25. at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  26. at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  27. at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  28. at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  29. at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  30. at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  31. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  32. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  33. at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.20.jar:8.5.20]
  34. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  35. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  36. at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  37. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  38. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  39. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  40. at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  41. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  42. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  43. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  44. at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  45. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  46. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  47. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  48. at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  49. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar:4.3.11.RELEASE]
  50. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  51. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  52. at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
  53. at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.20.jar:8.5.20]
  54. at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.20.jar:8.5.20]
  55. at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.20.jar:8.5.20]
  56. at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.20.jar:8.5.20]
  57. at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.20.jar:8.5.20]
  58. at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.20.jar:8.5.20]
  59. at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.20.jar:8.5.20]
  60. at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.20.jar:8.5.20]
  61. at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.20.jar:8.5.20]
  62. at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457) [tomcat-embed-core-8.5.20.jar:8.5.20]
  63. at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.20.jar:8.5.20]
  64. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]
  65. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
  66. at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.20.jar:8.5.20]
  67. at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]





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




声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/56006
推荐阅读
相关标签
  

闽ICP备14008679号