Mysql 未能在Quill中使用事务插入一对多关系对象
我有一个人表和动物表,动物表中有FK to personId,因为它们之间有一对多的关系 我只想创建一个人,并使用事务创建它的动物,因为我希望这个过程是原子的(如果我不能创建它的动物,数据库中就没有人的用处) 这是我如何接受人员创建请求的模型:Mysql 未能在Quill中使用事务插入一对多关系对象,mysql,sql,scala,quill.io,Mysql,Sql,Scala,Quill.io,我有一个人表和动物表,动物表中有FK to personId,因为它们之间有一对多的关系 我只想创建一个人,并使用事务创建它的动物,因为我希望这个过程是原子的(如果我不能创建它的动物,数据库中就没有人的用处) 这是我如何接受人员创建请求的模型: case class PersonCreateRequest(name: String, age: Int, animals: Seq[AnimalCreateRequest]) 以下是DB认识一个人的方式: case class Person(per
case class PersonCreateRequest(name: String, age: Int, animals: Seq[AnimalCreateRequest])
以下是DB认识一个人的方式:
case class Person(personId: Long, name, age: Int)
// this is just a companion object to help me take a PersonCreateRequest and make it Person
object Person {
def apply(person: PersonCreateRequest): Person = {
Person(0L,
person.name,
person.age)
}
}
和我对动物的看法一样:
case class AnimalCreateRequest(animalType: String, age: Int)
这是db了解动物的方式(personId=所有者):
所以现在我试着这么做(但失败了):
lazy val ctx = new MysqlAsyncContext(CamelCase, "ctx")
import ctx._
def insertPerson(personToCreate: PersonCreateRequest): Future[Long] = {
// getting the person object that the db knows
val dbPerson = Person.apply(personToCreate)
// INSERT Person Query
val insertPersonQuery = quote {
query[Person].insert(lift(dbPerson)).returning(_.personId)
}
ctx.transaction { implicit ec =>
for {
personId <- ctx.run(insertPersonQuery)
contactIds <- {
Future.sequence(
personToCreate.animals.map(animal => {
val animalToInsert = Animal.apply(animal, personId)
insertAnimal(animalToInsert)
})
)
}
} yield personId
}
}
def insertAnimal(animal: Animal): Future[Long] = {
val q = quote {
query[Animal].insert(lift(animal)).returning(_.animalId)
}
ctx.run(q)
}
lazy val ctx=new MysqlAsyncContext(CamelCase,“ctx”)
进口ctx_
def insertPerson(personToCreate:PersonCreateRequest):未来[Long]={
//获取数据库知道的person对象
val dbPerson=Person.apply(personToCreate)
//插入人员查询
val insertPersonQuery=报价单{
查询[Person].insert(lift(dbPerson)).returning(u.personId)
}
ctx.transaction{implicit ec=>
为了{
personId将隐式ExecutionContext
参数添加到insertAnimal
方法:
def insertAnimal(animal: Animal)(implicit ec: ExecutionContext): Future[Long] =
如果没有它,您将无法从事务块传递ec,动物插入将尝试使用池中的其他连接。您熟悉吗
要从事务中获取结果,您应该将onSuccess
处理程序添加到从ctx.transaction
调用返回的Future
:
ctx.transaction { ...
}.onSuccess {
case personId => ...
}
问题是,目前Quill async不支持事务内部的并发操作
因此必须按顺序插入动物:
ctx.transaction { implicit ec =>
for {
personId <- ctx.run(insertPersonQuery)
animals = personCreate.animals.map(Animal.apply(personId, _))
_ <- animals.foldLeft(Future.successful(0l)) {
case (fut, animal) =>
fut.flatMap(_ => insertAnimal(animal))
}
} yield personId
}
ctx.transaction{implicit ec=>
为了{
拟人插入动物(动物))
}
}屈服人格
}
此外,更好的方法是使用批插入:)
感谢@fwbrasil和@mentegy的帮助!请添加有关您所遇到错误的更多信息。@mixel发生的情况是,我没有得到回复…(添加到问题中)这是你处理这项任务的方式吗?我是这个图书馆的新手。为什么?我想把未来还给controllerOk,然后把它还给控制器处理。你写了“它一直在处理,没有返回任何东西或抛出错误”。那么这是什么意思呢?在我的控制器中,我有这样一个:peopleDao.insertPerson(personToCreate.map{personId=>Ok(s“personId:$personId”)
这应该行得通,我只是没有得到答案……我真的想弄清楚到底发生了什么:/你应该添加最小但完整的示例来重现你的问题。这可能是http服务器库配置或其他方面的问题。你能在GitHub上创建示例项目吗?如果我导入导入,为什么我需要它scala.concurrent.ExecutionContext.Implicits.{global=>ec}
,它不允许我同时拥有这两个:/如果您想在事务中执行查询,它们必须使用调用事务方法后隐式获得的ec。如果insertAnimal
使用全局ec,那么这些插入将在事务之外运行。
ctx.transaction { implicit ec =>
for {
personId <- ctx.run(insertPersonQuery)
animals = personCreate.animals.map(Animal.apply(personId, _))
_ <- animals.foldLeft(Future.successful(0l)) {
case (fut, animal) =>
fut.flatMap(_ => insertAnimal(animal))
}
} yield personId
}