JDBC下的事务

在这里,直接模拟一个账户表。我们在账户存钱,存钱的先后顺序会有一些逻辑处理,假设我们已经对数据库中插入了数据,但之后出现了异常,需要将存在账户中的数据回滚。在开始程序之前,新建一个 jdbcTransaction 包,具体如图7.4所示。

image 2024 03 31 21 39 38 020
Figure 1. 图7.4 程序结构

首先,需要新建 ACCOUNT 表,在表中加入一些数据,这些数据主要是用来和执行效果对比,SQL 如下所示。

CREATE TABLE ACCOUNT(
  ID INT(16) NOT NULL,
  MONEY DECIMAL(10,2),
  PRIMARY KEY(ID)
);
INSERT INTO ACCOUNT VALUE(1,999.99);
INSERT INTO ACCOUNT VALUE(2,999.99);
INSERT INTO ACCOUNT VALUE(3,999.99);

然后,针对表新建实体类,代码如下所示。

package com.springBoot.jdbcTransaction.entiry;
import java.math.BigDecimal;
public class Account {
   private int id;
   private BigDecimal money;
//set and get
      .
}

接着写 Mapper 接口,其功能主要是用来实现数据库表的更新操作。访问为 save 方法,这里的 SQL 直接写在注解里,没有另外写 XML。代码如下所示。

package com.springBoot.jdbcTransaction.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface AccountMapper {
   @Update("update account set money=money+1000 where id=2")
   public void save();
}

然后,在写完数据访问层的代码之后,在此基础上,写 AccountService 类,代码如下所示。

package com.springBoot.jdbcTransaction.service;
@Service
public class AccountService {
   @Autowired
   AccountMapper accountMapper;
   @Transactional
   public void save(){
      accountMapper.save();
      throw new RuntimeException("=====异常=====");
   }
}

上面的代码中,可以看到在 save 方法上有一个注解 @Transactional,其作用在前面已介绍,这个方法将会存在事务操作。在这个方法中,先对数据库进行更新操作,更新之后,模拟业务上出现业务异常,这个异常将会在上层业务中继续处理。

然后,开始写我们的业务控制层,代码如下所示。

package com.springBoot.jdbcTransaction.controller;

@RestController
public class AccountController {
   @Autowired
   AccountService accountService;
   @RequestMapping(value = "/save",method = RequestMethod.GET)
   public Object save(){
      try{
          accountService.save();
      }catch (Exception ex){
          return "异常了";
      }
      return "success";
   }
}

在上面的代码中,会进行数据的更新,同时会捕获底层出现的异常,异常捕获主要来源于 AccountService。最后,我们使用 Restful 测试的方式对事务进行测试,所以还需要一个启动类,启动类的代码如下所示。

package com.springBoot.jdbcTransaction;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
   public static void main(String[] args) {
      SpringApplication.run(Application.class, args);
   }
}

程序启动后,在页面上访问 http://localhost:8082/save?id=5&money=666.77 (地址栏默认省略“http://”)。执行效果如图7.5所示。

image 2024 03 31 21 47 34 544
Figure 2. 图7.5 执行效果

这时需要看数据的执行情况,如图7.6所示。

image 2024 03 31 21 48 18 269
Figure 3. 图7.6 数据库的执行情况