mysql,sqlserver与Oracle事务的不同与选择



mysql默认事务级别为repeat read,而sqlserver与Oracle为readcommit。
mysql ndbcluster又只支持readcommit,sqlserver还有一个行版本是否开启的选项。

情况有些乱。先说结论:
1.mysql最好将默认事务隔离级别调整为readcommit。
2.sqlserver最好开启行版本,且保持默认事务级别。
3. oracle保持不变,这样三者事务表现得最相像。

此时三者表现:
1.事务开启后,不加修饰的select可以读到其他事务提交的数据无论其它事务开始时间,
且读不会上锁,不会阻止其他事务写,也不会被其他事务阻塞。
2.需要读上更新锁时,可以使用select ... for update
  这样读的记录就不会被其他事务修改了,如果此时该记录已经被其他事务修改,
  那么读操作将被阻塞直到其他事务提交

3.读不上锁导致会出现幻读:两次读,可能数据不同,被其它事务修改并提交了。
也可能增减记录数,被其它事务新插入或删除。


为什么sqlserver要开启行版本控制?
sqlserver2005之后可以开启行版本控制
alter database dbname set read_committed_snapshot=on

如果没有开启,那么readcommit会表现很不一样:
1.一个事务的写操作,将阻止所有其上的读操作
 简单说,一个事务中update t set where id=1,那么在事务提交前,任何
 select from t where id=1这类读操作都会被阻塞!

所以绝大部分情况都应该开启,不然和其他数据库比在并发度上就太弱了。

开启后,如果希望给读的记录上共享锁,也就是不读行版本,可以指定表提示

select * from t1 with (READCOMMITTEDLOCK) ...

这样就恢复成read_committed_snapshot=off时的行为。
而mysql在readcommit时可以使用下面方式来达到类似目的
select * from t1 ... LOCK IN SHARE MODE


为什么mysql repeat read比较另类?
首先其他数据库默认级别基本都是readcommit比如postgreSQL,db2,sybase
orcale不支持repeat read,来看和SQLServer对比
SQLServer repeat read中任何读的记录都会被上共享锁,也就是事务提交前,其它事务是无法修改了,
那么怎么读都一样了。

而mysql的方式确是第一次读的时候建立一个快照,随后只能读快照,也就是重复读,
但却不禁止其他事务修改,甚至其他修改提交后,依然只能读到之前的快照,
而此时还允许自己再修改这个记录,修改后却又可以读到最新纪录了。比如:

开始事务
select z1,z2 from t where id=1
1,2

--此时其他事务修改id=1记录z2=20的值,并提交了

--随后再读z1,z2依然是1,2

update t set z1=10 where id=1
--自己修改z1,可以成功!!!


select z1,z2 from t where id=1
--再读,惊奇发现
z1=10,z2=20

--如果刚才是修改z2,那么其他事务提交的修改z2将被丢失!


从某种角度来说,已经不能算重复读了。
当然你还是可以强制用LOCK IN SHARE MODE来实现类似sqlserver repeat read时的读共享锁。

这个实现不能说不好,只能说有些另类。
加上他自己的ndbcluster也只支持read commit级别,所以还是建议修改一下。

配置文件修改
[mysqld]
transaction-isolation = READ-COMMITTED
 
或者用mysqld命令行参数
 --transaction-isolation=READ-COMMITTED

--查看当前与全局事务级别

select @@tx_isolation , @@global.tx_isolation;


而当有并发问题时,可以通过 FOR UPDATE or LOCK IN SHARE MODE来自己控制。




你可能感兴趣的:(oracle,sql,mysql,server,事务)