事务
transaction
什么是事务?
将一系列对数据库的操作封装到一个执行流程,
如果所有操作都能成功,则完成,
否则所有操作均失败
事务实现流程:
A:开启事务 start transaction;
B:执行SQL操作
C:如果SQL语句都正常执行,最后要执行 commit 将数据写入到数据库
如果SQL语句出现问题,执行 rollback 进行回滚操作,这时,数据恢复成事务开始之前的状态
事务实现原理:
A:非事务实现,执行完一条SQL语句,就马上将数据写入到数据库
B:事务执行时,执行完SQL语句,数据只是保存在内存中,如果事务执行成功,一次性写入到数据库
否则就不写
事务与非事务的本质区别
事务是在内存中操作数据,根据最终结果再决定是否写到磁盘,而非事务是直接操作磁盘
导入数据库连接池工具类
//一定不要指定线程池,因为要统一con,线程池自己调用con不能保证
QueryRunner qr = new QueryRunner();
Connection con = null;
try {
con = ...;从连接池获得,(从线程局部变量得到(ThreadLocal)保证每个线程得到的Connection是同一个)
con.setAutoCommit(false);
String sql1 = "xxxx";
qr.update(sql1);
String sql2 = "xxxx";
qr.update(sql2);
con.commit();
} catch(Exception e) {
if(con != null){
con.rollback();
}
}
总结:
DOS命令行下,事务的最终处理依赖于人力判断
java中的回滚或提交是靠程序实现的,如果没有异常就提交,不然就在catch中回滚
事务提交有两种设置方式:
方式1:start transaction;
方式2:set autoCommit = 0;
SQL语句中针对于单个事务,实现相同
但是若是多个事务,start transaction 对应的要在每次事务开始时都调用
但是set autocommit只需要调用一次
一个线程中,只能有一个事务,如果开启另一个事务时,第一个事务会自动提交
ThreadLocal:
在同一个线程中共享数据,底层是一个Map,有泛型,一个线程中共用的是同一个资源,不同的线程是不同con,两个线程的con互不影响
get() set() 方法
不用ThreadLocal保存线程时,两个线程有可能共用的是同一个con
(因为加了static,如果不加static,dao层要用con就必须通过传递,增加耦合),
如果共用一个con,一个线程提交,另一个线程也会提交(因为共用的同一个con),数据不安全
事务特性:
原子性:事务不可分,必须提交或回滚
一致性:数据操作前后一致
隔离性:不同的事务之间具有隔离的作用
持久性:对数据的操作是写在磁盘中的,是永久的
隔离性:出现的问题
脏读 不可重复读 虚读/幻读
read uncommitted 脏读:读到没有提交的数据(update语句),并可以使用
read commit 不可重复读:另一个事务中提交(update语句)后,此事务即使没有重启也能读到该数据
repeatable read 幻读:一个事务读取数据时,另一个事务插入数据并提交之后,这个事务数据的更改会更改到刚插入的数据
serializable 不存在安全问题
MySql:repeatable
Oracle:read committed