@Transactional的正确打开方式
经常用到事务管理,可还是不小心会写错,导致事务没有生效,这里总结下。
正确的代码例子如下所示,框架是使用spring+mybatis的,有些配置的就不贴出来了。
TestController2:
package com.test.controller; import com.alibaba.fastjson.JSON;
import com.cy.service.UserService;
import com.test.dto.Child;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
public class TestController2 { @Autowired
private UserService userService; /**
* 测试transcation
*/
@RequestMapping("/testTranscation.do")
public void testTranscation(){
String username = "小王";
String password = "123455";
userService.callAddUserMethod(username, password);
}
}
UserService接口:
package com.cy.service; import com.cy.entity.User; /**
* 用户Service接口
* @author Administrator
*
*/
public interface UserService { User login(User user); void addUserMethod(User user); void callAddUserMethod(String username, String password);
}
UserServiceImpl:
package com.cy.service.impl; import com.cy.dao.UserDao;
import com.cy.entity.User;
import com.cy.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; /**
* 用户Service实现类
* @author Administrator
*
*/
@Service("userService")
public class UserServiceImpl implements UserService { @Resource(name = "userService")
private UserService userService; @Autowired
private UserDao userDao; @Override
public User login(User user) {
return userDao.login(user);
} @Override
public void callAddUserMethod(String username, String password){
User user = new User();
user.setUsername(username);
user.setPassword(password);
try{
userService.addUserMethod(user);
}catch (Exception e){
System.err.println("addUserMethod异常:" + e.getMessage());
e.printStackTrace();
}
} @Transactional(rollbackFor = Exception.class)
@Override
public void addUserMethod(User user){
int a = userDao.addUser(user);
badMethod();
} private void badMethod(){
int i = 1/0;
} }
UserDao接口:
package com.cy.dao; import com.cy.entity.User; public interface UserDao { //登录
User login(User user); Integer addUser(User user);
}
UserMapper.xml(这里属于不重要的配置)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.dao.UserDao"> <select id="login" parameterType="User" resultType="User">
select * from t_user where username=#{username} and password=#{password}
</select> <insert id="addUser" parameterType="User">
INSERT INTO
t_user(
username,
password
)
VALUES(
#{username},
#{password}
)
</insert>
</mapper>
applicationContext.xml(这里属于不重要的配置,但是事务管理的配置重要)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 自动扫描 -->
<context:component-scan base-package="com.cy.service,com.test.service" /> <!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/demodb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean> <!-- 配置mybatis的sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mappers.xml文件 -->
<property name="mapperLocations" value="classpath:com/cy/mappers/*.xml"></property>
<!-- mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean> <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.cy.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean> <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> </beans>
mybatis-config.xml:(这个是完全不重要的配置)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 别名 -->
<typeAliases>
<package name="com.cy.entity"/>
</typeAliases> </configuration>
测试:
在浏览器中输入:http://localhost:8088/testTranscation.do,发现"小王"并没有被插入数据库,因为报异常回滚掉了。
console中可以看到事务的回滚rollback:
2019-03-29 14:41:52,411 [http-nio-8088-exec-3] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Acquired Connection [com.mysql.jdbc.JDBC4Connection@3f44f876] for JDBC transaction
2019-03-29 14:41:52,435 [http-nio-8088-exec-3] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@3f44f876] to manual commit
14:41:53.328 [http-nio-8088-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
14:41:53.353 [http-nio-8088-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5453248e]
14:41:53.384 [http-nio-8088-exec-3] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@3f44f876] will be managed by Spring
14:41:53.437 [http-nio-8088-exec-3] DEBUG com.cy.dao.UserDao.addUser - ==> Preparing: INSERT INTO t_user( username, password ) VALUES( ?, ? )
14:41:53.668 [http-nio-8088-exec-3] DEBUG com.cy.dao.UserDao.addUser - ==> Parameters: 小王(String), 123455(String)
14:41:53.669 [http-nio-8088-exec-3] DEBUG com.cy.dao.UserDao.addUser - <== Updates: 1
14:41:53.669 [http-nio-8088-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5453248e]
14:41:59.161 [http-nio-8088-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5453248e]
14:41:59.161 [http-nio-8088-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5453248e]
2019-03-29 14:41:59,161 [http-nio-8088-exec-3] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Initiating transaction rollback
2019-03-29 14:41:59,161 [http-nio-8088-exec-3] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@3f44f876]
2019-03-29 14:41:59,259 [http-nio-8088-exec-3] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3f44f876] after transaction
2019-03-29 14:41:59,259 [http-nio-8088-exec-3] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource
addUserMethod异常:/ by zero
java.lang.ArithmeticException: / by zero
at com.cy.service.impl.UserServiceImpl.badMethod(UserServiceImpl.java:51)
at com.cy.service.impl.UserServiceImpl.addUserMethod(UserServiceImpl.java:47)
总结:
1.@Transactional方法为接口方法,有异常往外抛。 (addUserMethod必须为接口方法)
2.@Transactional方法中可以有私有方法,有异常往外抛。(badMethod)
3.调用@Transactional的方法,可以对它try catch,且必须是接口.方法来调用。(callAddUserMethod中调用addUserMethod,必须是userService.addUserMethod,userServiceImpl把自己注进来)
4.配置文件中必须要有事务管理的配置,缺一不可:
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
5.@Transactional方法里面不要try catch异常,但是可以声明throws Exception;
@Transactional方法里面的方法也同样往外抛异常
UserService:
public interface UserService { User login(User user); void addUserMethod(User user) throws ArithmeticException; void callAddUserMethod(String username, String password);
}
UserServiceImpl:
package com.cy.service.impl; import com.cy.dao.UserDao;
import com.cy.entity.User;
import com.cy.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; /**
* 用户Service实现类
* @author Administrator
*
*/
@Service("userService")
public class UserServiceImpl implements UserService { @Resource(name = "userService")
private UserService userService; @Autowired
private UserDao userDao; @Override
public User login(User user) {
return userDao.login(user);
} @Override
public void callAddUserMethod(String username, String password){
User user = new User();
user.setUsername(username);
user.setPassword(password);
try{
userService.addUserMethod(user);
}catch (Exception e){
System.err.println("addUserMethod异常:" + e.getMessage());
e.printStackTrace();
}
} @Transactional(rollbackFor = Exception.class)
@Override
public void addUserMethod(User user) throws ArithmeticException{
int a = userDao.addUser(user);
badMethod();
} private void badMethod() throws ArithmeticException{
try{
int i = 1/0;
}catch (ArithmeticException e){
throw e;
}
} }
transcation事务也是生效的。
@Transactional的正确打开方式的更多相关文章
- iOS开发小技巧--相机相册的正确打开方式
iOS相机相册的正确打开方式- UIImagePickerController 通过指定sourceType来实现打开相册还是相机 UIImagePickerControllerSourceTypeP ...
- Xcode 的正确打开方式——Debugging(转载)
Xcode 的正确打开方式——Debugging 程序员日常开发中有大量时间都会花费在 debug 上,从事 iOS 开发不可避免地需要使用 Xcode.这篇博客就主要介绍了 Xcode 中几种能 ...
- C#语法——泛型的多种应用 C#语法——await与async的正确打开方式 C#线程安全使用(五) C#语法——元组类型 好好耕耘 redis和memcached的区别
C#语法——泛型的多种应用 本篇文章主要介绍泛型的应用. 泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性.类型安全性和效率. 泛型的定义 下面定义了 ...
- InnoDB缓冲池预加载在MySQL 5.7中的正确打开方式
InnoDB缓冲池预加载在MySQL 5.7中的正确打开方式 https://mp.weixin.qq.com/s/HGa_90XvC22anabiBF8AbQ 在这篇文章里,我将讨论在MySQL 5 ...
- Console控制台的正确打开方式
Console控制台的正确打开方式 console对象提供了访问浏览器调试模式的信息到控制台 -- Console对象 |-- assert() 如果第一个参数断言为false,则在控制台输出错误信息 ...
- 任务队列和异步接口的正确打开方式(.NET Core版本)
任务队列和异步接口的正确打开方式 什么是异步接口? Asynchronous Operations Certain types of operations might require processi ...
- (一)Redis for Windows正确打开方式
目录 (一)Redis for Windows正确打开方式 (二)Redis for 阿里云公网连接 (三)Redis for StackExchange.Redis 下载地址 官网.中文网1 及 中 ...
- List的remove()方法的三种正确打开方式
转: java编程:List的remove()方法的三种正确打开方式! 2018年08月12日 16:26:13 Aries9986 阅读数 2728更多 分类专栏: leetcode刷题 版权声 ...
- C++11随机数的正确打开方式
C++11随机数的正确打开方式 在C++11之前,现有的随机数函数都存在一个问题:在利用循环多次获取随机数时,如果程序运行过快或者使用了多线程等方法,srand((unsigned)time(null ...
随机推荐
- dos4章
批处理中的变量,我把他分为两类,分别为"系统变量"和"自定义变量" 我们现在来详解这两个变量! 一.系统变量 他们的值由系统将其根据事先定义的条件自动赋值,也就 ...
- caog
import pandas as pd#匹配可发库存1. import oslst=os.listdir(r'E:\每日必做\琪琪小象库存')lst1=[]for i in lst: if i[:2] ...
- Linux查看服务器配置
服务器型号 [root@txs ~]# dmidecode|grep "System Information" -A9|egrep "Manufacturer|Produ ...
- sublime text常用快捷键及多行光标批量操作教程
sublime text常用快捷键及多行光标批量操作教程 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a772304419/article/d ...
- python初识模块
sys import sys print(sys.argv) #输出 $ python test.py helo world ['test.py', 'helo', 'world'] # ...
- Mesh内存分配器的mmap小技巧
最近看了一篇内存分配器的论文,原理很简单,但是里面的数学论证还没看懂,这次先简单写一下原理和用到的API. 内存分配器是用于封装操作系统提供的底层API,给应用程序提供动态内存的.内存不断申请释放后, ...
- UVa439——骑士的移动
简单bfs #include <iostream> #include <cstring> #include <string> #include <map> ...
- django_视图层_编写url
URL的配置 django中,url也称urlconf,默认的django项目设定两个url地址,分别是admin站点管理和首页地址.from diango.urls import path,incl ...
- SDL中 so库的使用
用到的项目:Tocy-Android-SDLv2 JAVA层:只有一个 SDLActivity.java 路径\Android-SDLv2\src\org\libsdl\app 项目简单分析: 默认在 ...
- Python之jieba库的使用
jieba库,它是Python中一个重要的第三方中文分词函数库. 1.jieba的下载 由于jieba是一个第三方函数库,所以需要另外下载.电脑搜索“cmd”打开“命令提示符”,然后输入“pip in ...