Spring之路(37)–在原生JDBC上使用事务

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 本文目录1. 概述2. 不使用事务3. 使用事务4. 默认情况

1. 概述

Spring事务是对原生事务的封装,我们还是需要了解如果直接使用JDBC的话,如何实现事务。


我们将向blog表插入两条数据(两次更新操作)定义为一个原子性操作,所以我们是期望这两个操作能同时成功、或者同时失败的。


2. 不使用事务

如果不使用事务,有可能会发生一个操作成功、另一个操作失败的情况,所以我们预期的原子性操作不成立。代码如下,可以看出因为执行过程中出现异常,导致最终只插入了一条数据,数据的完整性保护失败。

package org.maoge.jdbctran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
 * 原生JDBC事务使用实例
 */
public class JdbcTransactionDemo {
  public static void main(String[] args) {
    actionWithoutTransaction();
  }
  /**
   * 未使用事务
   */
  public static void actionWithoutTransaction() {
    String driver = "com.mysql.jdbc.Driver";
    String url = "jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8";
    String username = "root";
    String password = "Easy@0122";
    Connection conn = null;
    try {
      Class.forName(driver);
      conn = DriverManager.getConnection(url, username, password);
      String sql = "insert into blog(author,content,title)values(1,2,3)";
      Statement stmt = conn.createStatement();
      stmt.execute(sql);// 执行成功
      int temp = 1 / 0;// 模拟抛出异常
      stmt.execute(sql);// 未执行
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (conn != null) {
        try {
          conn.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
  }
}

3. 使用事务

如果使用事务的话,示例如下:

package org.maoge.jdbctran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
 * 原生JDBC事务使用实例
 */
public class JdbcTransactionDemo {
  public static void main(String[] args) {
    actionWithTransaction();
  }
  /**
   * 使用事务
   */
  public static void actionWithTransaction() {
    String driver = "com.mysql.jdbc.Driver";
    String url = "jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8";
    String username = "root";
    String password = "Easy@0122";
    Connection conn = null;
    try {
      Class.forName(driver);
      conn = DriverManager.getConnection(url, username, password);
      conn.setAutoCommit(false);// 定义事务的起点
      String sql = "insert into blog(author,content,title)values(1,2,3)";
      Statement stmt = conn.createStatement();
      stmt.execute(sql);// 没问题
      int temp = 1 / 0;// 模拟抛出异常,导致回滚,所以上面的执行也回滚了
      stmt.execute(sql);// 未执行
      conn.commit();// 如果全部执行成功,则提交事务
    } catch (Exception e) {
      try {
        conn.rollback();// 如果出现异常则回滚
      } catch (SQLException ex) {
        ex.printStackTrace();
      }
      e.printStackTrace();
    } finally {
      if (conn != null) {
        try {
          conn.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
  }
}

分析上面的代码,就是我们在开始一个原子性操作之前(可能包含若干对数据库的操作),先开启事务,然后等几个操作都执行后再提交事务,此时对数据库的修改才生效;如果这中间发生异常,则执行回滚,则这些操作一个都不会生效。


从上面的示例中可以发现,几乎很多地方都是跟业务逻辑无关的代码,都是模板性质的代码,遵循如下结构:


try{

//开始事务

//执行具体操作

//提交事务

}catch(Exception e){

//回滚事务

//处理异常

}finally{

//释放资源

}

1

2

3

4

5

6

7

8

9

10

其中真正有意义的,只有具体操作部分,其他都是雷同的,所以可以封装起来。


4. 默认情况

那么如果不显示的指定conn.setAutoCommit(false);,是什么情况呢。我们尝试下,可见默认情况下事务是自动提交的,也就是执行一个sql就自动提交事务了,所以默认情况下执行sql后更新马上就持久化到数据库了。

package org.maoge.jdbctran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
 * 原生JDBC事务使用实例
 */
public class JdbcTransactionDemo {
  public static void main(String[] args) {
    testAutoCommit();
  }
  /**
   * 使用事务
   */
  public static void testAutoCommit() {
    String driver = "com.mysql.jdbc.Driver";
    String url = "jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8";
    String username = "root";
    String password = "Easy@0122";
    Connection conn = null;
    try {
      Class.forName(driver);
      conn = DriverManager.getConnection(url, username, password);
      System.out.println(conn.getAutoCommit());//输出true
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (conn != null) {
        try {
          conn.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
  }
}
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
50 9
|
2月前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
127 13
|
6月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
2月前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
75 2
Spring高手之路26——全方位掌握事务监听器
|
7月前
|
Java 关系型数据库 MySQL
Spring 事务失效场景总结
Spring 事务失效场景总结
82 4
|
2月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
3月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
82 1
Spring高手之路24——事务类型及传播行为实战指南
|
3月前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
109 1
|
3月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
117 3
|
5月前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务