锁定老帖子 主题:只读查询是否需要启动事务管理,兼论只读事务
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-11-15
http://forum.iteye.com/viewtopic.php?t=1603 但是并没有得出明确的结论。先让我们看看事务的定义: 引用 Transactions are described in terms of ACID properties, which are as follows: n Atomic: all changes to the database made in a transaction are rolled back if any change fails. n Consistent: the effects of a transaction take the database from one consistent state to another consistent state. n Isolated: the intermediate steps in a transaction are not visible to other users of the database. n Durable: when a transaction is completed (committed or rolled back), its effects persist in the database. 即ACID的定义,从上面看来,似乎除了isolated之外,和只读查询都没有关系。那么是否只读查询不需要事务呢? 再看看Oracle对于只读事务的定义: 引用 Read-Only Transactions
By default, Oracle guarantees statement-level read consistency. The set of data returned by a single query is consistent with respect to a single point in time. However, in some situations, you might also require transaction-level read consistency. This is the ability to run multiple queries within a single transaction, all of which are read-consistent with respect to the same point in time, so that queries in this transaction do not see the effects of intervening committed transactions. If you want to run a number of queries against multiple tables and if you are not doing any updating, you prefer a read-only transaction. After indicating that your transaction is read-only, you can run as many queries as you like against any table, knowing that the results of each query are consistent with respect to the same point in time. 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” 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-11-29
我在MySQL4.1试验了一下,过程和结果如下:
数据库:MySQL4.1 表类型:InnoDB Spring:1.1.2 Hibernate:2.1.7 使用Spring的声明式事务管理 试验过程如下: 不设置查询方法的事务类型(即不需要事务):访问查询页面,后台执行Spring的Bean方法,让Hibernate发送select语句,然后手工在MySQL里面修改该记录某字段值,再访问查询页面,发现被修改过的字段值并没有变化,Hibernate输出的log显示,数据库还是把老的字段值返回,而没有返回新的字段值。 设置查询方法的事务类型(只读事务):访问查询页面,后台执行Spring的Bean方法,让Hibernate发送select语句,然后手工在MySQL里面修改该记录某字段值,再访问查询页面,发现被修改过的字段值已经变化,Hibernate输出的log显示,数据库返回新的字段值。 这个试验说明,至少在MySQL4.1的InnoDB情况下,不使用只读事务的查询将无法读取到数据更新值,必须使用只读事务来保证读记录的数据一致性。这个结果非常令我诧异,和我预期完全两样。 我将在Oracle平台上试试看会有什么样的结果。 BTW: 如果MySQL的表类型改为MyISAM,那么即使不设置事务,也不会出现读数据不一致的现象。 |
|
返回顶楼 | |
发表时间:2004-11-30
oracle有两种方法保证在事务级读数据一致性(Transaction-Level Read Consistency)
一是用SET TRANSACTION ISOLATION LEVEL SERIALIZABLE , 当执行这条命令后读数据时会产生一些重复copy, 你也可以做数据修改, 但在大量数据修改的情况下容易造成deadlock或异常, 用commit或rollback将把ISOLATION LEVEL设回为缺省模式read committed, 二是用SET TRANSCATION READ ONLY 当执行这条命令时数据库会生成一个快照的latch, 这个latch会耗费一些resource, 如果你想进行数据修改会导致异常. 用commit或rollback会把latch释放掉, 也将把ISOLATION LEVEL设回为缺省模式read committed, |
|
返回顶楼 | |
发表时间:2004-11-30
robbin老大, 严重怀疑你做的mysql试验, 把测试代码贴出来瞅瞅......
|
|
返回顶楼 | |
发表时间:2004-11-30
Readonly 写道 robbin老大, 严重怀疑你做的mysql试验, 把测试代码贴出来瞅瞅......
http://forum.iteye.com/viewtopic.php?t=8857 就用这个简单的例子测试的 |
|
返回顶楼 | |
发表时间:2004-11-30
那个里面没有测试代码啊, 你是用手工做的测试吧? ? 偶怎么能够重复呢?
写一个测试代码吧, 起2个线程, 一个用jdbc改写mysql数据库, 另外一个用UserManager调用, 看看结果咯...... |
|
返回顶楼 | |
发表时间:2004-11-30
在Oracle上面则没有这样的问题,无论是否使用只读事务,都可以读到数据库改变之后新的字段值。
说实话,我也觉得有点莫名惊诧,看起来MySQL4.1下面使用事务类型表InnoDB的时候,一但获取该Connection之后,如果不使用事务,则无法看到数据库改变,这真的太诡异了。我也希望你能证伪我的试验结果。 我的环境是: Hibernate-2.1.7 Spring-1.1.2 MySQL-4.1.7 MySQL-JDBC-3.0.16GA 表类型InnoDB |
|
返回顶楼 | |
发表时间:2004-11-30
Readonly 写道 那个里面没有测试代码啊, 你是用手工做的测试吧? ? 偶怎么能够重复呢?
写一个测试代码吧, 起2个线程, 一个用jdbc改写mysql数据库, 另外一个用UserManager调用, 看看结果咯...... 根本不需要自动测试就已经发现问题了,你设想一下,你通过web访问数据库,我是DBA,手工在console修改数据,结果你看不到我修改之后的数据,不论你怎么刷新都没用。 如果你非要写测试,自己写一个好了,不过你即使写测试代码,测试也没用办法模拟我的试验,因为你的测试代码测试会比我的条件严格很多。 |
|
返回顶楼 | |
发表时间:2004-11-30
你是指手工修改完数据, 然后页面上随便做多少次刷新, 也都不能获得数据库修改后的内容??
|
|
返回顶楼 | |
发表时间:2004-11-30
Readonly 写道 你是指手工修改完数据, 然后页面上随便做多少次刷新, 也都不能获得数据库修改后的内容??
是的,就是这样,怪异吧。 按照你的要求,我准备写一个测试,其实就是先调用Spring Bean assert一下,然后用JDBC去修改数据,然后再调用Spring Bean assert一下。 |
|
返回顶楼 | |