我正在Clojure中构建一个围绕OrientDB的包装器。 OrientDB的最大限制之一(IMHO)是ODatabaseDocumentTx
不是线程安全的,但是从.open()
到.close()
这个事物的生命周期应该代表一个事务,有效地强制事务发生是一个单一的线程。实际上,默认情况下提供了对这些混合数据库/事务对象的线程局部引用。但是,如果我想登录同一个线程,我想要保持“真实”状态呢?如果我遇到错误,日志条目也会回滚!仅使用该用例几乎使我无法使用所有DBMS,因为大多数DBMS都不允许使用命名的事务范围管理。 /肥皂盒
无论如何,OrientDB就是这样,而且对我来说不会改变。我正在使用Clojure,我想要一种优雅的方法来构造with-tx
宏,以便with-tx
体内的所有命令式数据库调用都被序列化。
显然,我可以通过在with-tx
生成的主体的顶层创建一个标记并将每个表单解构为最低级别并将它们包装在同步块中来强制它。这太可怕了,我不确定这会与pmap
之类的东西相互作用。
我可以在宏体中搜索对ODatabaseDocumentTx
对象的调用,并将它们包装在synchronized块中。
我猜可以用代理创建某种调度系统。
或者我可以使用同步方法调用将ODatabaseDocumentTx子类化。
我正试图想出其他办法。思考?一般来说,代理方法似乎更有吸引力,因为如果一个代码块散布着数据库方法调用,我宁愿事先进行所有计算,对调用进行排队,最后只需向DB发送一大堆内容。然而,这假设计算不需要确保读取的一致性。 IDK。
答案 0 :(得分:1)
听起来像是Lamina的工作。
答案 1 :(得分:0)
一种选择是在线程池中使用带有1个线程的Executor。如下所示的东西。你可以围绕这个概念创建一个漂亮的宏。
(import 'java.util.concurrent.Executors)
(import 'java.util.concurrent.Callable)
(defmacro sync [executor & body]
`(.get (.submit ~executor (proxy [Callable] []
(call []
(do ~@body))))))
(let [exe (Executors/newFixedThreadPool (int 1))
dbtx (sync exe (DatabaseTx.))]
(do
(sync exe (readfrom dbtx))
(sync exe (writeto dbtx))))
sync
宏确保在执行程序(只有一个线程)中执行正文表达式,并等待操作完成,以便所有操作逐个执行。