如何避免嵌套事务

OnM*_*uck 2 sqlite database-design relational-database

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

目标

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

用例

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

  1. instance_id; 用于唯一标识此信息所涉及的抽象实例.
  2. 属性图; (attribute_uri,attribute_value)-pairs其中attribute_uri唯一标识属性,attribute_value是对应的文本值.

instance_id和attribute_id都可以在表中找到,分别是TBL_INSTANCES和TBL_ATTRIBUTES.这里使用的数据库模型是EAV模型.

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

[ entry_id | instance_id | attribute_id | attribute_value ]
Run Code Online (Sandbox Code Playgroud)

问题

实施似乎很简单:

  1. 设置保存点
  2. 开始交易
  3. 为TBL_ENTRIES中的许多插入准备语句
  4. 对于集合中的每个实例:
    • 4.1.在TBL_INSTANCES中查找instance_id.如果不存在,请将其添加到TBL_INSTANCES
    • 4.2.对于实例的属性映射中的每个属性:
      • 4.2.1.在TBL_ATTRIBUTES中查找attribute_id.如果不存在,请将其添加到TBL_ATTRIBUTES.
      • 4.2.2.添加TBL_ENTRIES条目
  5. 如果在任何时候发生错误,则回滚到保存点,否则提交.

不幸的是,在查找步骤(4.1和4.2.1)中,SQLite报告"无法在事务中启动事务"错误.阅读文档,似乎是查找调用sqlite3_exec例程的事实,除非我错了,似乎在内部设置了一个事务.

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

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

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

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

Ant*_*nko 5

关于BEGIN TRANSACTION的SQLite文档:

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

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