事务用于保证数据的一致性,它由一组相关的dml语句组成,该组的dml语句要么全部成功,要么全部失败。
如:网上转账就是典型的要用事务来处理,用以保证数据的一致性。
当执行事务操作时(dml语句),oracle会在被作用的表上加锁,防止其它用户改表表的结构,这种锁机制采用的是文件锁形式,之前学习Java多线程的时候,对此一个比较直观的认识就是,上锁就表示在他没有解锁的情况下,只有他能用,其他人不能用。
当执使用commit语句可以提交事务,当执行了commit语句之后,会确认事务的变化、结束事务、删除保存点、释放锁,当使用commit语句结束事务后,其它会话将可以查看到事务变化后的新数据。
在介绍回退事务前,必须先知道保存点(savepoint)的概念和作用。保存点是事务中的一点,用于取消部分事务,当结束事务时,会自动的删除该事务所定义的所有保存点。
而回退事务就是在没有提交的情况下,返回当前事务的某一个保存点。
1、设置保存点
savepoint 保存点名;
2、取消部分事务
rollback to 保存点名;
3、取消全部事务
rollback;
1)保存点基本语法:savepoint 保存点名称;
2)在一个事务中允许设置多个保存点
3)返回保存点基本语法:rollback to 保存点名称;
4)回退至指定保存点后,此保存点会被删除。无法再次回退到此点,如要再回此点,需再次设置保存点
5)设置保存点,是有资源开销的
6)一旦提交commit事务,则不能回退到任何保存点,换言之,只要提交commit了事务,此事务保存点就全被删除了。
/** * 使用jdbc连接Oracle * 事务演示 * 1)从SMITH帐户减掉$100。 * 2)在ALLEN帐户加入$100。 */ package com.oracle.db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class db3 { Connection ct = null; PreparedStatement ps = null; ResultSet rs = null; public db3() { try { // 1.加载驱动 Class.forName("oracle.jdbc.driver.OracleDriver"); // 2.得到连接 ct = DriverManager.getConnection( "jdbc:oracle:thin:@127.0.0.1:1521:Switch", "scott", "123456"); // 3.创建PreparedStatement // 4.执行SQL // 设置不自动提交 ct.setAutoCommit(false); // 这样事务就是原子的 // empno为7360的员工薪水-100 String sql1 = "update emp set sal=sal-100 where empno=7369"; ps = ct.prepareStatement(sql1); ps.executeUpdate(); //如果在事务之中发生了异常,则回滚 //int a = 10/0; // empno为7499的员工薪水+100 String sql2 = "update emp set sal=sal+100 where empno=7499"; ps = ct.prepareStatement(sql2); ps.executeUpdate(); // 提交事务 ct.commit(); } catch (Exception e) { //事务出现了异常,就可以回滚 try { // 回滚 ct.rollback(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } e.printStackTrace(); } finally { try { if (rs != null) { rs.close(); } if (ps != null) { ps.close(); } if (ct != null) { ct.close(); } } catch (SQLException e) { e.printStackTrace(); } } } public static void main(String[] args) { db3 d1 = new db3(); } }
1、如果一个事务中,只有select那么事务控制可以忽略;
2、如果一个事务中,有多个dml语句(update,insert,delete)则需要考虑事务。
概念:隔离级别定义了事务与事务之间的隔离程度。
ANSI/ISO SQL92标准定义了一些数据库操作的隔离级别(这是国际标准化组织定义的一个标准而以,不同的数据库在实现时有所不同)。
隔离级别 |
脏读 |
不可重复读 |
幻影读 |
读未提交(Read uncommitted) |
√ |
√ |
√ |
读已提交(Read committed) |
× |
√ |
√ |
可重复读(Repeatable read) |
× |
× |
√ |
可串行化(Serializable) |
× |
× |
× |
√可能出现,×不会出现
脏读(dirty read):当一个事务读取另一个事务尚未提交的修改时,产生脏读。
在oracle中没有脏读的问题。
不可重复读(nonrepeatable read):同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时产生非重复读。
幻影读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻读。
oracle提供了sql92标准中的read committed(读已提交)和serializable(可串行化),同时提供了非sql92标准的read-only(读一致性)
oracle的read committed读已提交说明:
1、这里oracle缺省的事务隔离级别;
2、保证不会脏读,但可能出现非重复读和幻读。
oracle的serializable可串行化说明:
1、serializable就是使事务看起来象是一个接着一个地顺序地执行(从效果上可以这样理解);
2、仅仅能看见在本事务开始前由其它事务提交的更改和在本事务中所做的更改;
3、保证不会出现脏读、不可重复读和幻读;
4、serializable隔离级别提供了read-only事务所提供的读一致性(事务的读一致性),同时又允许DML(update/insert/delete)操作
oracle的read only读一致性说明:
1、遵从事务级的读一致性,仅仅能看见在本事务开始前由其它事务提交的更改;
2、不允许在本事务中进行DML(insert/update/delete)操作;
3、read only是serializable的子集。它们都避免了不可重复读和幻读。区别是在read only中是只读;而在serializable中可以进行DML操作。
set transaction isolation level read committed;(oracle默认的事务隔离级别“读已提交”)
set transaction isolation level serializable;(设置事务隔离级别为“可串行化”)
set transaction read only;(设置事务隔离级别为“读一致性”)
alter session set isolation_level serializable;(设置会话为“可串行化”)
alter session set isolation_level read committed;(设置会语为“读已提交”)
只读事务是指只允许执行查询的操作,而不允许执行任何其它dml操作的事务,使用只读事务可以确保用户只能取得某时间点的数据。假定机票代售点每天18点开始统计今天的销售情况,这时可以使用只读事务.在设置了只读事务后,尽管其它会话可能会提交新的事务,但是只读事务将不会取得最新数据的变化,从而可以保证取得特定时间点的数据信息。
ct.setTransactionIsolation(Connection.TRANSACTION_NONE);//不设置事务处理 ct.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); //读未提交 ct.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);//读已提交 ct.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);//可重复读 ct.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);//可串行化
1、java程序中Connection.XXXXXX有五个,但不是所有的数据库对有对应的五个事务隔离级别实现。
2、在实际工作中,我们极少去修改各个数据库默认的隔离级别。
----------参考《韩顺平玩转Oracle》