Neo4j数据库的事务

时间:2021-09-16 18:02:36
1.事务管理
为了保持数据的完整性和保证良好的事务行为,Neo4j也支持ACID特性:
(1).原子性:一整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
(2).一致性:在事务开始之前和事务结束以后,数据库的完整性限制没有被破坏。 
(3).隔离性:两个事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。 
(4).持久性:在事务完成以后,该事务对数据库所作的更改便持久地保存在数据库之中,并不会被回復。 
注意:
(1)所有对Neo4j数据库的数据的修改操作都必须封装在事务里。
(2)默认的isolation level是READ_COMMITTED
(3)遍历返回的数据会受到其他事务的修改操作的影响
(4)有时会出现“不可重复的读”
(5)可以手动为节点和关系添加写锁来获取更高的独立性
(6)在节点和关系层次上,锁是必须要的。
(7)死锁保护已经内置到核心事务管理

1.1   交互作用周期
        所有对图的写操作都必须在事务里执行。事务是线程受限的,而且它可以嵌套成灵活的嵌套事务。灵活的嵌套事务的意思是,嵌套事务会被添加到顶层事务的范围。嵌套事务会引起顶层事务的回滚,即整个事务的回滚。只回滚嵌套事务里所作的修改是不可能的。

事务处理的交互作用周期如下:
1.开始一个事务
2.对图执行写操作
3.标志事务的成功与否
4.结束事务

        结束每一个事务是非常重要的。事务结束后才会解锁和释放它占用的内存。在Neo4j里一般是把事务的代码写在try-finall块里。在try块里的最后一行代码要把事务标志为成功,而finally块则要执行结束事务这个动作。事务的成功状态决定事务结束后是提交还是回滚。
       在使用线程池的环境中,无法正确地结束事务也许会引起其他错误。试想一下,如果一个事务被漏掉,没有正确地结束,它就会捆绑在一个线程里。当轮到那个线程执行时,则会启动一个新的顶层事务。如果这个漏掉的事务的状态是“标志为回滚”(当检测到死锁时就会出现这种状态),则该事务则不能再做任何工作。

1.2  独立程度
        默认情况下,读操作读到的是最近一次提交的值或者是当前事务的修改值。默认的独立程度是READ_COMMITTED,即是读操作是非阻塞的,也不带锁的,所以可以重复地读。要获得更高的独立程度(例如REPETABLE_READ ,SERIALIZABLE)则需要手动添加读写的锁。

1.3  默认的锁
(1)当为一个节点或关系添加,修改或者删除一个属性是,写锁将会自动添加到指定的节点或关系
(2)当创建或者删除节点时,写锁同样会添加到指定的节点
(3)当创建或者删除关系时,写锁将会添加到指定的关系和关系上的节点

事务开始时就会添加锁,直到事务结束时才释放锁。

1.4  死锁
       只要用了锁,就有可能发生死锁。但是,Neo4j会在死锁发生之前检测死锁并抛出异常。在异常抛出之前,事务会被标志为回滚。当事务结束时,事务会释放它所持有的锁。一旦该事务的锁释放了,则该事务的锁所引起的死锁也就是解除,其他事务就可以继续执行。当用户需要时,引起死锁的事务可以重新试着执行。
       遇到频繁的死锁是并发写请求因事务的独立性和一致性而不能同时执行的迹象。解决办法是保证并发更新以一种合理的方式进行。例如,有两个给定的节点A,B,在每个事务里给这些节点以任意顺序添加或删除关系会导致死锁。一个解决办法是保证更新时总是以相同的顺序来更新(先A然后B)。另一个解决办法是确保每个线程或事务和其他并发事务没有对节点或关系的写冲突。可以考虑一下用单一线程完成一种特定类型的更新操作。

注意:

       除了Neo4j管理着的锁,如果你还使用了其他同步方法的话,死锁仍然会发生。除了特别声明的之外,Neo4j的API的所有操作都是线程安全的,在对Neo4j数据库的操作也就没有必要使用外部的同步方法。其他代码如果需要同步,则它的同步代码块里不能包含任何Neo4j的操作。


PS:翻译得比较生硬,见谅。Neo4j数据库的事务