问题描述
我有这样的插入方法(权重是索引)
I have insert method like this (weight is index)
implicit def run[A](action: DBIOAction[A, NoStream, _ <: slick.dbio.Effect]): Future[A] = {
db.run(action)
}
def insert(newCategory: CategoryExtractor): Future[Either[String, CategoryResponse]] = {
category.map(_.weight).max.result.flatMap {
case Some(weight) =>
val temp = newCategory.copy(weight = weight+1)
(category += temp).andThen(DBIO.successful(Right(toCategoryExtractor(temp))))
case None =>
val temp = newCategory.copy(weight = 1)
(category += temp).andThen(DBIO.successful(Right(toCategoryExtractor(temp))))
}
}
我称之为 2 次p>
and I call it 2 time
insert(CategoryExtractor("1", "name", "scala every where", 0, 0, 0, None)) onComplete {
case Success(data) => println(data)
}
insert(CategoryExtractor("2", "name", "haskell every where", 0, 0, 0, None)) onComplete {
case Success(data) => println(data)
}
它返回异常(唯一索引).
and it return exception(Unique index).
如何解决这个问题,我不使用 for-comprehension 或插入第一个 onComplete.只需调用 2 次.
How to fix this and I don't use for-comprehension or insert in first onComplete. Just call it 2 time.
谢谢.
推荐答案
这是一个常见的错误 - 转换为 Future
到早期(换句话说,调用 db.run(...)
到早期).
That is a common mistake - converting to Future
to early (in other words calling db.run(...)
to early).
您需要做的是删除此方法,因为它(可能有点不直观)弊大于利:
What you need to do is to remove this method as it (maybe a little unintuitively) brings more harm than good:
implicit def run[A](action: DBIOAction[A, NoStream, _ <: slick.dbio.Effect]): Future[A] = {
db.run(action)
}
经验法则基本上是您通常希望严格控制实际的数据库交互(和事务边界),因此我建议不要在该领域使用任何类型的隐式
.毕竟这是这个库背后的驱动思想之一 - Slick
试图在应用程序和数据库之间的交互中非常明确(与经典 ORM 相反 - 使用访问器可能实际上触发了对 db 或通过 mutator 设置值可能会导致实际的数据库更新).
Rule of thumb is basically that you usually would like to strictly control you actual database interactions (and transactional boundaries) so I would advice against any kind of implicit
s in this area. After all it's one of the driving ideas behind this library - Slick
tries to be very explicit in your interactions between application and db (contrary to classic ORMs - where using accessor might have actually fired lazy call to db or setting a value through mutator might resulted in actual database update).
然后你需要把返回类型改成这个(把Future
改成DBIO
):
Then you need to change the return type to this (changed Future
to DBIO
):
def insert(newCategory: CategoryExtractor): DBIO[Either[String, CategoryResponse]] = {
...
}
然后你这样做:
val firstInsert = insert(CategoryExtractor("1", "name", "scala every where", 0, 0, 0, None)) map {
data => println(data)
}
val secondInsert = insert(CategoryExtractor("2", "name", "haskell every where", 0, 0, 0, None)) map {
data => println(data)
}
db.run(DBIO.seq(firstInsert, secondInsert).transactionally))
基本上问题是:一旦您将 DBIO
转换为 Future
,您就失去了将操作捆绑到单个事务中的能力.所以您基本上使用不同的 DBIO 转换(通常的东西:map
、flatMap
、seq
等)来做所有事情,并且只作为你触发的最后一步db.run(yourComposedDbio.transactionally)
.
Basically the thing is: as soon as you convert DBIO
to Future
you loose capability of bundling actions into single transaction. So you basically do everything with use of different transformations of DBIO (usual stuff: map
, flatMap
, seq
etc) and only as the very last step you fire db.run(yourComposedDbio.transactionally)
.
以下是我几周前的演示文稿中有关处理事务和 DBIO
组合的更多信息.相关幻灯片:http://slides.com/pdolega/slick-101#/85(以及更多).
Here is some more information about handling transactions and DBIO
composition from the presentation I gave couple of weeks ago. Relevant slide: http://slides.com/pdolega/slick-101#/85 (and further).
还有一个由 Dave Gurnell 主持的很棒的研讨会,他在 01:05:00 左右谈到了这个问题(链接在这里:https://vimeo.com/148074461 )
Also there is a great workshop run by Dave Gurnell where he talks about this at around: 01:05:00 (link here: https://vimeo.com/148074461 )
这篇关于如何在 slick 中使用事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!