数据库事务

概述

事务是逻辑上的一组操作,或者说一个独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。

事务处理

数据一旦提交,就不可回滚。数据意味着提交的情况:

  • 当一个连接对象被创建时,默认情况下时自动提交事务:

    • DDL 操作一旦执行成功,就会自动提交。connection.setAutoCommit(false); 对 DDL 无效。
    • DML 操作默认情况下一旦执行成功,就会自动提交。connection.setAutoCommit(false); 对 DML 取消自动提交。
  • 当一个连接被关闭时,事务就会自动的提交:
    • 如果有多个操作,每个操作使用的是自己单独的连接,则无法保证事务,所以同一个事务的多个操作必须在同一个连接下。

JDBC 中让多条 SQL 语句作为一个事务执行:

  • 使用 connection.setAutoCommit(false); ,取消自动提交事务;
  • 在所有 SQL 语句都成功执行后,调用 connection.commit();,提交事务;
  • 在出现异常是,调用 connection.rollback();,回滚事务。

注意:若此时 Connection 没有被关闭,还可能被重复使用,则需要恢复其自动提交状态 connection.setAutoCommit(true);。尤其是在使用数据库连接池技术时,执行 close() 方法前,建议恢复自动提交状态。

package cn.parzulpan.jdbc.ch06;

import cn.parzulpan.jdbc.util.JDBCUtils;
import org.junit.Test; import java.sql.Connection;
import java.sql.SQLException; /**
* @Author : parzulpan
* @Time : 2020-12-01
* @Desc : 事务问题,AA 用户 向 BB 用户转账 100
*/ public class TransactionTest { // 出现事务问题
@Test
public void test1() {
String sql1 = "update user_table set balance = balance - 100 where user = ?";
JDBCUtils.update(sql1, "AA"); // 模拟网络异常
System.out.println(10 / 0); String sql2 = "update user_table set balance = balance + 100 where user = ?";
JDBCUtils.update(sql2, "BB");
} // 考虑事务问题
@Test
public void test2() {
Connection connection = null;
try {
connection = JDBCUtils.getConnection();
// 取消事务自动提交
connection.setAutoCommit(false); String sql1 = "update user_table set balance = balance - 100 where user = ?";
JDBCUtils.update(connection, sql1, "AA"); // 模拟网络异常
System.out.println(10 / 0); String sql2 = "update user_table set balance = balance + 100 where user = ?";
JDBCUtils.update(connection, sql2, "BB"); // 若没有异常,则提交事务
connection.commit();
} catch (Exception e) {
e.printStackTrace();
try {
// 如有异常,则回滚事务
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} finally {
try {
// 恢复每次 DML 操作的自动提交功能,针对于数据库连接池时
connection.setAutoCommit(true);
} catch (Exception e) {
e.printStackTrace();
} // 关闭连接
JDBCUtils.closeResource(connection, null, null);
}
}
}

事务的特性

事务的 ACID 属性

  • 原子性(Atomicity):指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  • 一致性(Consistency):指数据库总是从一个一致性状态切换到另一个一致性状态。
  • 隔离性(Isolation):指并发执行的一个事务之间不能互相干扰;
  • 持久性(Durability):指事务一旦提交,它对数据库的改变是永久性的。

数据库的并发问题

  • 对于同时运行的多个事务,当这些事务访问数据库的相同数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:

    • 脏读:对于事务 T1 和 T2,T1 读取了已经被 T2 更新但还没提交 的数据,若 T2 回滚,T1 读取的内容就是临时且无效的。
    • 不可重复读:对于事务 T1 和 T2,T1 读取了一个数据,然后 T2 更新了这个数据,之后 T1 再次读取这个数据,数据值改变。
    • 幻读:对于事务 T1 和 T2,T1 读取了表的数据,然后 T2 向表增加了一些数据,之后 T1 再次读取这个表,表就会多处几行。
  • 数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题,这就是数据库事务的隔离性。

隔离级别越高,数据的一致性就越好,但并发行就越弱。

四种事务隔离级别

  • TRANSACTION_READ_UNCOMMITTED 读未提交:允许事务读取未被其他事务提交的变更,出现 脏读、不可重复读、幻读等问题。
  • TRANSACTION_READ_COMMITTED 读已提交:只允许事务读取已经被其他事务提交的变更,避免 脏读问题,出现 不可重复读、幻读等问题。这是 Oracle 默认的事务隔离级别
  • TRANSACTION_REPEATABLE_READ 可重复读:确保在同一个事务中多次读取同样记录的结果是一致的,避免 脏读、不可重复读问题,出现 幻读等问题。这是 MySQL 默认的事务隔离级别。
  • TRANSACTION_SERIALIZABLE 串行化:确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表进行增删改操作,避免上面所有问题。

设置事务隔离级别

  • 每个数据库连接都有一个全局变量 @@tx_isolation,表示当前的事务隔离级别。

  • 查看当前的事务隔离级别:

    select @@tx_isolation;
  • 设置当前数据库连接的隔离级别:

    set transaction isolation level read committed;
  • 设置数据库全局的隔离级别:

    set global transaction isolation level read committed;
  • 创建 MySQL 用户,并授予权限:

    create user parzulpan identified by 'xxx';
    
    # 授予网络方式登陆的用户,对所有库所有表的全部权限,并设置密码
    grant all privileges on *.* to parzulpan@'%' identified by 'xxx'; # 授予本地方式登陆的用户,对 test 库所有表的增删改查权限,并设置密码
    grant select, insert, delete, update on test.* to parzulpan@localhost identified by 'xxx';
package cn.parzulpan.jdbc.ch06;

import cn.parzulpan.jdbc.bean.UserTable;
import cn.parzulpan.jdbc.util.JDBCUtils;
import org.junit.Test; import java.sql.Connection; /**
* @Author : parzulpan
* @Time : 2020-12-01
* @Desc : 事务隔离级别
*/ public class TransactionTest1 { // 模拟 事务隔离级别
@Test
public void test1() throws Exception{
Connection connection = JDBCUtils.getConnection(); // TRANSACTION_READ_UNCOMMITTED 读未提交数据
// 允许事务读取未被其他事务提交的变更,出现 脏读、不可重复读、幻读等问题
// 先运行 test2(),然后运行 test1(),发现数据已更改,但是10秒后,再然后运行 test1(),发现数据已恢复
connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); // TRANSACTION_READ_COMMITTED 读已提交数据
// 只允许事务读取已经被其他事务提交的变更,避免 脏读问题,出现 不可重复读、幻读等问题
// 先运行 test2(),然后运行 test1(),发现数据未更改,10秒后,再然后运行 test1(),发现数据依然未更改
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); // TRANSACTION_REPEATABLE_READ 可重复读
// 确保在同一个事务中多次读取同样记录的结果是一致的,避免 脏读、不可重复读问题,出现 幻读等问题
// 打开 test2() 自动事务提交,先运行 test2(),然后运行 test1(),发现数据未更改,10秒后,再然后运行 test1(),发现数据依然未更改
connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); System.out.println(connection.getTransactionIsolation()); connection.setAutoCommit(false); String sql = "select user, password, balance from user_table where user = ?";
JDBCUtils jdbcUtils = new JDBCUtils();
UserTable userTable = jdbcUtils.getQuery(connection, UserTable.class, sql, "CC");
System.out.println(userTable);
} // 模拟 事务隔离级别
@Test
public void test2() throws Exception{
Connection connection = JDBCUtils.getConnection(); System.out.println(connection.getTransactionIsolation()); connection.setAutoCommit(false); String sql = "update user_table set balance = ? where user = ?";
JDBCUtils jdbcUtils = new JDBCUtils();
jdbcUtils.update(connection, sql, 5000, "CC"); Thread.sleep(5000);
System.out.println("修改结束"); // 注意此时事务并未提交
}
}

练习和总结

【JDBC核心】数据库事务的更多相关文章

  1. JDBC(3)-数据库事务

    一.环境搭建(复习) 首先建立lib目录然后要把对应的jar包导进来 然后就是jdbc.properties文件 user=root password=123456 url=jdbc:mysql:// ...

  2. 【Spring】Spring的事务管理 - 1、Spring事务管理概述(数据库事务、Spring事务管理的核心接口)

    Spring事务管理概述 文章目录 Spring事务管理概述 数据库事务 什么是Spring的事务管理? Spring对事务管理的支持 Spring事务管理的核心接口 Platform Transac ...

  3. 使用JDBC进行数据库的事务操作(2)

    本篇将讲诉如何使用JDBC进行数据库有关事务的操作.在上一篇博客中已经介绍了事务的概念,和在MySQL命令行窗口进行开启事务,提交事务以及回滚事务的操作. 似乎事务和批处理都可以一次同时执行多条SQL ...

  4. 使用JDBC进行数据库的事务操作(1)

    本篇讲述数据库中非常重要的事务概念和如何使用MySQL命令行窗口来进行数据库的事务操作.下一篇会讲述如何使用JDBC进行数据库的事务操作. 事务是指数据库中的一组逻辑操作,这个操作的特点就是在该组逻辑 ...

  5. JDBC基础学习(四)—数据库事务

    一.事务基本认识 1.事务的概述      为了保证数据库中数据的一致性,数据的操作应当是离散的成组的逻辑单元.当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败,整个事务应当全部视 ...

  6. 数据库事务的四大特性以及4种事务的隔离级别-以及对应的5种JDBC事务隔离级别

    本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务 ...

  7. JDBC事务和数据库事务嵌套的讨论 .

    首先必须执行con.setAutoCommit(false)方法,将JDBC事务设置为手动提交,否则手动提交con.commit()无效,手动回滚con.rollback()引发SQLExceptio ...

  8. Jdbc执行存储过程报数据库事务无法执行的异常

    Jdbc执行存储过程报数据库事务无法执行的异常 环境: Eclipse+Jdk1.7+spring-jdbc-3.0.7+同版本的jdbctemplate+Sqlserver 2012 问题: 一个小 ...

  9. Java操作数据库——在JDBC里使用事务

    Java操作数据库——在JDBC里使用事务 摘要:本文主要学习了如何在JDBC里使用事务. 使用Connection的事务控制方法 当JDBC程序向数据库获得一个Connection对象时,默认情况下 ...

随机推荐

  1. 学习笔记:插头DP

    基于连通性的状压DP问题. 一般是给你一个网格,有一些连通性的限制. 例题 插头DP模板 链接 题意:网格图,去掉一些点,求哈密顿回路方案数. 一般按格递推(从上到下,从左到右). 每个格子要从四个方 ...

  2. AcWing 339 .圆形数字

    大型补档计划 题目链接 设 \(f[i][j]\) 表示二进制下,数字有 \(i\) 位, \(0\) 的个数 - \(1\) 的个数 \(=\) \(j\) 的方案数 \(f[0][0] = 1;\ ...

  3. 操作系统精髓与设计原理(九)——I/O管理和磁盘调度

    文章目录 I/O设备 I/O功能组织 直接存储器访问 操作系统设计问题 设计目标 IO功能的逻辑结构 I/O缓冲 单缓冲 双缓冲 循环缓冲 缓冲的作用 磁盘调度 磁盘性能参数 磁盘调度策略 先进先出 ...

  4. [日常摸鱼]loj6000「网络流 24 题」搭配飞行员

    题面 应该是二分图匹配,不过我写的是网络最大流. dinic求二分图最大匹配:加个源点和汇点,源点连向二分图的一边所有点,二分图的另一边所有点连向汇点,很明显这样得到的最大流就是这个二分图的最大匹配. ...

  5. Numpy的学习1-创建数据基础

    1 import numpy as np 2 3 array = np.array([[1,2,3],[4,5,6]]) 4 5 print(array) 6 print('number of dim ...

  6. DVWA-文件包含-目录遍历学习笔记

    参考文献资料: https://www.cnblogs.com/s0ky1xd/p/5823685.html https://www.cnblogs.com/yuzly/p/10799486.html ...

  7. SpringBoot从入门到精通教程(三)

    在上一篇中,我们已经讲了,SpringBoot 如何构建项目,和SpringBoot的HelloWorld, 那这一节我们继续讲 Thymeleaf Thymeleaf 官网: Thymeleaf T ...

  8. ThreadX——IPC应用之消息队列

    作者:zzssdd2 E-mail:zzssdd2@foxmail.com 一.应用简介 消息队列是RTOS中常用的一种数据通信方式,常用于任务与任务之间或是中断与任务之间的数据传递.在裸机系统中我们 ...

  9. Winform程序及dll打包成一个可执行的exe

    使用场景 通常开发的Winform程序,引用了其他类库后,在输出目录下都会产生很多DLL文件,exe执行时必须依赖这些DLL.想要Winform程序只有一个可执行exe文件,又不想打包成安装包,就可以 ...

  10. Core3.0路由配置

    前言 MSDN文档,对ASP.NETCore中的路由完整的介绍 https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/routing?vi ...