JDBC高级-事务

Posted djw1314-94-08-31

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDBC高级-事务相关的知识,希望对你有一定的参考价值。

(一)什么是事务

事务:是数据库的概念,逻辑上的一组操作,组成这级操作的各个单元,要么全部成功,要么全部失败。

主要是针对批量的insertupdatedelete语句

(二)事务的作用

保证多条SQL的数据变更,要么全部成功,要么全部失败。

在实际业务场景里,通常会遇到一些特殊的业务:这些业务需要由多条SQL操作来一起完成。如果没有事务,那么每执行一条SQL,数据变更会立即生效;但是如果在执行过程中,某一条SQL执行失败或者出现了异常,前边的SQL变更已经生效,但是后边的SQL就不执行了,造成的后果就是:业务完成了一半,一半成功,一半失败。

就可以使用事务来保证业务里的多条SQL,要么一起成功,要么一起失败。

 

开启事务:

执行多条SQL语句 ----开启事务之后,执行的SQL不会立即生效,而是被数据库暂时保存起来

关闭事务

提交事务:刚刚执行的所有SQL的变更,会立即全部生效,持久化保存到数据库里

回滚事务:刚刚执行的所有sqlr变更,会全部撤消,数据回滚到执行之前的状态

(三)mysql的事务管理(了解)

MySql的事务管理,默认是自动提交的。

MySql提供了两种事务管理的方式:

自动管理:

关闭自动提交:set autocommit=0;

执行nSQL语句

提交事务/回滚事务: commit/rollback

手动管理:

手动开启事务: start transaction;

执行nSQL语句

手动提交事务/回滚事务: commit/rollback;

一、JDBC的事务管理

(一)JDBC事务管理简介

操作数据库一般是由Java程序来操作,那么事务管理也需要由Java程序来进行管理。就需要使用JDBC来管理事务。

(二)JDBC事务相关的API

JDBC里事务管理是基于Connection对象的。

开启事务:conn.setAutoCommit(false);

提交事务:conn.commit();

回滚事务:conn.rollback();

 

使用JDBC管理事务的步骤:

注册驱动

获取连接

开启事务

创建SQL执行平台

执行SQL语句

关闭事务:提交事务/回滚事务

释放资源

二、DBUtils的事务管理(重点)

DBUtils的本质仍然是JDBC,所以DBUtils的事务管理,也是基于Connection对象的。

 无事务的DBUtils操作

创建QueryRunner对象:有参构造方法,把连接池对象传递进去

QueryRunner runner = new QueryRunner(连接池对象);/执行SQL语句

runner.update(sql, Object… params);

 事务管理相关的DBUtils操作

创建QueryRunner对象:使用无参构造

QueryRunner runner = new QueryRunner();

执行SQL时,需要传递一个开启了事务的Connection对象给runner来执行SQL

runner.update(conn, sql, params);

三、ThreadLocal(应用)

 什么是ThreadLocal

JDK提供的一个类,java.lang.ThreadLocal。 线程局部变量。可以实现在线程的进行变量的共享

 ThreadLocal有什么用

在某一个代码里,使用ThreadLocal向当前线程中绑定一个数据,当线程执行到后边其它代码的时候,就可以从当前线程获取到绑定的变量的值。

可以理解为:实现隐式传参的

比如:

显式传参:service传参conndao

dao.outMoney(conn);

隐式传参:service传参conndao

service里,把conn绑定到当前线程上

线程会调用dao的代码:dao.outMoney()

dao里,从当前线程上获取到绑定的conn对象

 ThreadLocal相关的API

构造方法:ThreadLocal<T>();

向当前线程上绑定数据:tl.set(value);

从当前线程上取数据:tl.get();

从当前线程上删除数据:tl.remove();

 使用ThreadLocal优化工具类,进行事务管理

Service代码:

try{

JdbcUtils.startTransaction();

调用dao的方法,不需要传参Connection对象。可以调用多个dao的方法,属于同一个事务

JdbcUtils.commitAndClose();

}catch(Exception e){

JdbcUtils.rollbackAndClose();

}

Dao的代码:

使用无参构造创建一个QueryRunner对象:runner

runner.update(JdbcUtils.getConnection(), sql, params);

四、事务的特性

(一)事务的特性ACID

Atomicity 原子性,表示一个事务里的多个操作是不可分割的,一个事务的所有操作,要么全部成功,要么全部失败。

Consistency 一致性,表示事务提交前后,数据是一致的。

I  Isolation 隔离性,表示多个事务之间,应该是相互独立,互不干扰的。

Durability 持久性,表示事务提交之后,数据就持久化保存到了数据库里。

(二)事务并发存在的问题

是在不考虑事务的隔离性,或者隔离性比较弱的情况下,存在的事务并发问题。

脏读:一个事务读取到了另外一个事务未提交的数据。(最严重的问题,必须要避免的问题)

不可重复读:一个事务读取到另外一个事务里的update的变更。

虚读/幻读:一个事务读取到另外一个事务里的insertdelete的变更。

(三)事务的隔离级别

read uncommitted:未提交读,存在脏读、不可重复读、虚读

read committed:已提交读,不存在脏读,存在不可重复读、虚读

repeatable read:可重复读,不存在脏读、不可重复读,存在虚读

serializable:串行化,同一时间只有一个事务在执行,其它事务排队等候,所有问题都不存在

 

安全性比较:serializable > repeatable read > read committed > read uncommitted

性能比较:serializable < repeatable read < read committed < read uncommitted

 

MySql的默认隔离级别是:repeatable read

Oracle的默认隔离级别是:read committed

 

MySql

查看事务的隔离级别:select @@tx_isolatioin

设置事务的隔离级别:set session transaction isolation level 隔离级别

(四)不同事务隔离级别的演示

准备:

打开AB两个客户端,都连接上MySql。把A作为演示会话,把B作为干扰会话。

l read uncommited

设置A的隔离级别为read uncommitted

AB都开启事务

A查询一下数据----看一下表的原始数据是什么样的

B执行update,但不提交事务

A再次查询数据----看数据有没有变更,如果有变量,就说明读到了B未提交的数据----存在脏读

 read commited

设置A的隔离级别为read commited

AB都开启事务

A查询数据---看原始数据

B执行update但不提交

A再次查询----确认脏读问题是否解决:已经解决

B提交事务

A再次查询----看数据和刚刚查询是否一致:数据不一致,存在不可重复读问题

 repeatable read

设置A的隔离级别为repeatable read

AB同时开启事务

A查询数据查看原始数据

B执行update但不提交

A再次查询----确认脏读是否解决:已经解决

B提交事务

A再次查询----确认不可重复读是否解决:已经解决

A关闭事务

A查询数据----确认数据是否已经真实变更到数据库

 serializable

设置A的隔离级别为serializable

AB同时开启事务

A查询数据

B执行update操作---会处于等待状态,等A事务结束

有两种结果:

等待超时

A事务结束了,B事务会立即执行

以上是关于JDBC高级-事务的主要内容,如果未能解决你的问题,请参考以下文章

Java数据库连接——JDBC调用存储过程,事务管理和高级应用

Java数据库连接——JDBC调用存储过程,事务管理和高级应用

JAVA高级——吃透JDBC中的事务及事务的封装

Java数据库连接--JDBC调用存储过程,事务管理和高级应用

第13章WEB13-JSP模式&JDBC高级篇

Spring的事务抽象