事务
事务(transaction)指的是一组操作,里面包含许多个单一的逻辑。只要有一个逻辑没有执行成功,那么就算失败,所有的数据都回归到最初的状态(回滚)。
为什么要有事务呢?为了确保逻辑的成功。例子:银行转账。
1、使用命令行方式演示事务:
(1)关闭autocommit
commit:提交事务,数据将会写到磁盘上的数据库;
rollback: 数据回滚,回到最初的状态。
2、使用代码方式演示事务(转账业务):
1 package TrasctionsDemo; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 8 import org.junit.Test; 9 10 import com.util.jdbcUtil; 11 12 public class TestDemo { 13 @Test 14 public void testTransaction() { 15 Connection conn=null; 16 PreparedStatement ps=null; 17 ResultSet results=null; 18 try { 19 conn = jdbcUtil.getMysqlConn(); 20 conn.setAutoCommit(false);//关闭自动提交 21 String sql="update acc set money=money-? where name=?"; 22 ps=conn.prepareStatement(sql); 23 ps.setInt(1, 10); 24 ps.setString(2, "wangwu"); 25 ps.executeUpdate(); 26 //int a=10/0; 27 28 ps.setInt(1, -10); 29 ps.setString(2, "lisi"); 30 ps.executeUpdate(); 31 32 conn.commit(); 33 34 } catch (SQLException e) { 35 // TODO Auto-generated catch block 36 try { 37 conn.rollback(); 38 } catch (SQLException e1) { 39 // TODO Auto-generated catch block 40 e1.printStackTrace(); 41 } 42 e.printStackTrace(); 43 44 }finally{ 45 jdbcUtil.close(results, ps, conn); 46 } 47 48 } 49 }
3、事务特性:
ACID
原子性(atomicity):事务中包含的逻辑,不可分割。
一致性(consistency):事务执行前后,数据的完整性。
隔离性(isolation):事务在运行期间不应该受到其他事务的影响。
持久性(durability):事务执行成功,那么数据应该持久保存到磁盘上。
4、安全问题&隔离级别
事务的安全隐患:如果不考虑隔离设置,会出现以下安全问题:
(1)读 :脏读、不可重复读、幻读;
脏读(读未提交 read uncommitted):一个事务读到了另一个事务还未提交的数据;
不可重复读(读已提交 read committed):一个事务读到了另外一个事务提交的数据,造成了前后两次查询结果不一致;
幻读:一个事务读到了另一个事务已提交的插入的数据,导致多次查询结果不一样。
重复读:确保当前事务不受另外事务的影响。
可串行化:如果有一个连接的隔离级别设置为了串行化,那么谁先打开了连接,谁就有了先执行的权力,后打开的只能等前面的事务提交或者回滚后才能执行。但是这种级别一般少用,因为效率低。
注意:(1)事务只是针对当前连接对象,如果再开一个连接对象,是默认的提交。(2)mySql默认的隔离级别是可重复度;Oracle默认读已提交。
(2)写:丢失更新
两类:
解决丢失更新:乐观锁,悲观锁
5、乐观锁与悲观锁
(1)悲观锁:
与序列化有点相似
在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作都某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。
悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。
悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数。
for update 语句只能放到select语句中,因为查询时把数据锁住才有意义。
(2)乐观锁
在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。
乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。