事务
什么是事务,简单的说就是,就是要不一起成功,要不一起失败。
- 事务通常被定义为一个不可分割的工作单元。
- 事务控制多个应用程序对数据库的并发访问操作,确保数据的完整性。
- 在系统失效的情况下,事务确保恢复后,数据仍处于一致的状态。
再来了解一下两个重要的概念,Java事务API(JTA;Java Transaction API)以及Java事务服务(JTS;Java Transaction Service)
JTA事务比JDBC事务更强大。一个JTA事务可以有多个参与者,而一个JDBC事务则被限定在一个单一的数据库连接。下列任一个Java平台的组件都可以参与到一个JTA事务中:
.JDBC连接
.JDO PersistenceManager 对象
.JMS 队列
.JMS 主题
.企业JavaBeans(EJB)
.一个用J2EE Connector Architecture 规范编译的资源分配器。
要用JTA来划分一个事务,应用程序调用javax.transaction.UserTransaction接口中的方法。
InitialContext ctx = new InitialContext();
Object txObj = ctx.lookup("java:comp/UserTransaction";);
UserTransaction utx = (UserTransaction) txObj;
DataSource ds = obtainXADataSource();
Connection conn = ds.getConnection();。。。
utx.commit();
如果计划使用JTA来划分事务,需要一个实现了javax.sql.XADataSource,javax.sql.XAConnection和javax.sql.XAResource接口JDBC的驱动,(如果在weblogic或者webshere中建立过datasource的朋友对XA应该比较熟悉。)XA连接是一个JTA事务中的参与者。使用了XA连接的应用程序不必调用java.sql.Connection.commit()或java.sql.Connection.rollback()。而应该使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback().
下面的例子可能更有些:
InitialContext ic = new InitialContext();
Object txObj = ic .lookup("java:comp/UserTransaction";);
UserTransaction ut = (UserTransaction) txObj;
ut.begin();
DataSource db1 = (DataSource) ic.lookup("java:comp/env/OrdersDB");
DataSource db2 = (DataSource) ic.lookup("java:comp/env/InventoryDB");
Connection con1 = db1.getConnection();
Connection con2 = db2.getConnection();
// perform updates to OrdersDB using connection con1
// perform updates to InventoryDB using connection con2
ut.commit();
数据库访问可能碰到的问题:
1,Lost update - 两个transactions同时更新同一行,由于第2个transaction的abort,造成2个更新都失去。这一般发生在系统没有对transaction进行隔绝。
2,Dirty read - 一个transaction正在读取另一个还没有commited的transaction对数据库做的改变。如果第2个transaction roll back,那么第一个transaction读取的信息就是不同步的。(脏读)
3,Unrepeatable read - 一个transaction对数据库中同一行数据读取了2遍,但是读取出来的数据却不同。这可能发生的情况是在这两次读取的间隔另一个transaction对该行做了更新。(被更新)
4,Second lost updates problem - 这种问题是Unrepeatable read的一种特例。当2个transactions同时读取一行,其中一个对该行做了更新并且commited,此时另外一transaction可能也会对此行做更新。那么第一个transaction做的改变就失效了。(同时更新)
5,Phantom read - 一个transaction执行了2次同一个query,但是第2次query读出的结果集合有第一个不存在的行。这发生在在两次query执行之间另一个transaction新增了新行。(被插入了数据)
Transaction Isolation
1.Read uncommitted
指定语句可以读取已由其他事务修改但尚未提交的行。
- 允许Dirty Read但是不允许Lost update。即一个transaction在更新数据库的一行时,别的Transaction不能对其做写操作,只能做读操作。这是通过排它写锁实现的。写锁还是有的。
2。Read committed
指定语句不能读取已由其他事务修改但尚未提交的数据。这样可以避免脏读。其他事务可以在当前事务的各个语句之间更改数据,从而产生不可重复读取和幻像数据。该选项是一般数据库的默认设置。
- 允许Unrepeatable reads但是不允许Dirty reads。对一行做读操作的transactions不会block其它访问改行的transaction,但是一个没有committed的对该行进 行写操作的transaction会block掉其它的transaction(包括读操作的transaction)。这是通过排它写锁和瞬时的共享读 锁实现的。
3。Repeatable Read
指定语句不能读取已由其他事务修改但尚未提交的行,并且指定,其他任何事务都不能在当前事务完成之前修改由当前事务读取的数据。-》 也就是读取时就给了一个排他写锁。(相当于加了 for update )
- 在此level下,只有Phantom read可能发生。当一个transaction对数据库进行读操作时候,它会block掉其它全部的transactions(不包括只读的 transactions),而一个对数据库进行写操作的transaction就会block掉其它全部的transactions。这是通过排它写锁 和共享读锁实现的。
4。Serializable
-
语句不能读取已由其他事务修改但尚未提交的数据。
-
任何其他事务都不能在当前事务完成之前修改由当前事务读取的数据。
-
在当前事务完成之前,其他事务不能使用当前事务中任何语句读取的键值插入新行。
- 这是最严格的Isolation level。他让全部的transactions以线性的方式依次执行。这是通过排它锁实现的。
ORACLE的隔离级别
l ORACLE提供了SQL92标准中的read committed和serializable,同时提供了非SQL92标准的read-only。
l read committed:
l 这是ORACLE缺省的事务隔离级别。
l 事务中的每一条语句都遵从语句级的读一致性。
l 保证不会脏读;但可能出现非重复读和幻像。
l serializable:
l 简单地说,serializable就是使事务看起来象是一个接着一个地顺序地执行。
l 仅仅能看见在本事务开始前由其它事务提交的更改和在本事务中所做的更改。
l 保证不会出现非重复读和幻像。
l Serializable隔离级别提供了read-only事务所提供的读一致性(事务级的读一致性),同时又允许DML操作。
l 如果有在serializable事务开始时未提交的事务在serializable事务结束之前修改了serializable事务将要修改的行 并进行了提交,则serializable事务不会读到这些变更,因此发生无法序列化访问的错误。(换一种解释方法:只要 在serializable事务开始到结束之间有其他事务对serializable事务要修改的东西进行了修改并提交了修改,则发生 无法序列化访问的错误。)
l read-only:
l 遵从事务级的读一致性,仅仅能看见在本事务开始前由其它事务提交的更改。
l 不允许在本事务中进行DML操作。
l read only是serializable的子集。它们都避免了非重复读和幻像。区别是在read only中是只读;而 在serializable中可以进行DML操作。
l Export with CONSISTENT = Y sets the transaction to read-only.
l read committed和serializable的区别和联系:
l 事务1先于事务2开始,并保持未提交状态。事务2想要修改正被事务1修改的行。事务2等待。如果事务1回滚,则事 务2(不论是read committed还是serializable方式)进行它想要做的修改。如果事务1提交,则当事务2是read committed方式时,进行它想要做的修改;当事务2是serializable方式时,失败并报错“Cannot serialize access”,因为事务2看不见事务1提交的修改,且事务2想在事务一修改的基础上再做修改。
l read committed和serializable可以在ORACLE并行服务器中使用。
l 关于SET TRANSACTION READ WRITE:read write和read committed 应该是一样的。在读方面,它们都避免 了脏读,但都无法实现重复读。虽然没有文档说明read write在写方面与read committed一致,但显然它在写的 时候会加排他锁以避免更新丢失。在加锁的过程中,如果遇到待锁定资源无法锁定,应该是等待而不是放弃。这 与read committed一致。
l 语句级的读一致性
l ORACLE保证语句级的读一致性,即一个语句所处理的数据集是在单一时间点上的数据集,这个时间点是这个语句开 始的时间。
l 一个语句看不见在它开始执行后提交的修改。
l 对于DML语句,它看不见由自己所做的修改,即DML语句看见的是它本身开始执行以前存在的数据。
l 事务级的读一致性
l 事务级的读一致性保证了可重复读,并保证不会出现幻像。
l 设置隔离级别
l 设置一个事务的隔离级别
l SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
l SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
l SET TRANSACTION READ ONLY;
l 设置增个会话的隔离级别
l ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE;
l ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;