删除记录时在 ScalarDB 中获取 InvalidUsageException
Getting InvalidUsageException in ScalarDB when deleting a record
我正在使用在 Cassandra
上提供 ACID 功能的 ScalarDB。删除记录时,出现 com.scalar.db.exception.transaction.InvalidUsageException: the record to be deleted must be existing and read beforehand
异常。
我正在从几个表中删除条目(因此使用 Scalar 来提供 Atomocity)。我在开始时创建了一个 DistributedTransaction
然后开始删除条目。
def deleteQuestion(questionKey:PracticeQuestionKeys,user:User) = {
logger.trace(s"delete question request ${questionKey}, ${user}")
val transaction = transactionService.start
val questionGetResult = getQuestionFromQuestionID(transaction,questionKey)//
if(questionGetResult.isLeft) throw questionGetResult.left.get
val question = questionGetResult.right.get
deleteQuestionIfUserIsAuthorized(transaction,questionKey, question, user)
deleteQuestionTagFromTagRepository(transaction,question)
deleteQuestionFromProfileAndPortfolio(transaction, question, user.id)
commitTransaction(transaction)
}
commitTransaction
之前的所有步骤似乎都没有问题,但 `commitTransaction 因错误而失败
2020-08-02 13:19:12,883 [WARN] from com.scalar.db.transaction.consensuscommit.CommitHandler in scala-execution-context-global-141 - preparing records failed
com.scalar.db.exception.transaction.InvalidUsageException: the record to be deleted must be existing and read beforehand
at com.scalar.db.transaction.consensuscommit.PrepareMutationComposer.add(PrepareMutationComposer.java:89)
at com.scalar.db.transaction.consensuscommit.PrepareMutationComposer.add(PrepareMutationComposer.java:45)
at com.scalar.db.transaction.consensuscommit.Snapshot.lambda$to(Snapshot.java:134)
at java.util.concurrent.ConcurrentHashMap$EntrySetView.forEach(ConcurrentHashMap.java:4795)
at com.scalar.db.transaction.consensuscommit.Snapshot.to(Snapshot.java:130)
at com.scalar.db.transaction.consensuscommit.CommitHandler.prepareRecords(CommitHandler.java:104)
at com.scalar.db.transaction.consensuscommit.CommitHandler.commit(CommitHandler.java:40)
at com.scalar.db.transaction.consensuscommit.ConsensusCommit.commit(ConsensusCommit.java:121)
at services.QuestionsTransactionDatabaseService.commitTransaction(QuestionsTransactionDatabaseService.scala:251)
at services.QuestionsTransactionDatabaseService.deleteQuestion(QuestionsTransactionDatabaseService.scala:388)
at services.QuestionsTransactionService.$anonfun$deleteQuestion(QuestionsTransactionService.scala:57)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
at scala.concurrent.Future$.$anonfun$apply(Future.scala:653)
at scala.util.Success.$anonfun$map(Try.scala:251)
at scala.util.Success.map(Try.scala:209)
at scala.concurrent.Future.$anonfun$map(Future.scala:287)
at scala.concurrent.impl.Promise.liftedTree1(Promise.scala:29)
at scala.concurrent.impl.Promise.$anonfun$transform(Promise.scala:29)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:140)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
参考https://scalardl.readthedocs.io/en/latest/trouble-shooting-guide/,好像是不允许盲删的。但是我尝试在删除之前执行 get
并且还尝试设置 DeleteIfExists
之类的条件,但我仍然遇到错误。
def delete(transaction:DistributedTransaction,key:PracticeKeys) = {
logger.trace("Deleting question. Checking if question exists for" + key)
get(transaction,key) //I have tried with and without commenting getting/reading question before deleting
//Perform the operations you want to group in the transaction
val pKey = new Key(new TextValue("id", key.id.toString))
logger.trace(s"created question keys ${pKey}")
logger.trace(s"getting question using ${keyspaceName}, ${tablename}")
val deleteToken:Delete = new Delete(pKey)
.forNamespace(keyspaceName)
.forTable(tablename)
.withCondition(new DeleteIfExists)
transaction.delete(deleteToken)
}
为什么我必须 get
一条记录才能删除它?有什么方法可以直接删除?我没有正确使用库吗?
事实证明,问题出在我的代码中。首先,我们必须在 delete
之前先执行 get
。我不知道为什么,但这似乎是规则。
所以我在每个delete
中添加了一个get
def delete(transaction:DistributedTransaction,questionKey:QuestionsCreatedByAUserForATagKeys) = {
logger.trace(s"deleting question created for tag with key ${questionKey}")
get(transaction,questionKey) // <-- HERE. I should probably also check if get returned a valid record.
val pQuestionsCreatedKey = new Key(
new TextValue("question_creator", questionKey.creator.creatorId.toString),
new TextValue("tag", questionKey.tag)
)
val cQuestionKey = if(questionKey.creationMonth !=0 && questionKey.creationYear !=0 && questionKey.questionId.isDefined){
new Key(
new BigIntValue("creation_year", questionKey.creationYear),
new BigIntValue("creation_month", questionKey.creationMonth),
new TextValue("question_id", questionKey.questionId.get.toString),
)
} else {
throw CannotDeleteWithoutEntireCompositeKeyException()
}
logger.trace(s"deleting question with keys ${pQuestionsCreatedKey},${cQuestionKey}")
val deleteToken = new Delete(pQuestionsCreatedKey,cQuestionKey)
.forNamespace(keyspaceName)
.forTable(tablename)
.withCondition(new DeleteIfExists)
logger.trace(s"deleting from user profile ${deleteToken}")
transaction.delete(deleteToken)
}
尽管之前添加了 get
,但我还是收到异常的原因是编程问题(正确分配变量时的错误)。假设删除是为了记录 A
,但我没有正确存储 A
,而是将其存储为 A1
。所以 get
实际上失败了。
一般来说,我认为这个错误是指被删除的记录不存在。
我正在使用在 Cassandra
上提供 ACID 功能的 ScalarDB。删除记录时,出现 com.scalar.db.exception.transaction.InvalidUsageException: the record to be deleted must be existing and read beforehand
异常。
我正在从几个表中删除条目(因此使用 Scalar 来提供 Atomocity)。我在开始时创建了一个 DistributedTransaction
然后开始删除条目。
def deleteQuestion(questionKey:PracticeQuestionKeys,user:User) = {
logger.trace(s"delete question request ${questionKey}, ${user}")
val transaction = transactionService.start
val questionGetResult = getQuestionFromQuestionID(transaction,questionKey)//
if(questionGetResult.isLeft) throw questionGetResult.left.get
val question = questionGetResult.right.get
deleteQuestionIfUserIsAuthorized(transaction,questionKey, question, user)
deleteQuestionTagFromTagRepository(transaction,question)
deleteQuestionFromProfileAndPortfolio(transaction, question, user.id)
commitTransaction(transaction)
}
commitTransaction
之前的所有步骤似乎都没有问题,但 `commitTransaction 因错误而失败
2020-08-02 13:19:12,883 [WARN] from com.scalar.db.transaction.consensuscommit.CommitHandler in scala-execution-context-global-141 - preparing records failed
com.scalar.db.exception.transaction.InvalidUsageException: the record to be deleted must be existing and read beforehand
at com.scalar.db.transaction.consensuscommit.PrepareMutationComposer.add(PrepareMutationComposer.java:89)
at com.scalar.db.transaction.consensuscommit.PrepareMutationComposer.add(PrepareMutationComposer.java:45)
at com.scalar.db.transaction.consensuscommit.Snapshot.lambda$to(Snapshot.java:134)
at java.util.concurrent.ConcurrentHashMap$EntrySetView.forEach(ConcurrentHashMap.java:4795)
at com.scalar.db.transaction.consensuscommit.Snapshot.to(Snapshot.java:130)
at com.scalar.db.transaction.consensuscommit.CommitHandler.prepareRecords(CommitHandler.java:104)
at com.scalar.db.transaction.consensuscommit.CommitHandler.commit(CommitHandler.java:40)
at com.scalar.db.transaction.consensuscommit.ConsensusCommit.commit(ConsensusCommit.java:121)
at services.QuestionsTransactionDatabaseService.commitTransaction(QuestionsTransactionDatabaseService.scala:251)
at services.QuestionsTransactionDatabaseService.deleteQuestion(QuestionsTransactionDatabaseService.scala:388)
at services.QuestionsTransactionService.$anonfun$deleteQuestion(QuestionsTransactionService.scala:57)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
at scala.concurrent.Future$.$anonfun$apply(Future.scala:653)
at scala.util.Success.$anonfun$map(Try.scala:251)
at scala.util.Success.map(Try.scala:209)
at scala.concurrent.Future.$anonfun$map(Future.scala:287)
at scala.concurrent.impl.Promise.liftedTree1(Promise.scala:29)
at scala.concurrent.impl.Promise.$anonfun$transform(Promise.scala:29)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:140)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
参考https://scalardl.readthedocs.io/en/latest/trouble-shooting-guide/,好像是不允许盲删的。但是我尝试在删除之前执行 get
并且还尝试设置 DeleteIfExists
之类的条件,但我仍然遇到错误。
def delete(transaction:DistributedTransaction,key:PracticeKeys) = {
logger.trace("Deleting question. Checking if question exists for" + key)
get(transaction,key) //I have tried with and without commenting getting/reading question before deleting
//Perform the operations you want to group in the transaction
val pKey = new Key(new TextValue("id", key.id.toString))
logger.trace(s"created question keys ${pKey}")
logger.trace(s"getting question using ${keyspaceName}, ${tablename}")
val deleteToken:Delete = new Delete(pKey)
.forNamespace(keyspaceName)
.forTable(tablename)
.withCondition(new DeleteIfExists)
transaction.delete(deleteToken)
}
为什么我必须 get
一条记录才能删除它?有什么方法可以直接删除?我没有正确使用库吗?
事实证明,问题出在我的代码中。首先,我们必须在 delete
之前先执行 get
。我不知道为什么,但这似乎是规则。
所以我在每个delete
get
def delete(transaction:DistributedTransaction,questionKey:QuestionsCreatedByAUserForATagKeys) = {
logger.trace(s"deleting question created for tag with key ${questionKey}")
get(transaction,questionKey) // <-- HERE. I should probably also check if get returned a valid record.
val pQuestionsCreatedKey = new Key(
new TextValue("question_creator", questionKey.creator.creatorId.toString),
new TextValue("tag", questionKey.tag)
)
val cQuestionKey = if(questionKey.creationMonth !=0 && questionKey.creationYear !=0 && questionKey.questionId.isDefined){
new Key(
new BigIntValue("creation_year", questionKey.creationYear),
new BigIntValue("creation_month", questionKey.creationMonth),
new TextValue("question_id", questionKey.questionId.get.toString),
)
} else {
throw CannotDeleteWithoutEntireCompositeKeyException()
}
logger.trace(s"deleting question with keys ${pQuestionsCreatedKey},${cQuestionKey}")
val deleteToken = new Delete(pQuestionsCreatedKey,cQuestionKey)
.forNamespace(keyspaceName)
.forTable(tablename)
.withCondition(new DeleteIfExists)
logger.trace(s"deleting from user profile ${deleteToken}")
transaction.delete(deleteToken)
}
尽管之前添加了 get
,但我还是收到异常的原因是编程问题(正确分配变量时的错误)。假设删除是为了记录 A
,但我没有正确存储 A
,而是将其存储为 A1
。所以 get
实际上失败了。
一般来说,我认为这个错误是指被删除的记录不存在。