setAutoCommit(false)相当于start transaction;开启事务
rollback()事务回滚
commit()事务提交
设置事务的回滚点
例如:
Savepoint sp = conn.setSavepoint();
conn.rollback(sp);
原子性:指它是一个不可分割的整体,要么全都成功,要么全都不成功。
一致性:在执行事务完成后,前后的数据要保持一致。
隔离性:事务与事务之间不可以相互影响。
持久性:事务一旦提交,数据就真正修改了,不可以在改变。
对于以上问题,怎样进行控制?可以通过设置事务的隔离级别来解决以上问题
事务隔离级别有四种----------(级别从高到低)
1 Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)
2 Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)不可以避免虚读
3 Read committed:可避免脏读情况发生(读已提交)
4 Read uncommitted:最低级别,以上情况均无法保证。(读未提交)
Mysql数据库默认的事务隔离级别是 repeatable read
Oracle数据库默认的事务隔离级别是 read committed
设置事务的隔离级别:
数据库默认有事务的隔离级别,mysql 中查看与修改事务的隔离级别
set session transaction isolation level 设置事务隔离级别
select @@tx_isolation 查询当前事务隔离级别
这个方法是在jdbc中设置事务的隔离级别
参数level可以是以下值之一
Connection.TRANSACTION_READ_UNCOMMITTED(最低)、
Connection.TRANSACTION_READ_COMMITTED(次低)
Connection.TRANSACTION_REPEATABLE_READ(次高) Connection.TRANSACTION_SERIALIZABLE。(最高)
(注意,不能使用 Connection.TRANSACTION_NONE,因为它指定了不受支持的事务。)
一个事务读取到了另一个事务的未提交数据。
要想演示脏读,我们必须设置事务的隔离级别Read uncommitted
步骤
1.设置两个窗口的事务隔离级别
set session transaction isolation level Read uncommitted;
2.在两个窗口中开启事务
start transaction;
3.在 A窗口中执行汇款操作(但没有提交事务,可以回滚)
4.在b窗口中执行(看到的结果是对方未提交的事务)
出现了脏读。
解决脏读,可以设置事务隔离级别为Read committed(次级)
1. 设置事务隔离级别
set session transaction isolation level Read committed;
将上面操作在执行一次。
2. 这时b窗口在执行查询操作结果
解决了脏读。
不可重复读是指一个事务读取到了另一个事务提交的数据。
接着上面的案例继续执行。
1. A窗口将事务提交。
2. B窗口在查询数据
将事务的隔离级别修改为Repeatable read(次高)
1. 将事务隔离级别修改为
set session transaction isolation level Repeatable read;
2. 将上述操作在执行一次,那么会发现,我们在执行查询结果
这时A窗口已经commit.但我们没有读取到提交的数据。
避免了不可重复读。(但数据真实性没有得到及时更新)(保证在自己当前事务的查到数据一致)
要想将A窗口提交的数据读取到,必须让当前事务commit,在执行操作
set session transaction isolation level Serializable;
这种事务隔离级别会锁表,它的安全性最高。(只允许一个事务操作,其他事务只能等待操作)
对于隔离级别四种
安全性 Serializable》Repeatable read》read committed 》read uncommitted;
性能 Serializable《Repeatable read《read committed 《read uncommitted;
在开发中,一般使用 read committed repeatable read两种。
通过这个案例明白service层的作用,及在开发中,事务一般都是在service层处理的。
1. 创建一个account.jsp页面
2. 创建一个AccountServlet
3. 创建一个AccountService
1. 开启事务
2. 调用dao中两个方法完成转账汇款操作
3. 有问题了在catch中进行事务 回滚。
4. 最后在finally中进行事务commit及con.close();
简单说,我们在service层调用了dao中两个方法,为了保证这个两个操作是在同一个事务中,我们将Connection做为参数传递到了dao层。
4.创建一个AccountDao
在dao中进行转账汇款操作
在以上代码基础上进行优化
1. 对jdbcUtils工具进行优化
2. 对service层传递connection对象到dao进行优化。
ThreadLocal类,它相当于一个Map集合,只不过它的key就是当前线程对象.
通过set方法向ThreadLocal中添加元素 相当于put(Thread.currentThread(),Object);
通过get方法从ThreadLocal中获取元素 相当于get(Thread.currentThread());
在jdbcUtils中创建一个ThreadLocal对象来存储绑定到线程中的Connection对象,在JdbcUtils中提供开启事务,事务回滚,事务提交及关闭的方法
丢失更新是指后提交的事务将先提交事务的修改操作覆盖了。
解决丢失更新问题方式:
1. 悲观锁 for update(排它锁) update语句默认添加排它锁。
2. 乐观锁 使用版本字段