settings
Attribute | Required? | Default | Description |
---|---|---|---|
name |
Yes | The method name(s) with which the transaction attributes are to be associated. The wildcard (*) character can be used to associate the same transaction attribute settings with a number of methods; for example, |
|
propagation |
No | REQUIRED | The transaction propagation behavior |
isolation |
No | DEFAULT | The transaction isolation level |
timeout |
No | -1 | The transaction timeout value (in seconds) |
read-only |
No | false | Is this transaction read-only? |
rollback-for |
No | The |
|
no-rollback-for |
No | The |
即ACID的定义,从上面看来,似乎除了isolated(隔离级别:事务隔离:当前事务和其它事务的隔离的程度。例如,这个事务能否看到其他事务未提交的写数据?)之外,和只读查询都没有关系。那么 是否只读查询不需要事务呢?
再看看Oracle对于只读事务的定义:
Oracle默认情况下 保证了SQL语句级别的读一致性,即在该条SQL语句执行期间,它只会看到执行前点的数据状态,而不会看到执行期间数据被其他SQL改变的状态。
而Oracle的只读查询(read-only transaction)则保证了事务级别的读一致性,即在该事务范围内执行的多条SQL都只会看到执行前点的数据状态,而不会看到事务期间的任何被其他 SQL改变的状态。
因此我们可以得出结论:
如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性; 如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查 询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。
只读事务与读写事务区别
对 于只读查询,可以指定事务类型为readonly,即只读事务。由于只读事务不存在数据的修改,因此数据库将会为只读事务提供一些优化手段,例如 Oracle对于只读事务,不启动回滚段,不记录回滚log。
在JDBC中,指定 只读事务的办法为: connection.setReadOnly(true);
在 Hibernate中,指定只读事务的办法为: session.setFlushMode(FlushMode.NEVER); 此时,Hibernate也会为只读事务提供Session方面的一些优化手段
在 Spring的Hibernate封装中,指定只读事务的办法为: bean配置文件中,prop属性增加“readOnly”
只读事务只是无法再触发只读事务的会话中进行DML操作,而顺序事务则可以在这个触发的会话中进行DML操作。如下例所示:
只读事务:
A表:
SQL> select sal,ename from emp;
SAL ENAME
---------- ----------
800 SMITH
1600 ALLEN
1250 WARD
2975 JONES
1250 MARTIN
2850 BLAKE
2450 CLARK
3000 SCOTT
5000 KING
1500 TURNER
1100 ADAMS
SAL ENAME
---------- ----------
950 JAMES
3000 FORD
1300 MILLER
已选择14行。
SQL> set transaction read only;
事务处理集。
SQL> select sal,ename from emp where ename='SCOTT';
SAL ENAME
---------- ----------
3000 SCOTT
SQL> select sal,ename from emp where ename='SCOTT';
SAL ENAME
---------- ----------
3000 SCOTT
SQL> update emp set sal=500 where ename='SCOTT';
update emp set sal=500 where ename='SCOTT'
*
第 1 行出现错误:
ORA-01456: 不能在 READ ONLY 事务处理中执行插入/删除/更新操作
B表:进行SCOTT用户的sal update操作
SQL> show user
USER 为 "SCOTT"
SQL> update emp set sal=2000 where ename='SCOTT';
已更新 1 行。
SQL> commit;
提交完成。
SQL> select sal,ename from emp where ename='SCOTT';
SAL ENAME
---------- ----------
2000 SCOTT
顺序事务:
A表:
SQL> set transaction isolation level serializable;
事务处理集。
SQL> select sal,ename from emp;
SAL ENAME
---------- ----------
800 SMITH
1600 ALLEN
1250 WARD
2975 JONES
1250 MARTIN
2850 BLAKE
2450 CLARK
1000 SCOTT
5000 KING
1500 TURNER
1100 ADAMS
SAL ENAME
---------- ----------
950 JAMES
3000 FORD
1300 MILLER
已选择14行。
SQL> select sal,ename from emp;
SAL ENAME
---------- ----------
800 SMITH
1600 ALLEN
1250 WARD
2975 JONES
1250 MARTIN
2850 BLAKE
2450 CLARK
1000 SCOTT
5000 KING
1500 TURNER
1100 ADAMS
SAL ENAME
---------- ----------
950 JAMES
3000 FORD
1300 MILLER
已选择14行。
SQL> update emp set sal=3000 where ename='SCOTT';
update emp set sal=3000 where ename='SCOTT'
*
第 1 行出现错误:
ORA-08177: 无法连续访问此事务处理
SQL> select sal,ename from emp;
SAL ENAME
---------- ----------
800 SMITH
1600 ALLEN
1250 WARD
2975 JONES
1250 MARTIN
2850 BLAKE
2450 CLARK
1000 SCOTT
5000 KING
1500 TURNER
1100 ADAMS
SAL ENAME
---------- ----------
950 JAMES
3000 FORD
1300 MILLER
已选择14行。
SQL> update emp set sal=3000 where ename='SCOTT';
update emp set sal=3000 where ename='SCOTT'
*
第 1 行出现错误:
ORA-08177: 无法连续访问此事务处理
SQL> update emp set sal=3000 where ename='MILLER';
已更新 1 行。
SQL> commit;
提交完成。
B表:
SQL> update emp set sal=2000 where ename='SCOTT';
已更新 1 行。
SQL> commit;
提交完成。
oracle 只读事务 (转载)
一致性读是oracle区别于其他数据库的重要特点之一,但一般来说,这个一致性读是sql级别的,只针对单个sql有效。
由于业务逻辑需要,我们可能需要在一个事务中的多个sql也能实现读一致性,也就是说,数据源在事务开始时就定下来了,不受其他会话影响。oracle的只读事务可以实现这个功能,它可以在事务级别上实现读一致性。
看下面的实验:
SQL> select * from t1;
ID
---------------------------------------
1
SQL> set serverout on
SQL>
SQL> create or replace procedure p_test is
2 l_id int;
3 begin
4 select id into l_id from t1;
5 dbms_output.put_line(l_id);
6 dbms_lock.sleep(15);
7 select id into l_id from t1;
8 dbms_output.put_line(l_id);
9 end p_test;
10 /
Procedure created
SQL> exec p_test;
--在p_test运行期间(执行dbms_lock.sleep时),修改t1的数据:
SQL> update t1 set id=2;
1 row updated
SQL> commit;
Commit complete
--以下是输出结果
1
2
可以看到,由于第二次读取t1表的数据时,由于有其他会话修改并提交了t1表的数据,所以第二次得到的结果是2.
我们对这个p_test做一个简单的修改,设置只读事务:
SQL> create or replace procedure p_test is
2 l_id int;
3 begin
4 set transaction read only;
5 select id into l_id from t1;
6 dbms_output.put_line(l_id);
7 dbms_lock.sleep(15);
8 select id into l_id from t1;
9 dbms_output.put_line(l_id);
10 end p_test;
11 /
Procedure created
SQL> exec p_test;
--在p_test运行期间(执行dbms_lock.sleep时),修改t1的数据:
SQL> update t1 set id=3;
1 row updated
SQL> commit;
Commit complete
--以下是输出结果
2
2
可以看到,虽然第二次读取t1表的数据前,已经有其他会话修改并提交了t1表的数据,但第二次得到的结果仍然是2.
这就是只读事务的功能,它在整个事务中保证一致性读:在整个事务中的数据在事务开始时就决定,即使有其他会话在事务周期内修改并提交数据,也不会影响事务。可以认为在只读事务周期内,其他事务的对数据的改变就像不存在一样。
在显式提交或者回滚后、或执行ddl后,结束只读事务。
需要注意:因为只读事务的原理是读取undo中数据的前镜像来实现一致性读的,所以,只读事务运行时间不能过长,否则会报0ra-01555。
还有一点,只读事务下是不能对数据做修改的:
suk@ORA10G> set transaction read only;
事务处理集。
suk@ORA10G> delete from test;
delete from test
*
第 1 行出现错误:
ORA-01456: 不能在 READ ONLY 事务处理中执行插入/删除/更新操作