springboot 事务统一配置_SpringBoot设置事务管理

本文探讨了在SpringBoot中如何开启和测试事务管理。通过引入jdbc依赖,Spring Boot会自动配置事务管理器。在Service层添加@Transactional注解实现事务控制。在无事务配置的情况下,数据库操作异常不会回滚;而添加事务注解后,事务会进行回滚,确保数据一致性。
摘要由CSDN通过智能技术生成

这里直接研究springboot中事务的开启以及测试方法。

在Spring Boot中推荐使用@Transactional注解来申明事务。

首先需要导入依赖:

org.springframework.boot

spring-boot-starter-jdbc

当引入jdbc依赖之后,Spring Boot会自动默认分别注入DataSourceTransactionManager或JpaTransactionManager,所以我们不需要任何额外配置就可以用@Transactional注解进行事务的使用。

在Service中添加@Transactional注解:

===================测试事务效果===========

Service层代码:

packagecn.qlq.service.impl.user;importjava.util.List;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importcn.qlq.bean.user.User;importcn.qlq.mapper.user.UserMapper;importcn.qlq.service.user.UserService;

@Servicepublic class UserServiceImpl implementsUserService {

@AutowiredprivateUserMapper userMapper;@Overridepublic voidaddUser(User user) {

userMapper.insert(user);int i = 1 / 0;

}

}

(1)测试未添加事务

数据库原来记录:

测试添加后查看日志:(插入数据之后报异常)

2019-02-21 16:25:20.983 INFO 20960 --- [nio-8088-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'

2019-02-21 16:25:20.984 INFO 20960 --- [nio-8088-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started2019-02-21 16:25:21.004 INFO 20960 --- [nio-8088-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 20ms2019-02-21 16:25:21.047 INFO 20960 --- [nio-8088-exec-1] cn.qlq.action.UserController : user -> User [id=null, username=2, password=2, userfullname=2, createtime=Thu Feb 21 16:25:21 CST 2019, isdeleted=null, sex=女, address=2]2019-02-21 16:25:21.320 DEBUG 20960 --- [nio-8088-exec-1] cn.qlq.mapper.user.UserMapper.insert : ==> Preparing: insert into user (id, username, password, userfullname, createtime, isdeleted, sex, address) values (?, ?, ?, ?, ?, ?, ?, ?)2019-02-21 16:25:21.335 DEBUG 20960 --- [nio-8088-exec-1] cn.qlq.mapper.user.UserMapper.insert : ==> Parameters: null, 2(String), 2(String), 2(String), 2019-02-21(Date), null, 女(String), 2(String)2019-02-21 16:25:21.674 DEBUG 20960 --- [nio-8088-exec-1] cn.qlq.mapper.user.UserMapper.insert : <== Updates: 1java.lang.ArithmeticException:/by zero

at cn.qlq.service.impl.user.UserServiceImpl.addUser(UserServiceImpl.java:27)

at cn.qlq.action.UserController.addUser(UserController.java:31)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:606)

at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)

at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)

at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116)

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)

at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)

at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)

at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)

at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)

at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)

at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)

at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)

at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)

at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)

at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)

at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

at java.lang.Thread.run(Thread.java:745)2019-02-21 16:25:21.763 WARN 20960 --- [nio-8088-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by Handler execution: java.lang.ArithmeticException: / by zero

查看数据库:(数据增加,没有事务回滚)

(2)测试添加事务

只需在类加上@Transactional注解就可以了。

测试查看日志同上面一样,但是事务进行回滚了,只是没有打出日志。(下次提交发现id会跳过本次提交的值)

查看数据库记录:

补充:原理理解

在再次使用事务的时候发现其回滚没有打印日志,于是就想的研究一下原理。

其自动配置是在springboot-autoconfig-xxx.jar中。入口类是:DataSourceTransactionManagerAutoConfiguration

(1)查看DataSourceTransactionManagerAutoConfiguration源码:

/**Eclipse Class Decompiler plugin, Copyright (c) 2017 Chen Chao.*/

packageorg.springframework.boot.autoconfigure.jdbc;importjavax.sql.DataSource;importorg.springframework.beans.factory.ObjectProvider;importorg.springframework.boot.autoconfigure.AutoConfigureOrder;importorg.springframework.boot.autoconfigure.EnableAutoConfiguration;importorg.springframework.boot.autoconfigure.condition.ConditionalOnClass;importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;importorg.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;importorg.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;importorg.springframework.boot.context.properties.EnableConfigurationProperties;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.core.Ordered;importorg.springframework.jdbc.core.JdbcTemplate;importorg.springframework.jdbc.datasource.DataSourceTransactionManager;importorg.springframework.transaction.PlatformTransactionManager;/*** {@linkEnableAutoConfiguration Auto-configuration} for

* {@linkDataSourceTransactionManager}.

*

*@authorDave Syer

*@authorStephane Nicoll

*@authorAndy Wilkinson

*@authorKazuki Shimizu

*@since1.0.0*/@Configuration(proxyBeanMethods= false)

@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class})

@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)

@EnableConfigurationProperties(DataSourceProperties.class)public classDataSourceTransactionManagerAutoConfiguration {

@Configuration(proxyBeanMethods= false)

@ConditionalOnSingleCandidate(DataSource.class)static classDataSourceTransactionManagerConfiguration {

@Bean

@ConditionalOnMissingBean(PlatformTransactionManager.class)

DataSourceTransactionManager transactionManager(DataSource dataSource,

ObjectProvidertransactionManagerCustomizers) {

DataSourceTransactionManager transactionManager= newDataSourceTransactionManager(dataSource);

transactionManagerCustomizers.ifAvailable((customizers)->customizers.customize(transactionManager));returntransactionManager;

}

}

}

ConditionalOnClass表示在当前类路径下存在对应的类。

第一步:去掉上面的pom配置,并且去掉JPA等配置,发现不存在PlatformTransactionManager类。(没有这个class类,但是没报错是因为是class文件不会再次编译)

如果需要我们自己写判断可以用name判断,值是包全路径。源码如下:

@Target({ ElementType.TYPE, ElementType.METHOD })

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Conditional(OnClassCondition.class)public @interfaceConditionalOnClass {Class>[] value() default{};String[] name()default{};

}

第二部:加上上面的pom配置发现在当前工程的classpath环境中可以找到上面类。

也可以在反编译的class文件中加断点测试,如果类路径有上面两个类会进入断点创建transactionManager对象;如果不存在不会进入断点。

在我们需要设置自己的事务管理器的时候可以重新返回一个PlatformTransactionManager对象,这些经常在使用动态数据源的时候需要设置自己的事务管理器,如下:

@BeanpublicPlatformTransactionManager transactionManager() {//配置事务管理, 使用事务时在方法头部添加@Transactional注解即可

return newDataSourceTransactionManager(dynamicDataSource());

}

(2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值