第10章—开启事务

Posted 质行

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第10章—开启事务相关的知识,希望对你有一定的参考价值。

spring boot 系列学习记录:http://www.cnblogs.com/jinxiaohang/p/8111057.html

码云源码地址:https://gitee.com/jinxiaohang/springboot

  此前,我们主要通过XML配置Spring来托管事务。在SpringBoot则非常简单,只需在业务层添加事务注解(@Transactional )即可快速开启事务。虽然事务很简单,但对于数据方面是需要谨慎对待的,识别常见坑点对我们开发有帮助。

  推荐做法:在业务层统一抛出异常,然后在控制层统一处理。

1. 引入依赖

如果是新建项目的,可以在这页添加依赖,如是原有项目可直接编写。

<?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.xiaohang</groupId>
    <artifactId>springboot-transactional</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot-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-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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:
    url: jdbc:mysql://localhost:3306/test?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

 

三、编写各层代码

  • 实体层
import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;
import java.math.BigDecimal;

@Data
@Entity
public class UserAccount {

    @Id
    private String userId;

    private String userName;

    private BigDecimal balance;
}

 

  • dao层
import com.xiaohang.springboottransactional.entity.UserAccount;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserAccountRepository extends JpaRepository<UserAccount,String>{
}

 

  • service层
public interface UserAccountService {
    /**
     * 转账
     */
    public UserAccount change(String userId,BigDecimal bigDecimal,String userId2) throws Exception;
}

 

  • service实现层
import com.xiaohang.springboottransactional.entity.UserAccount;
import com.xiaohang.springboottransactional.repository.UserAccountRepository;
import com.xiaohang.springboottransactional.service.UserAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

@Service
public class UserAccountServiceImpl implements UserAccountService {

    @Autowired
    private UserAccountRepository userAccountRepository;

    @Transactional
    @Override
    public UserAccount change(String userId, BigDecimal bigDecimal, String userId2) throws Exception{
        UserAccount userAccount = userAccountRepository.findOne(userId);
        UserAccount userAccount2 = userAccountRepository.findOne(userId2);
        userAccount.setBalance(userAccount.getBalance().add(bigDecimal));
        userAccount2.setBalance(userAccount2.getBalance().subtract(bigDecimal));
        userAccountRepository.save(userAccount);
        int n=1/0;//throw new Exception();//假设发生故障
        userAccountRepository.save(userAccount2);
        return userAccountRepository.findOne(userId);

    }
}

 

  • 测试层
import com.xiaohang.springboottransactional.service.UserAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.math.BigDecimal;


@RunWith(SpringRunner.class)
@SpringBootTest
public class UserAccountServiceImplTest {

    @Autowired
    private UserAccountService userAccountService;

    @Test
    public void change() throws Exception {
        try {
            System.out.println(userAccountService.change("1",new BigDecimal("100"),"2"));
        }catch (Exception e){
            System.out.println("抛出异常");
        }
    }

}

 

三、测试


 原始数据:

 

 


 不开启事务,不抛出异常时:

 

 


 不开启事务,抛出异常时(转账时发生错误,钱扣完,但是对方钱未到账;或者钱到帐了,但是钱未扣。)

 

 


 先恢复数据:

 开启事务,抛出异常时。

 

以上是关于第10章—开启事务的主要内容,如果未能解决你的问题,请参考以下文章

数据库第10章作业——数据库恢复技术

数据库第10章作业——数据库恢复技术

片段事务中的实例化错误

mysql

分布式事务系列第二篇,回顾 Jdbc 事务

Java开发工程师(Web方向) - 03.数据库开发 - 第4章.事务