经常用到事务管理,可还是不小心会写错,导致事务没有生效,这里总结下。

正确的代码例子如下所示,框架是使用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的正确打开方式的更多相关文章

  1. iOS开发小技巧--相机相册的正确打开方式

    iOS相机相册的正确打开方式- UIImagePickerController 通过指定sourceType来实现打开相册还是相机 UIImagePickerControllerSourceTypeP ...

  2. Xcode 的正确打开方式——Debugging(转载)

    Xcode 的正确打开方式——Debugging   程序员日常开发中有大量时间都会花费在 debug 上,从事 iOS 开发不可避免地需要使用 Xcode.这篇博客就主要介绍了 Xcode 中几种能 ...

  3. C#语法——泛型的多种应用 C#语法——await与async的正确打开方式 C#线程安全使用(五) C#语法——元组类型 好好耕耘 redis和memcached的区别

    C#语法——泛型的多种应用   本篇文章主要介绍泛型的应用. 泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性.类型安全性和效率. 泛型的定义 下面定义了 ...

  4. InnoDB缓冲池预加载在MySQL 5.7中的正确打开方式

    InnoDB缓冲池预加载在MySQL 5.7中的正确打开方式 https://mp.weixin.qq.com/s/HGa_90XvC22anabiBF8AbQ 在这篇文章里,我将讨论在MySQL 5 ...

  5. Console控制台的正确打开方式

    Console控制台的正确打开方式 console对象提供了访问浏览器调试模式的信息到控制台 -- Console对象 |-- assert() 如果第一个参数断言为false,则在控制台输出错误信息 ...

  6. 任务队列和异步接口的正确打开方式(.NET Core版本)

    任务队列和异步接口的正确打开方式 什么是异步接口? Asynchronous Operations Certain types of operations might require processi ...

  7. (一)Redis for Windows正确打开方式

    目录 (一)Redis for Windows正确打开方式 (二)Redis for 阿里云公网连接 (三)Redis for StackExchange.Redis 下载地址 官网.中文网1 及 中 ...

  8. List的remove()方法的三种正确打开方式

    转: java编程:List的remove()方法的三种正确打开方式! 2018年08月12日 16:26:13 Aries9986 阅读数 2728更多 分类专栏: leetcode刷题   版权声 ...

  9. C++11随机数的正确打开方式

    C++11随机数的正确打开方式 在C++11之前,现有的随机数函数都存在一个问题:在利用循环多次获取随机数时,如果程序运行过快或者使用了多线程等方法,srand((unsigned)time(null ...

随机推荐

  1. dos4章

    批处理中的变量,我把他分为两类,分别为"系统变量"和"自定义变量" 我们现在来详解这两个变量! 一.系统变量 他们的值由系统将其根据事先定义的条件自动赋值,也就 ...

  2. caog

    import pandas as pd#匹配可发库存1. import oslst=os.listdir(r'E:\每日必做\琪琪小象库存')lst1=[]for i in lst: if i[:2] ...

  3. Linux查看服务器配置

    服务器型号 [root@txs ~]# dmidecode|grep "System Information" -A9|egrep "Manufacturer|Produ ...

  4. sublime text常用快捷键及多行光标批量操作教程

    sublime text常用快捷键及多行光标批量操作教程   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a772304419/article/d ...

  5. python初识模块

    sys import sys   print(sys.argv)     #输出 $ python test.py helo world ['test.py', 'helo', 'world']  # ...

  6. Mesh内存分配器的mmap小技巧

    最近看了一篇内存分配器的论文,原理很简单,但是里面的数学论证还没看懂,这次先简单写一下原理和用到的API. 内存分配器是用于封装操作系统提供的底层API,给应用程序提供动态内存的.内存不断申请释放后, ...

  7. UVa439——骑士的移动

    简单bfs #include <iostream> #include <cstring> #include <string> #include <map> ...

  8. django_视图层_编写url

    URL的配置 django中,url也称urlconf,默认的django项目设定两个url地址,分别是admin站点管理和首页地址.from diango.urls import path,incl ...

  9. SDL中 so库的使用

    用到的项目:Tocy-Android-SDLv2 JAVA层:只有一个 SDLActivity.java 路径\Android-SDLv2\src\org\libsdl\app 项目简单分析: 默认在 ...

  10. Python之jieba库的使用

    jieba库,它是Python中一个重要的第三方中文分词函数库. 1.jieba的下载 由于jieba是一个第三方函数库,所以需要另外下载.电脑搜索“cmd”打开“命令提示符”,然后输入“pip in ...