@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 ...
随机推荐
- Ricker wavelet 简介
本文依照参考文献简介 Ricker wavelet . 参考: [1] Frequency of the Ricker wavelet DOI: 10.1190/GEO2014-0441.1 [2] ...
- QTCPSOCKET 客户端已连接 而服务器无响应
最近在使用qt coding一个项目时,使用到了qtcpsocket模块来编写客户端与服务器.在windows平台下还能正常工作,但是在ubuntu平台下,客户端提示已连接时,服务器却没有响应.经过排 ...
- iOS利用xcodebuild命令自动打包方法
1,xcode项目先打包试一下可以打包成功 2,创建一plist导出文件 3,xcodebuild命令直接运行 导出文件内容: <?xml version="1.0" enc ...
- mysql新增用户并开启远程连接
之前使用mysql一直使用root来连接登录数据库,现在想使用新的用户名来连接数据库,碰到数据连接不上的情况. 把这些记录下来,以备后用 1.首先,创建用户 CREATE USER 'xiazhenx ...
- for语句,range() 函式
for 语句在任意序列 (列表或者字符串) 中迭代时, 总是按照元素在序列中的出现顺序依次迭代. 2 ... a = ['cat', 'window', 'defenestrate']3 >&g ...
- Feign源码解析系列-注册套路
感谢不知名朋友的打赏,感谢你的支持! 开始 在追寻Feign源码的过程中发现了一些套路,既然是套路,就可以举一反三,所以值得关注. 这篇会详细解析Feign Client配置和初始化的方式,这些方式大 ...
- leetcode 813. Largest Sum of Averages
对于一个数组中的数进行分组,取每个组里的平均值进行加和的. 使用动态规划,其中dp[i][k]表示以i为结尾的有k个分组的,那么递推式为: dp[i][k]=dp[j][k-1]+(sum[i]-su ...
- 多线程——C++
线程: 先说进程,进程是应用程序的执行实例,每个进程拥有其私有的虚拟地址空间.代码.数据和其它系统资源组成.进程在运行时创建的资源随着进程的终止而死亡. 而线程是一个独立的执行流,是进程内部的一个独立 ...
- day09 小练习 斐波那契数列 文件
#2.写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素, # 并将其作为新列表返回. # def get_odd_list(info): # ul=info[1::2] # return ...
- SSH(Spring+Struts2+Hibernate) of mappings(SSH三大框架的映射问题)
错误提示: org.springframework.orm.hibernate3.HibernateSystemException: Unknown entity org.hibernate.Mapp ...