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条评论来说两句吧...

 
			
 
				 
				 
				 
				 
				 
				 
				



 微信收款码
微信收款码 支付宝收款码
支付宝收款码