分享

只读事务还是只读模式

 chengkunzhang 2016-02-18
     学习spring常常听说只读事务,到底什么是只读事务?
“只读事务”的提法太过笼统.只读事务可以分为两个方面:JDBC和数据库。

JDBC的Connection对象有一个方法setReadOnly。JDK的API描述如下:
Java代码  收藏代码
  1. Puts this connection in read-only mode as a hint to thedriver to enable   
  2. database optimizations.   

翻译过来的意思“把此连接设置为只读模式,作为的数据库优化的暗示”.这里面有事务隔离吗?没有。甚至SUN的描述都很模糊,只是向数据库驱动做一个启动数据库优化的暗示,不代表一定有效。所以不应该把readOnly作为打开只读事务的判断。
robbin 在只读查询是否需要启动事务管理,兼论只读事务的说法并不十分正确:
robbin 写道

在JDBC中,指定只读事务的办法为:
connection.setReadOnly(true);

在Hibernate中,指定只读事务的办法为:
session.setFlushMode(FlushMode.NEVER);
此时,Hibernate也会为只读事务提供Session方面的一些优化手段

在Spring的Hibernate封装中,指定只读事务的办法为:
bean配置文件中,prop属性增加“readOnly”


查看oracle的文档对jdbc驱动的描述:
Java代码  收藏代码
  1. Transaction Isolation Levels and Access Modes  
  2. Read-only connections are supported by the Oracle server, but not by the   
  3. Oracle JDBC drivers.  

Oracle服务器支持Read-only ,这个又是什么意思呢?

为了搞清楚这个所谓的“只读事务”必须先明确一个概念--“事务隔离级别(transaction isolation degree)”,ANSI标准定义了4个隔离级别标准:
  • READ UNCOMMITTED:最低级别的隔离,通常又称为dirty read,它允许一个事务读取还没commit的数据,这样可能会提高性能,但是dirty read可能不是我们想要的。
  • READ COMMITTED:在一个事务中只允许已经commit的记录可见。如果session中select还在查询中,另一session此时insert一条记录,当前事务可以看到修改的记录,从而产生不可重复读取和幻像数据。
  • REPEATABLE READ:在一个事务开始后,其他session对数据库的修改在本事务中不可见,直到本事务commit或rollback。在一个事务中重复select的结果一样,除非本事务中update数据库。  
  • SERIALIZABLE:最高级别的隔离,只允许事务串行执行。为了达到此目的,数据库会锁住每行已经读取的记录,其他session不能修改数据直到前一事务结束,事务commit或取消时才释放锁。

主流数据库的一般的默认是READ COMMITTED级别。

MYSQL和MS SQLServer遵守了这个定义而oracle没有。oracle只有三种事务隔离等级:
  • Read committed
  • Serializable
  • Read-only Read-only transactions see only those changes that were committed at the time the transaction began and do not allow INSERT, UPDATE, and DELETE statements


前两个Read committed,Serializable 和ANSI的定义是一致的,来看看最关键的第三个Read-only 。Read-only事务只会看到在这个事务开启时间点其他事务提交过的数据,并且不允许执行INSERT, UPDATE,DELETE语句,换句话说,在设置set transaction read only后,当前会话所见的数据图像,将不再受到其他会话事务的影响。
所以oracle支持的只读事务不是为了优化性能,而是为了让这个事务中所有的查询操作看到的数据是一个时间点(开启事务)上的一致数据。MYSQL,SQL_SERVER根本没有只读事务的概念,但是有REPEATABLE READ,具体看之间的差别。


有了这个基础后,再看Connection对象也定义了五个变量和ANSI标准对应:

Java代码  收藏代码
  1. int TRANSACTION_NONE  =0;    //不受支持的事务  
  2. int TRANSACTION_READ_COMMITTED =1;  
  3. int TRANSACTION_READ_UNCOMMITTED = 2;  
  4. int TRANSACTION_REPEATABLE_READ = 4;  
  5. int TRANSACTION_SERIALIZABLE  =8;  


而Spring也不过是在这上面做封装。TransactionDefinition接口中定义了五个不同的事务隔离级别:
Java代码  收藏代码
  1. int ISOLATION_DEFAULT = -1;  
  2. int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;  
  3. int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;  
  4. int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;  
  5. int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;  


既然没有只读事务的概念,那么提交一个查询是否需要开启一个事务呢?
不同的数据库可能有不同实现,oracle驱动的文档介绍:
如果关闭Disabling Auto-Commit Mode可以提高一定的性能。
但是MYSQL好像相反,参见:http://www./topic/1603?page=1

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多