如何避免嵌套事务

时间:2013-01-21 18:10:06

标签: database-design sqlite relational-database

我目前正在实现一些依赖于SQLite数据库的功能。在这样做的同时,我遇到了一个我没想到的限制。这让我想知道我是否正确地解决了我的问题。我希望有人能提出一种考虑到要求的不同方法。

目标

目标是尽可能快地将大量对象存储到数据库中。但是,如果在任何时候确定不应该存储这些对象,则操作不应对数据库产生任何影响。确切的存储查询('插入')取决于先前的插入。

使用案例

考虑一个非常大的'实例信息包'集合,每个包代表一些相应抽象实例的知识的一部分。因此,总集合代表了一个或多个抽象实例的完整知识。每个包的信息包括:

  1. 一个instance_id;用于唯一标识此信息所涉及的抽象实例。
  2. 属性图; (attribute_uri,attribute_value)-pairs其中attribute_uri唯一标识属性,attribute_value是对应的文本值。
  3. 在表中找到instance_id和attribute_id,分别为TBL_INSTANCES和TBL_ATTRIBUTES。这里使用的数据库模型是EAV模型。

    插入后,表格TBL_ENTRIES应包含以下格式的条目:

    [ entry_id | instance_id | attribute_id | attribute_value ]
    

    问题

    实施似乎很简单:

    1. 设置保存点
    2. 开始交易
    3. 为TBL_ENTRIES
    4. 中的许多插入准备语句
    5. 对于集合中的每个实例:
      • 4.1。在TBL_INSTANCES中查找instance_id。如果不存在,请将其添加到TBL_INSTANCES
      • 4.2。对于实例的属性映射中的每个属性:
        • 4.2.1。在TBL_ATTRIBUTES中查找attribute_id。如果不存在,请将其添加到TBL_ATTRIBUTES。
        • 4.2.2。添加条目到TBL_ENTRIES
    6. 如果在任何时候发生错误,请回滚到保存点,否则提交。
    7. 不幸的是,在查找步骤(4.1和4.2.1)中,SQLite报告“无法在事务中启动事务”错误。阅读文档,似乎是查找调用sqlite3_exec例程的事实,除非我错了,似乎在内部设置了一个事务。

      问题

      如果不允许嵌套事务,我应该如何执行查找步骤(基本上是“INSERT OR REPLACE”表达式后跟“SELECT”查询)?有没有办法避免它们或在当前事务中使用sqlite3_exec?如果没有,我是否以错误的方式处理我的问题?也许我不应该使用单独的整数作为键,例如直接使用attribute_uri作为键,而不是查找相应的attribute_id。

      在任何情况下,我仍然需要在事务期间做一些相同的事情,因为真正的速度增益在于准备实例集合上的语句,而不是属性集合:实例可能只有一个或两个属性,而实例集合中的实例数总是非常大。

      我正在使用C / C ++,SQLite 3.7。

      对我的方法有任何建议或评论,我们非常感谢!

1 个答案:

答案 0 :(得分:5)

来自SQLite documentation on BEGIN TRANSACTION

  

使用BEGIN ... COMMIT创建的事务不会嵌套。对于嵌套   事务,使用SAVEPOINT和RELEASE命令

我似乎记得嵌套事务应该已经存在于任何SQLite 3.7。*。