系统事务隔离:
事务隔离的原因:脏读:一事务回滚,一事务执行。 不可重复读与幻想读:二个事务交叉,不涉及回滚。 要改变在一个事务执行的过程中,不受其它事务影响的思路,要认为影响程度是由事务隔离的级别来决定。
事务的隔离级别产生的原因就是为了避免当前事务的sql立刻执行影响到其它事务.隔离很好理解,就是事务对保护区域的控制。为了可伸缩性,一般尽量限制事务的保护区域。最严格的也是最好理解的例子就是可串行化级别,将并发的事务强制为线性顺序执行的事务,当然会解决对应用影响不大的幻读,注意,由于是顺序执行事务,就不能再理解为“阻止其它事务”。因为当前访问数据的就只有一个事务。我以前一直认为序列化会将整个表锁定来“阻止其它事务写入或删除”而导致的幻读。看来完全错误,没有好好理解序列化的意思。串行化付出的性能损失是巨大的。
通常的思考方式是先假定没有事务隔离级别存在的情况下,hibernate中的session.flush()或jdbc中的executeQuery(sql)/executeUpdate(sql)会修改共享记录集而影响到其它事务。然后,我们可以针对这些影响采取适当的隔离级别。注意没有commit之前,并没有持久化到库里。随时可以回滚,脏读就是由于一个系统事务读到另一个系统事务回滚之前的数据导致的。一定要注意到虽然事务没有提交,但事务里的sql集已经修改了共享记录集。
注意
1.脏读由于涉及到事务的回滚,所以,需要con.setAutoCommit(false);而重复读,幻读不涉及事务回滚,所以不用调用该语句。
2.JDBC的事务执行sql除非使用batch,一般会立即更新到数据库里:
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:demo" , "scott" , "tiger");
PreparedStatement ps = conn.prepareStatement("insert into dept2 values(? , ? , ?)");
ps.setInt(1, 21);
ps.setString(2, "s1");
ps.setString(3, "s2");
ps.addBatch();
ps.setInt(1, 21);
ps.setString(2, "s3");
ps.setString(3, "s4");
ps.addBatch();
ps.setInt(1, 21);
ps.setString(2, "s5");
ps.setString(3, "s6");
ps.addBatch();
ps.executeBatch();
ps.close();
conn.close();
3.hibernate执行sql有点复杂。
首先如果session的FLUSHMODE=auto.那么会在其它query执行之前,手动调用flush之前,事务commit之前,调用flush,进而执行sql.
总之,通过session.flush()最终会执行sql(sql哪里构造的,具体看hibernate的代码吧,举个例子应该在session.update(object)与session.flush()之间。flush报sql语句错误,那可能的原因是update的object有问题。另一个是在flush之前,清空了object,这样也会导致sql有问题)。
hibernate执行flush后只是将Hibernate缓存中的数据提交到数据库,如果这时数据库处在一个事物当中,[则数据库将这些SQL语句缓存起来],当Hibernate进行commit时,会告诉数据库,你可以真正提交了,这时数据才会永久保存下来,也就是被持久化了.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
二个事务在操作同一个共享记录集时,可能会出现的问题:(A)脏读 (B)不可重复读 (C)幻读
JDBC的隔离级别(1)read-uncommit, (2)read-commit, (3)read-repeatable, (4)read-serializable都是用来阻止上面的问题的。
(1)什么都阻止不了。
(2)阻止(A)
(3)阻止(A)(B)
(4)阻止(A)(B)(C)
(1)->(4)隔离级别越高,性能损失越大。