JDBC高级-事务
Posted djw1314-94-08-31
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDBC高级-事务相关的知识,希望对你有一定的参考价值。
(一)什么是事务
事务:是数据库的概念,逻辑上的一组操作,组成这级操作的各个单元,要么全部成功,要么全部失败。
主要是针对批量的insert、update、delete语句
(二)事务的作用
保证多条SQL的数据变更,要么全部成功,要么全部失败。
在实际业务场景里,通常会遇到一些特殊的业务:这些业务需要由多条SQL操作来一起完成。如果没有事务,那么每执行一条SQL,数据变更会立即生效;但是如果在执行过程中,某一条SQL执行失败或者出现了异常,前边的SQL变更已经生效,但是后边的SQL就不执行了,造成的后果就是:业务完成了一半,一半成功,一半失败。
就可以使用事务来保证业务里的多条SQL,要么一起成功,要么一起失败。
开启事务:
执行多条SQL语句 ----开启事务之后,执行的SQL不会立即生效,而是被数据库暂时保存起来
关闭事务
提交事务:刚刚执行的所有SQL的变更,会立即全部生效,持久化保存到数据库里
回滚事务:刚刚执行的所有sqlr变更,会全部撤消,数据回滚到执行之前的状态
(三)mysql的事务管理(了解)
MySql的事务管理,默认是自动提交的。
MySql提供了两种事务管理的方式:
自动管理:
关闭自动提交:set autocommit=0;
执行n条SQL语句
提交事务/回滚事务: commit/rollback
手动管理:
手动开启事务: start transaction;
执行n条SQL语句
手动提交事务/回滚事务: 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传参conn给dao
dao.outMoney(conn);
隐式传参:service传参conn给dao
在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
A :Atomicity 原子性,表示一个事务里的多个操作是不可分割的,一个事务的所有操作,要么全部成功,要么全部失败。
C :Consistency 一致性,表示事务提交前后,数据是一致的。
I :Isolation 隔离性,表示多个事务之间,应该是相互独立,互不干扰的。
D :Durability 持久性,表示事务提交之后,数据就持久化保存到了数据库里。
(二)事务并发存在的问题
是在不考虑事务的隔离性,或者隔离性比较弱的情况下,存在的事务并发问题。
脏读:一个事务读取到了另外一个事务未提交的数据。(最严重的问题,必须要避免的问题)
不可重复读:一个事务读取到另外一个事务里的update的变更。
虚读/幻读:一个事务读取到另外一个事务里的insert、delete的变更。
(三)事务的隔离级别
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 隔离级别
(四)不同事务隔离级别的演示
准备:
打开A和B两个客户端,都连接上MySql。把A作为演示会话,把B作为干扰会话。
l read uncommited
设置A的隔离级别为read uncommitted
A和B都开启事务
A查询一下数据----看一下表的原始数据是什么样的
B执行update,但不提交事务
A再次查询数据----看数据有没有变更,如果有变量,就说明读到了B未提交的数据----存在脏读
read commited
设置A的隔离级别为read commited
A和B都开启事务
A查询数据---看原始数据
B执行update但不提交
A再次查询----确认脏读问题是否解决:已经解决
B提交事务
A再次查询----看数据和刚刚查询是否一致:数据不一致,存在不可重复读问题
repeatable read
设置A的隔离级别为repeatable read
A和B同时开启事务
A查询数据—查看原始数据
B执行update但不提交
A再次查询----确认脏读是否解决:已经解决
B提交事务
A再次查询----确认不可重复读是否解决:已经解决
A关闭事务
A查询数据----确认数据是否已经真实变更到数据库
serializable
设置A的隔离级别为serializable
A和B同时开启事务
A查询数据
B执行update操作---会处于等待状态,等A事务结束
有两种结果:
等待超时
A事务结束了,B事务会立即执行
以上是关于JDBC高级-事务的主要内容,如果未能解决你的问题,请参考以下文章
Java数据库连接——JDBC调用存储过程,事务管理和高级应用
Java数据库连接——JDBC调用存储过程,事务管理和高级应用