关于代码中事务的常用写法

在平常代码中,要保证功能的有效性和数据安全性,通常会对有关联的业务代码进行事务控制,常见的事务控制方法如下

1 事务控制的引入

在日常操作中,对于一些特定场景,需要保持数据安全和有效性,通过添加事务的控制,避免脏数据的产生,从而避免影响用户体验,以及整体项目的数据逻辑错误.

以常见的电商购物场景为例.

用户点击下单购买商品,其中涉及到几个关联操作.即用户余额扣减,商品数量减少,订单增加.上述三个操作彼此间是独立进行的,但是三个操作,要么都成功,即用户购买商品成功; 或者都失败,即用户购买商品失败(失败原因赞不说明,但是三张数据表中都没有新增数据)

所以,对于上述应用场景,需要使用事务来控制,整个业务的完成.保证数据的正确,从而减少脏数据以及系统bug的产生.

2 事务控制案例

1 环境准备

准备一个简单的SpringBoot项目环境.

1 application.yml文件
spring:
  datasource:
    name: test  #数据库名
    url: jdbc:mysql://localhost:3306/test #url
    username: root  #用户名
    password: root  #密码
2 pom.xml文件
 <dependency>
 <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.28</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.1.4</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
    </dependency>
3 启动类
@SpringBootApplication
public class DemoApplication {

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

}
4 Controller控制器
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;


    @GetMapping("/saveData")
    public String saveData() throws Exception {
        userService.saveEntity();
        return "新增成功";
    }

    @GetMapping("/saveData2")
    public String saveData2() throws Exception {
        userService.saveEntity2();
        return "新增成功";
    }

    @GetMapping("/saveData3")
    public String saveData3() throws Exception {
        userService.saveEntity3();
        return "新增成功";
    }

    @GetMapping("/saveData4")
    public String saveData4() throws Exception {
        userService.saveEntity4();
        return "新增成功";
    }
}
5 Service层

接口

public interface UserService {

    void saveEntity() throws Exception;

    void saveEntity2() throws Exception;

    void saveEntity3() throws Exception;

    void saveEntity4() throws Exception;

}

实现类

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserInfoDao userInfoDao;


    @Override
    public void saveEntity() throws Exception {
        userDao.saveUser();
        userInfoDao.saveUserInfo();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveEntity2() throws Exception {
        userDao.saveUser();
        userInfoDao.saveUserInfo();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveEntity3() throws Exception {
        //设置回滚点
        Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
        try {
            userDao.saveUser();
            userInfoDao.saveUserInfo();
        } catch (Exception e) {
            System.out.println("异常了=====" + e);
            //手工回滚异常
            TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
        }
    }


    @Autowired
    DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    TransactionDefinition transactionDefinition;

    @Override
    public void saveEntity4() throws Exception {

        //  手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager
                .getTransaction(transactionDefinition);

        try {
            userDao.saveUser();
            userInfoDao.saveUserInfo();
        } catch (Exception e) {
            e.printStackTrace();
            // 手动回滚事务
            dataSourceTransactionManager.rollback(transactionStatus);
        }
        // 手动提交事物
        dataSourceTransactionManager.commit(transactionStatus);//提交

    }
}
6 Dao层

接口

public interface UserDao {

    void saveUser();

}
public interface UserInfoDao {

    void saveUserInfo();

}

实现类

@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void saveUser() {
        String sql = "insert into user(id,name, age) values(?,?,?)";
        List<Object> sqlParamList = new ArrayList<Object>();
        sqlParamList.add("No-"+ new Random().nextInt(10));
        sqlParamList.add("杜甫"+new Random().nextInt(10));
        sqlParamList.add(20);
        jdbcTemplate.update(sql, sqlParamList.toArray(new Object[sqlParamList.size()]));
    }
}
@Repository
public class UserInfoDaoImpl implements UserInfoDao {


    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void saveUserInfo() {
        // 手动添加错误 isnert 打错成insertr
        String sql = "insertr into userinfo(id,name, age) values(?,?,?)";
        List<Object> sqlParamList = new ArrayList<Object>();
        sqlParamList.add("No-" + new Random().nextInt(10));
        sqlParamList.add("李白" + new Random().nextInt(10));
        sqlParamList.add(20);
        jdbcTemplate.update(sql, sqlParamList.toArray(new Object[sqlParamList.size()]));
    }

}
7 数据库脚本
CREATE TABLE `user` (
  `id` varchar(20) NOT NULL,
  `name` varchar(200) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `userinfo` (
  `id` varchar(20) NOT NULL,
  `name` varchar(200) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2 结果分析

启动项目

访问:

1 不加事务控制

localhost:8080/user/saveData

user表中插入数据,userinfo表中没有插入数据,查看程序,因sql语法报错

java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertr into userinfo(id,name, age) values('No-6','李白2',20)' at line 1
2 添加事务注释

localhost:8080/user/saveData2

user表中没有插入数据,userinfo表中没有插入数据,查看程序,因sql语法报错

java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertr into userinfo(id,name, age) values('No-3','李白6',20)' at line 1
3 手动添加事务

localhost:8080/user/saveData3

user表中没有插入数据,userinfo表中没有插入数据,没有抛出异常查看程序,因sql语法报错

异常了=====org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [insert into user(id,name, age) values(?,?,?)]; Duplicate entry 'No-9' for key 'PRIMARY'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'No-9' for key 'PRIMARY'
4 手动添加事务2

localhost:8080/user/saveData4

user表中没有插入数据,userinfo表中没有插入数据,查看程序,因sql语法报错

org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [insert into user(id,name, age) values(?,?,?)]; Duplicate entry 'No-9' for key 'PRIMARY'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'No-9' for key 'PRIMARY'
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值