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

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
个人博客开源系统XBlog介绍和部署
XBlog是dotnet core平台下的个人博客开源系统,它只需要通过Copy的方式即可以部署到Linux和windows系统中;如果你有安全证书那只需要简单配置一下即可提供安全的Https服务。接下来主要介绍XBlog功能、部署和基础设置。 技术要点 基于dotnet core平台,可以运行在windows和linux系统上 完全基于BeetleX.FastHttpAp框架开发 前后端分离,完全脱离后端视图引擎;基于vuejs和webapi模式 混合HTTP和Websocket,当浏览器兼容Websocket的情况下请求会使用Websocket. 基于javascript前端Markdown,降低文章在服务端解释的损耗 支持HTTPS满足安全访问的需求 项目地址:https://github.com/IKende/XBlog 功能介绍 XBlog提供了博客的基础功能主要包括:文章管理,分类管理,评论管理,文件管理,系统资源监控和文章搜索功能. 首页预览 后台预览 设置 主要配置博客信息如Title,ElasticSearch服务地址,关于,JWT KEY和设置用户密码等。 部署 X...
-
下一篇
为什么修复每个 bug 后都要问这 3 个问题?
你是否曾经修复了一个 bug ,随后又发现了一个跟刚修复 bug 有关的 bug ,又或是修复 bug 的方式引起了另一个 bug ?当我修改 bug 时,我会问自己三个问题,以确保我已经仔细考虑了它的意义。每次你认为发现并修改了一个 bug 时,可以使用这些问题来提高生产力和代码质量。 这些问题背后的主要思想就是:每一个 bug 都是底层进程的一个不良表现。你必须处理这些症状,但如果你仅仅是处理这些外在症状,你就会有永远解决不完的问题。你应该找到产生 bug 的进程,并且修复这个进程。当你确定究竟发生了什么和发生这些的原因时,也许你就会明白产生 bug 的基础进程不是随机的,而是可控的。 在问这三个问题前,你需要克服面对 bug 的这种天生的抗拒,仔细分析 bug 。查看代码并解释出错的原因,从能观察到的现象开始,向后分析,不断地问为什么,直到你可以找到产生 bug 的模式。通常,你该跟同事一起做这件事, 因为解释你认为会发生的事情,将迫使你面对一些假设——这些程序是做什么的。 “它溢出了,因为下标J越界了。” “为什么?” “J 是 10,但数组最大下标为 9。” “为什么?” “...
相关文章
文章评论
共有0条评论来说两句吧...