文档章节

Spring Boot 中如何使用事务(十三)

老虎是个蛋蛋
 老虎是个蛋蛋
发布于 2018/12/28 18:38
字数 1486
阅读 4.3K
收藏 39

精选30+云产品,助力企业轻松上云!>>>

之前一篇有讲过如何在spring boot中集成JPA和Mybatis,本篇就在此基础上以JPA为例讲一下如何对事务进行操作

  • 创建一个spring boot项目,pom文件如下:
<?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.quick</groupId>
	<artifactId>quick-transactional</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>quick-transactional</name>
	<description>Demo project for Spring Boot</description>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.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-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</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>
  • 添加数据库连接配置:
spring:
  datasource:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/restful?useUnicode=true&characterEncoding=UTF-8&useSSL=false
      username: root
      password: root
      initialize: true
  init-db: true
  jpa:
      database: mysql
      show-sql: true
      hibernate:
        ddl-auto: update
        naming:
          strategy: org.hibernate.cfg.ImprovedNamingStrategy
  • 编写实体bean:
@Data
@Entity
@Table(name="book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false)
    private Integer id;

    @Column(nullable = false,name = "name")
    private String name;

    @Column(nullable = false,name = "isbn")
    private String isbn;

    @Column(nullable = false,name = "author")
    private String author;
}
@Data
@Entity
@Table(name="user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false)
    private Integer id;

    @Column(nullable = false,name = "name")
    private String name;

    @Column(nullable = false,name = "hobby")
    private String hobby;
}
  • 编写实体bean对应的Repository:
@Repository("bookRepository")
public interface BookRepository extends JpaRepository<Book,Integer>{
}
@Repository("userRepository")
public interface UserRepository extends JpaRepository<User,Integer> {
}
  • 编写供测试使用的service:
public interface BookService {
    void save();
}
@Service("bookService")
public class BookServiceImpl implements BookService{
    @Resource
    private BookRepository bookRepository;
    @Transactional
    @Override
    public void save(){
        try {
            Book book = new Book();
            book.setName("book");
            book.setAuthor("wang");
            book.setIsbn("666");
            bookRepository.save(book);
            int a = 1/0;
        }catch (Exception e){
            throw new RuntimeException("error");
        }
    }
}
public interface UserService {
    void save();
}
@Service
public class UserServiceImpl implements UserService{
    @Resource
    private UserRepository userRepository;
    @Resource
    private BookService bookService;
    @Transactional
    @Override
    public void save() {
        User user = new User();
        user.setName("wang");
        user.setHobby("pingpang");
        userRepository.save(user);
        bookService.save();
    }
}

针对于需要进行事务管理的方法,大家只要在方法上加入 @Transactional注释即可启用事务

  • 编写测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
public class QuickTransactionalApplicationTests {
	@Resource
	private UserService userService;
	@Test
	public void contextLoads(){
		userService.save();
	}
}

由于我们在BookServiceImpl的save方法中手动制造了一个异常,大家执行以下测试类,就会发现,数据没有插入,事务回滚成功。

下面介绍一下@Transactional注解的参数以及使用:

事物传播行为介绍:

  • @Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
  • @Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务
  • @Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
  • @Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常
  • @Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
  • @Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.

事物超时设置:

  • @Transactional(timeout=30) //默认是30秒

事务隔离级别:

  • @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
  • @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
  • @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
  • @Transactional(isolation = Isolation.SERIALIZABLE):串行化  MYSQL: 默认为REPEATABLE_READ级别  SQLSERVER: 默认为READ_COMMITTED

@Transactional注解中常用参数说明

注意的几点:

  1. @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
  2. 用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
  3. @Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
  4. @Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 元素的出现 开启 了事务行为。
  5. Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。

源码地址:gitee.com/wangGet/spring-boot-quick.git

老虎是个蛋蛋
粉丝 172
博文 31
码字总数 40085
作品 0
朝阳
高级程序员
私信 提问
加载中
请先登录后再评论。
spring boot 从0到1

demo地址 https://gitee.com/wangGet/spring-boot-quick Spring Boot快速入门(一):https://my.oschina.net/wangxincj/blog/807792 Spring Boot开发WEB页面(二):https://my.oschina.ne......

老虎是个蛋蛋
2018/12/28
166
0
Spring Boot入门系列(十三)如何实现事务

前面介绍了Spring Boot 中的整合Mybatis并实现增删改查。不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1657780.html。 Spring Boot 整合完Mybatis,有个...

章为忠
05/08
0
0
Spring Boot入门教程

Spring Boot (一) 基础搭建、兼容jar启动及war tomcat启动、集成Swagger2 API。 Spring Boot (二)集成Mybatis、Druid Spring Boot (三)集成spring security Spring Boot(四)通用CRU...

外星人et59
2018/06/26
0
0
Spring框架学习笔记(7)——Spring Boot 实现上传和下载

最近忙着都没时间写博客了,做了个项目,实现了下载功能,没用到上传,写这篇文章也是顺便参考学习了如何实现上传,上传和下载做一篇笔记吧 下载 主要有下面的两种方式: 通过ResponseEntit...

osc_s5ulls1u
04/16
6
0
十三的博文作品

Spring Boot 大型线上商城项目实战教程 SpringBoot + Mybatis + Thymeleaf 搭建美观实用的个人博客 23 个实验带你轻松玩转 Spring Boot Spring Boot 入门及前后端分离项目实践 从零开始搭建一...

我是13
2017/03/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java使用jsoup时绕过https证书验证

java 代码 增加一个工具类 在jsoup获取之前调用此方法 //your codeSSLHelper.init();Connection connect = Jsoup.connect(url).userAgent(USER_AGENT);connect.header("Accept","text/htm......

MeiJM
22分钟前
30
0
6 Message 消息提示框

1 element.js导入message import { Message } from 'element-ui'# 赋值给变量,便于this调用Vue.prototype.$message = Message 2 调用 this.$message.error('错误')类型有:success,w......

书阳
22分钟前
16
0
聊聊rocketmq-client-go的strategy

序 本文主要研究一下rocketmq-client-go的strategy AllocateStrategy rocketmq-client-go-v2.0.0/consumer/strategy.go type AllocateStrategy func(string, string, []*primitive.MessageQ......

go4it
49分钟前
21
0
BuildRun低代码开发教程八节 | 图表和仪表盘展示

课程说明 ▍ 1.1 课程实现功能 本课程为物联网应用平台设计一个仪表盘首页,包括以下内容: 卡片展示设备总数; 卡片展示网关总数; 卡片展示产品总数; 卡片展示产品分组总数; 图表展示各运...

BuildRun团队
53分钟前
23
0
JavaSE第03篇:Java基础语法之运算符和流程控制

本章将会延续JavaSE第02篇,详细讲解Java基础语法中的运算符和流程控制中的顺序结构、分支结构。 第一章:运算符 运算符,简而言之就是运算的符号。 我们通常所理解的运算一般和数学有关系,...

雷哒哒
56分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部