Java千万级数据插入开启事务_SpringBoot系列:10、数据库事务

1、Spring事务

1.1 Spring事务介绍

事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性。

1.1.1 事务的四大特性(ACID)

  • 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用
  • 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏
  • 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
  • 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中

1.1.2 Spring支持的事务类型

  • 编程式事务(编码式事务)
  • 指的是将事务管理代码嵌入业务方法中来控制事务的提交和回滚,必须在每个业务操作中包含额外的事务管理代码。
  • 声明式事务
  • 指的是将事务管理代码从业务方法中分离出来,以声明的方式来实现事务的管理。

1.1.3 Spring的事务管理器

  • DataSourceTransactionManager:使用Spring JDBC或iBatis进行持久化数据时使用
  • JdoTransactionManager:使用Hibernate持久化数据时使用
  • JpaTransactionManager:当持久化机制时Jdo时使用
  • HibernaTransactionManager:使用一个JTA实现来管理事务,在一个事务跨多个资源时必须使用

1.2 Spring声明式事务

比较常用的就是使用@Transactional注解在类或者方法中表明该类或者方法需要事务支持。

1.3 Spring注解事务行为

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。

1.3.1 传播行为

传播行为 含义 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务;如果已经存在一个事务,就加入这个事务 PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行 PROPAGATION_MANDATORY 使用当前的事务,如果当前米有事务,就抛出异常 PROPAGATIONREQUIREDNEW 新建事务,如果当前存在事务,就把当前事务挂起 PROPAGATIONNOTSUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,就抛出异常 PROPAGATION_NESTED 如果当前存在事务,就在嵌套事务内执行,如果当前没有事务,就执行与PROPAGATION_REQUIRED类似的操作 1.3.2 隔离级别

隔离级别

场景 脏读(Dirty Read) 一个事务读取了另一个事务改写但未提交的数据,如果改后被回滚了,那么第一个事务获取的数据是无效 不可重复读(Nonrepeatable Read) 一个事务执行相同的查询俩次或者俩次以上,但每次都得到不同的数据,因为另一个事务在俩次查询期间更新了数据 幻读(Phantom Read) 与不可重复读类似,事务T1读取了几行数据,T2事务插入了一些数据。然后之后的查询中T1会多了原本不存在的数据 2、SpringBoot事务的使用

2.1 类级别事务

@Transactional注解在类上,表示此类的所有public方法都是开启事务

2.2 方法级别事务

@Transactional注解在方法上,如果类和方法同时使用了@Transactional注解,就使用方法级别注解覆盖类级别注解

2.3 @Transactional源码分析

package org.springframework.transaction.annotation;@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD})@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)@java.lang.annotation.Inherited@java.lang.annotation.Documentedpublic @interface Transactional { // 通过bean name指定事务管理器 @org.springframework.core.annotation.AliasFor("transactionManager") java.lang.String value() default "";  // 同value属性 @org.springframework.core.annotation.AliasFor("value") java.lang.String transactionManager() default ""; // 指定传播行为 org.springframework.transaction.annotation.Propagation propagation() default org.springframework.transaction.annotation.Propagation.REQUIRED; // 指定隔离级别 org.springframework.transaction.annotation.Isolation isolation() default org.springframework.transaction.annotation.Isolation.DEFAULT; // 超时时间,单位秒 int timeout() default -1; // 是否是只读事务 boolean readOnly() default false; // 方法上发生指定异常时回滚,默认是所有异常都回滚 java.lang.Class extends java.lang.Throwable>[] rollbackFor() default {}; // 方法上发生指定异常名时回滚,默认是所有异常都回滚 java.lang.String[] rollbackForClassName() default {}; // 方法在发生指定异常时不回滚,默认所有异常都回滚 java.lang.Class extends java.lang.Throwable>[] noRollbackFor() default {}; // 方法在发生指定异常名称时不回滚,默认是所有异常都回滚 java.lang.String[] noRollbackForClassName() default {};}

3、测试数据库事务

代码清单3-1 SQL脚本

DROP TABLE IF EXISTS `t_user`;CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID', `name` varchar(10) DEFAULT '' COMMENT '用户姓名', `password` varchar(32) DEFAULT '' COMMENT '密码', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;INSERT INTO `t_user` VALUES (1, '小H', '123456');INSERT INTO `t_user` VALUES (2, '萧炎', '123456');

代码清单3-2 用户实体类

public class User { // 主键 private String id; // 用户名 private String name; // 密码 private String password; //省略getter、setter、toString方法}

代码清单3-3 MyBatis接口文件

@Mapperpublic interface UserDao { List findAll(); Long save(User user);}

代码清单3-4 用户映射文件

<?xml version="1.0" encoding="UTF-8"?> id, name, password  SELECT  FROM t_user  insert into t_user(name, password) value(#{name}, #{password}) 

代码清单3-5 用户服务接口及实现类

public interface UserService { List findAll(); Long save(User user);}@Servicepublic class UserServiceImpl implements UserService { @Autowired UserDao userDao; /** * 开启事务,采用读写提交的隔离级别,超时时间设置为1s * @return */ @Override @Transactional(isolation = Isolation.READ_COMMITTED, timeout = 1) public List findAll() { return userDao.findAll(); } /** * 开启事务,采用读写提交的隔离级别,超时时间设置为1s * @return * */ @Override @Transactional(isolation = Isolation.READ_COMMITTED, timeout = 1) public Long save(User user) { return userDao.save(user); }}

代码清单3-6 controller测试数据库事务

@RestControllerpublic class UserController { @Autowired private UserService userService; @RequestMapping(value = "/users") public List findAll() { return userService.findAll(); } @RequestMapping(value = "/add") public List save(String name, String password) { User user = new User(); user.setName(name); user.setPassword(password); Long userId = userService.save(user); return userService.findAll(); }}

代码清单3-7 配置文件

spring: datasource: url: jdbc:mysql://172.16.6.31:3306/test username: root password: 123456 tomcat: max-idle: 10 max-active: 50 max-wait: 10000 initial-size: 5 driver-class-name: com.mysql.jdbc.Driverlogging: level: root: debug org: springframwwork: debug org: mybatis: debugmybatis: mapper-locations: classpath*:/mapper/*Mapper.xml type-aliases-package: com.xiaoh.springboot.transaction.domain

代码清单 3-8 启动类

@SpringBootApplication@MapperScan(value = "com.xiaoh.springboot.transaction.dao")public class SpringbootTransactionApplication {  public static void main(String[] args) { SpringApplication.run(SpringbootTransactionApplication.class, args); } }

启动项目,在浏览器中输入:http://localhost:8080/add?name=萧力&password=123456 ,可以看到控制台打印的日志:

282e0ba5-1113-eb11-8da9-e4434bdf6706.png

从日志中可以看到Spring获取了数据库连接以及修改了隔离级别,然后在执行SQL,在最后会自动地关闭和提交数据库事务,Spring会把标注了@Transactional的方法的代码织入约定的事务流程中。

本文由博客一文多发平台 https://openwrite.cn?from=article_bottom 发布!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值