0%

【JDBC】数据库事务

Java实现数据库事务学习笔记

一、介绍

1.1 事务

  • (1)事物:一组逻辑操作单元,使数据从一种状态变换到另一种状态
    • 一组逻辑操作单元:一行或多行的DML操作

1.2 事务处理

  • (1)事物处理:保证所有书屋作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。
  • (2)一个事物执行多个操作时,要么所有事物都被提交(commit);要么放弃修改,事物回滚(rollback)最初状态
  • (3)数据一旦提交,就不可以回滚

1.3 数据自动提交情况

  • (1)DDL操作,一旦执行,都会自动提交
  • (2)DML操作,默认情况下,一旦执行,就会自动提交
    • 可以通过set autocommit = false的方式取消自动提交
  • (3)默认在关闭连接时,会自动提交数据

二、操作方法

  • Java实现事务,主要避免出现数据自动提交,以免数据出错无法进行回滚

例子:转账

  • (1)重载JDBCUtils的update方法,不让其关闭连接,避免数据提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static int Update(Connection conn, String sql, Object ...args){
PreparedStatement ps = null;
try {
//1.sql语句预编译
ps = conn.prepareStatement(sql);

//2.填充占位符
for (int i = 0; i < args.length; i++){
ps.setObject(i+1, args[i]);
}

//3.执行sql语句
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
//4.资源关闭,不关闭连接
JDBCUtils.close(null, ps);
}
//6.try-catch-finally处理异常
return 0;
}
  • (2)设置数据执行sql不自动提交,等事务全部成功执行完再提交,报错就回滚
    • void setAutoCommit(boolean autoCommit) throws SQLException:设置数据是否自动提交
    • void commit() throws SQLException:手动提交数据
    • void rollback() throws SQLException:数据回滚
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Test
public void test2() {
Connection conn = null;
try {
//1.连接数据库
conn = JDBCUtils.getConnection();

//2.取消数据自动提交
conn.setAutoCommit(false);

//3.执行增删改操作
String sql1 = "update user_table set balance = balance - 100 where user = ?";
JDBCUtils.Update(conn, sql1, "AA");
String sql2 = "update user_table set balance = balance + 100 where user = ?";
JDBCUtils.Update(conn, sql2, "BB");

//4.手动提交数据
conn.commit();
} catch (Exception e) {
System.out.println("事物出现错误,数据回滚!");
//5.出现异常时,数据回滚
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} finally {
//6.恢复为默认值自动提交数据,用于数据库连接池操作
try {
conn.setAutoCommit(true);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
//7.关闭连接
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//8.try-catch-finally处理异常
}

三、事物ACID属性

  • (1)原子性(Automicity)
    • 原子性是指事物是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
  • (2)一致性(Consistency)
    • 事物必须使数据库从一致状态变换到另外一个一致性状态
  • (3)隔离性(isolation)
    • 事物的隔离性是指一个事物的执行不能被其他事物干扰,即一个事物内部的操作及使用的数据对并发的其他事务是隔离带,并发执行的各个事务之间不能互相干扰
  • (4)持久性(Durability)
    • 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其他有人哈影响

四、事务隔离

4.1 事务并发出现的问题

  • (1)脏读:事务T1读取事务T2更新了,但未提交的数据
  • (2)不可重复读:T1读取了某个字段,T2操作更新了该字段,T1再进行读取时发现两次读取不一致
  • (3)幻读:T1读取某个字段,T2对该字段所在表插入新的字段,如果T1再进行读取该表,会发现多出几行

4.2 四种隔离级别(隔离级别越高,性能越差)

  • (1)READ UNCOMMITTED(读未提交数据):什么问题都没解决

  • (2)READ COMMITTED(读已提交数据):解决了脏读的问题

  • (3)REPEATABLE READ(课重复读):解决脏读、不可重复读问题

  • (4)SERIALIZABLE(串行化):三个问题都解决了

  • 补充:

    • oracle支持2种事务隔离,READ COMMITTED和SERIALIZABLE,默认为READ COMMITTED
    • mysql支持4重事务隔离,默认为REPEATABLE READ

4.3 mysql8.0设置隔离等级

  • (1)查看当前隔离级别:
    • select @@transaction_isolation;
  • (2)设置当前mysql连接的隔离级别
    • set transaction isolation level read committed;
  • (3)设置数据库系统的全局的隔离级别:
    • set global transaction isolaction level read committed

4.4 java控制数据库设置隔离等级

  • void setTransactionIsolation(int level) throws SQLException:设置隔离等级
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void queryTest() throws Exception {
//1.连接数据库
Connection conn = JDBCUtils.getConnection();

//获取当前隔离级别
System.out.println(conn.getTransactionIsolation());

//设置数据库的隔离级别
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

//取消自动提交数据
conn.setAutoCommit(false);

//2.查询数据
String sql = "select user, password, balance from user_table where user = ?";
User cc = JDBCUtils.query(conn, User.class, sql, "CC");

System.out.println(cc);
}