1 数据库事务:Transaction

1.1 定义

  • 若干SQL语句构成的一个操作序列
  • 要么全部执行成功
  • 要么全部执行不成功

1.2 数据库事务具有ACID特性:

  • Atomicity:原子性

    一个事务虽有若干SQL语句构成,但它本身是一个原子操作,要么全部成功,要么全部失败

  • Consistency:一致性

    一个事务在开始前或结束之后,数据库的数据是完整的,不存在冲突和数据不一致的情况

  • Isolation:隔离型

    多个事务并发执行的时候,事务之间是隔离的,一个事务不应该影响其他事务运行的结果

  • Durability:持久性

    一个事务一旦成功完成,这个事务对数据库的更改会持久的保留在数据库中,并且不会被回滚。

1.3 为什么需要数据库事务?

例子:新建accounts表。

  1. CREATE table accounts (id int not null auto_increment, name varchar(10), balance DECIMAL(5,2) ,PRIMARY KEY(id)) ENGINE=INNODB DEFAULT charset=utf8;
  2. INSERT INTO accounts(name,balance) VALUES ("小明",550.00),("小红",120.00),("小军",870.60),("小白",120.00),("小兵",199.01);

转账操作,把100元从小明的账户转给小红。

  1. update accounts set balance = balance - 100 where id = 1;
  2. update accounts set balance = balance + 100 where id = 2;
情况一:如果这两条语句执行成功,小明的账户减少100,变为450元,小红的账号增加100,变为220元。

情况二:但如果在执行万第一条update语句后,由于各种原因,第二条update没有执行,会出现什么结果呢?
小明的钱已经扣了,小红的钱却未加上,这个时候应用逻辑出现了不一致的情况。

事务的作用:使用数据库事务可以保证多个SQL语句全部执行或全部取消。转账结果只有2种:

1.小明的钱成功转给了小红

2.小明的钱没有成功转给小红,退回小明账户。小明和小红的钱保持不变。

1.4 事务隔离级别

事务隔离是由数据库允许多个连接同时执行事务引起的。在Java程序中,当一个线程操作一个数据库连接的时候,另一个线程可能也在通过一个数据库连接更新数据。他们之间就会遇到隔离级别的问题。

事务隔离会遇到3个问题:

  • 1.脏读 Dirty Read
  • 2.非重复复读 Non Repeatable Read
  • 3.幻读 Phantom

1.4.1 Dirty Read 脏读:B读到了A未提交成功的数据Bob

  1. -- 事务A
  2. update students set name = 'Bob' where id = 1;
  3. rollback;
  4. -- 事务B:
  5. select * from students where id = 1;
  6. commit;

事务A修改了修改了一个数据,但还没有提交。这个时候,事务B读取了A没有提交的更新结果,如果事务A回滚,事务B读到的就是脏数据。

1.4.2 Non Repeatable Read 非重复读:在事务B中,2次select查询得到的结果不一致,这是因为事务A在2次select之间修改了数据,并且进行了提交。

而我们在同一个事务中,对于同样的select语句,希望返回同样的结果。这里出现的结果不一致的情况,就是Non Repeatable Read。

  1. -- 事务A
  2. update students set name='Bob' where id = 1;
  3. commit;
  4. -- 事务2
  5. select * from students where id = 1; -- 小明
  6. select * from students where id = 1; -- Bob

1.4.3 Phantom Read:幻读

在事务B中两次select条件为id=99的记录都是空,仿佛id=99的记录不存在。但实际上,事务A已经insert了一条id为99的记录。

当事务B第三次操作id=99的记录,就会多了一条记录。

  1. -- 事务A
  2. insert into students values(99, 1,'Bob', 'M');
  3. commit;
  4. -- 事务B
  5. select * from students where id = 99; --empty
  6. select * from students where id = 99; --empty
  7. update students set name 'Alice' where id = 99;
  8. commit;
  9. select * from students where id = 99; --Alice

1.4.4 数据库隔离级别:为了避免这三种问题,数据库定义了数据库隔离级别

isolation level Dirty Read Non Repeatable Read Phantom Read
Read Uncommitted 会出现 会出现 会出现
Read Committed 会出现 会出现
Repeatable Read 会出现
Serializable

但是隔离级别越高,数据运行的时候,要加的锁就越多,能够同时并发执行的事务就越少,所以要选择一个合适的隔离级别。

2 JDBC事务代码

  1. conn = openConnection();
  2. try{
  3. conn.setAutoCommit(false); //开始一个事务
  4. //执行多条SQL语句
  5. insert(); update(); delete();
  6. conn.commit(); //提交一个事务
  7. }catch(Exception e){
  8. conn.rollback(); //出现异常,就回滚这个事务
  9. }finally{
  10. conn.setAutoCommit(true); //恢复数据库原来的事务模式,即结束事务
  11. conn.close(); //关闭连接
  12. }
  1. package com.feiyangedu.sample.pop3;
  2. import java.sql.*;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. public class JdbcTx {
  6. static final String JDBC_URL = "jdbc:mysql://localhost:13306/test0828?characterEncoding=utf8&useSSL=false&serverTimeZone=UTC";
  7. static final String JDBC_USER = "root";
  8. static final String JDBC_PASSWORD = "123456";
  9. public static void main(String[] args) throws SQLException{
  10. List<Student> students = getAllStudents();
  11. for(Student student:students){
  12. System.out.println(student);
  13. }
  14. Connection conn = null;
  15. try{
  16. conn = getConnection();
  17. conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
  18. conn.setAutoCommit(false);
  19. updateName(conn, students.get(0).id, "Bob");
  20. updateName(conn, students.get(1).id, "Alice");
  21. conn.commit();
  22. System.out.println("commit ok");
  23. }catch (Exception e){
  24. e.printStackTrace();
  25. conn.rollback();
  26. }finally {
  27. if(conn != null){
  28. try{
  29. conn.setAutoCommit(true);
  30. conn.close();
  31. }catch (SQLException e){
  32. System.err.println(e);
  33. }
  34. }
  35. }
  36. System.out.println("第一次事务结束后");
  37. students = getAllStudents();
  38. for(Student student:students){
  39. System.out.println(student);
  40. }
  41. try{
  42. conn = getConnection();
  43. conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
  44. conn.setAutoCommit(false);
  45. updateName(conn, students.get(0).id,"张三");
  46. updateName(conn, students.get(1).id,"李四");
  47. throw new RuntimeException("第二次事务出错");
  48. }catch (Exception e){
  49. conn.rollback();
  50. }finally {
  51. if(conn != null){
  52. try{
  53. conn.setAutoCommit(true);
  54. conn.close();
  55. }catch (Exception e){
  56. System.err.println(e);
  57. }
  58. }
  59. }
  60. System.out.println("第二次事务结束");
  61. students = getAllStudents();
  62. for(Student student:students){
  63. System.out.println(student);
  64. }
  65. }
  66. static void updateName(Connection conn, long id, String name) throws SQLException{
  67. try(PreparedStatement ps = conn.prepareStatement("update students set name=? where id=?")){
  68. ps.setObject(1, name);
  69. ps.setObject(2, id);
  70. ps.executeUpdate();
  71. }
  72. }
  73. static List<Student> getAllStudents() throws SQLException{
  74. try(Connection conn = getConnection()){
  75. try(PreparedStatement ps = conn.prepareStatement("select * from students")){
  76. ResultSet rs = ps.executeQuery();
  77. List<Student> list = new ArrayList<>();
  78. while(rs.next()){
  79. long id = rs.getLong("id");
  80. long classId = rs.getLong("class_id");
  81. String name = rs.getString("name");
  82. String gender = rs.getString("gender");
  83. list.add(new Student(id,classId,name,gender));
  84. }
  85. return list;
  86. }
  87. }
  88. }
  89. static Connection getConnection() throws SQLException {
  90. return DriverManager.getConnection(JDBC_URL,JDBC_USER,JDBC_PASSWORD);
  91. }
  92. }

3. 数据库事务总结

  • 具有ACID特性

    * Atomicity:原子性

    * Consistency:一致性

    * Isolation:隔离型

    * Durability:持久性
  • JDBC提供了事务的支持

廖雪峰Java15JDBC编程-3JDBC接口-4JDBC事务的更多相关文章

  1. 廖雪峰Java15JDBC编程-3JDBC接口-5JDBC连接池

    1. JDBC连接池 1.1 JDBC连接池简介 线程池可以复用一个线程,这样大量的小任务通过线程池的线程执行,就可以避免反复创建线程带来的开销. 同样JDBC可以复用一个JDBC连接 JDBC的连接 ...

  2. 廖雪峰Java15JDBC编程-3JDBC接口-1JDBC简介

    JDBC:Java DataBase Connectivity Java程序访问数据库的标准接口 使用Java程序访问数据库的时候,Java代码并不是直接通过TCP连接去访问数据库,而是通过JDBC接 ...

  3. 廖雪峰Java15JDBC编程-3JDBC接口-3JDBC更新

    使用update语句的时候,需要通过JDBC实现update语句的执行,这个时候仍然通过PreparedStatement对象来使用,直接传入update语句,然后通过setObject传入占位符的值 ...

  4. 廖雪峰Java15JDBC编程-3JDBC接口-2JDBC查询

    我们可以使用JDBC查询来执行select语句. 1. Statement try(Connection conn = DriverManager.getConnection(JDBC_URL, JD ...

  5. 廖雪峰Java15JDBC编程-2SQL入门-2insert/select/update/delete

    1. INSERT用于向数据库的表中插入1条记录 insert into 表名 (字段1,字段2,...) values (数据1,数据2,数据3...) 示例 -- 如果表存在,就删除 drop t ...

  6. 廖雪峰Java15JDBC编程-2SQL入门-1SQL介绍

    1.SQL:结构化查询语言 Structured Query Language 针对关系数据库设计 各种数据库基本一致 允许用户通过SQL查询数据而不关心数据库底层存储结构 1.1 SQL使用: 可以 ...

  7. 廖雪峰Java15JDBC编程-1关系数据库基础-1关系数据库简介

    1.数据库 1.1 定义 数据库是按照数据结构来组合.存储和管理数据的软件. 1.2 数据库模型 数据库有层次模型.网状模型.关系模型三种模型. 2 关系数据库 关系数据库是建立在关系模型上的数据库, ...

  8. 廖雪峰Java6IO编程-1IO基础-1IO简介

    1.IO简介 IO是指Input/Output,即输入和输出: Input指从外部读取数据到内存,例如从磁盘读取,从网络读取. * 为什么要把数据读到内存才能处理这些数据呢? * 因为代码是在内存中运 ...

  9. 廖雪峰Java6IO编程-2input和output-1inputStream

    1.InputStream 1.1InputStream是所有输入流的超类: int read() * 读取下一个字节,并返回字节(0-255) * 如果已读到末尾,返回-1 * read()方法是阻 ...

随机推荐

  1. ionic:目录

    ylbtech-ionic:目录 1.返回顶部 1. http://www.runoob.com/ionic/ionic-tutorial.html 2. 2.返回顶部   3.返回顶部   4.返回 ...

  2. hive表操作(转)

    转载于:http://blog.csdn.net/lovelovelovelovelo/article/details/52234971 数据类型 基本数据类型 集合类型,array.map.stru ...

  3. go 数据类型和操作符

    文件名&关键字&标识符 1. 所有go源码以 .go结尾 2. 标识符以字母或者下划线开头,大小写敏感:add, Add, _add _是特殊标识符,用来忽略结果 3. 保留关键字 G ...

  4. iOS开发系列-Runtime运用场景

    概述 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的. 调用runtimeAPI需要导入都文件#impor ...

  5. Spark与Hadoop的对比

  6. css----less预处理器

    ###less less是一种动态样式语言,属于css预处理器的范畴,它扩展了 CSS 语言, 增加了变量.Mixin.函数等特性,使 CSS 更易维护和扩展 LESS 既可以在 客户端 上运行 ,也 ...

  7. P5390 [Cnoi2019]数学作业

    P5390 [Cnoi2019]数学作业求子集异或和的和拆成2进制,假设有x个数这一位为1,剩下n-x个数对答案没有贡献,对于这一位而言,对答案的贡献就是,x个数选奇数个数的方案数*2^(n-x).由 ...

  8. SpringBoot 非web项目简单架构

    1.截图 2.DemoService package com.github.weiwei02.springcloudtaskdemo; import org.springframework.beans ...

  9. Batch - C:\Progra~1是什么意思

    就是那种DOS下的8.3的规范,可以这样写 C:\Progra~1也可以这样写全名字的 "C:\Program File",因为这个路径中的文件夹名有空格,要用两个英文输入法下的双 ...

  10. pom parent 标签

    <!--parent用于引用父工程 1.统一管理jar包的版本,其依赖需要在子工程中定义才有效(比如此例) 2.统一的依赖管理(父工程的<dependencies>,子工程不必重新引 ...