Scala 如何捕获重复键值冲突的光滑postgres异常
我的表在我的postgresql数据库中的一对列上有一个唯一的索引 我想知道如何在插入时捕获重复密钥异常:Scala 如何捕获重复键值冲突的光滑postgres异常,scala,playframework,slick,Scala,Playframework,Slick,我的表在我的postgresql数据库中的一对列上有一个唯一的索引 我想知道如何在插入时捕获重复密钥异常: def save(user: User)(implicit session: Session): User = { val newId = (users returning users.map(_id) += user user.copy(id = newId) } 我的日志显示此异常: Execution exception[[PSQLException: ERROR: dup
def save(user: User)(implicit session: Session): User = {
val newId = (users returning users.map(_id) += user
user.copy(id = newId)
}
我的日志显示此异常:
Execution exception[[PSQLException: ERROR: duplicate key value violates unique constraint "...."
我在scala中也没有太多使用异常。您的
save
方法可能会返回与User
不同的结果,以指示失败的可能性。如果将抛出的唯一异常是unique key,并且您实际上只关心成功或失败(而不关心失败的类型),那么一种方法是返回选项[User]
您可以使用一个简单的try/catch
块,将成功保存映射到Some[User]
和psqleexception
到None
:
def save(user: User)(implicit session: Session): Option[User] = {
try {
val newId = (users returning users.map(_id) += user
Some(user.copy(id = newId))
} catch {
case PSQLException => None
}
}
就个人而言,我不会这样做,因为try/catch
并不是真正惯用的Scala,您的错误类型被丢弃。下一个选项是使用scala.util.Try
def save(user: User)(implicit session: Session): Try[User] = Try {
val newId = (users returning users.map(_id) += user
user.copy(id = newId)
}
这里的代码更简单。如果Try
的主体成功,则save
将返回Success[User]
,否则将返回包装在Failure
中的异常。这将允许您使用Try
执行许多操作
def save(user: User)(implicit session: Session): Try[User] = Try {
val newId = (users returning users.map(_id) += user
user.copy(id = newId)
}
您可以选择以下模式匹配:
save(user) match {
case Success(user) => Ok(user)
case Failure(t: PSQLException) if(e.getSQLState == "23505") => InternalServerError("Some sort of unique key violation..")
case Failure(t: PSQLException) => InternalServerError("Some sort of psql error..")
case Failure(_) => InternalServerError("Something else happened.. it was bad..")
}
您可以像选项那样使用它:
save(user) map { user =>
Ok(user)
} getOrElse {
InternalServerError("Something terrible happened..")
}
您可以一次将多个组件组合在一起,并在第一次失败时停止:
(for {
u1 <- save(user1)
u2 <- save(user2)
u3 <- save(user3)
} yield {
(u1, u2, u3)
}) match {
case Success((u1, u2, u3)) => Ok(...)
case Failure(...) => ...
}
(用于{
u1在Slick 3.x中,您可以使用asTry
def save(user: User)(implicit session: Session): Try[User] = Try {
val newId = (users returning users.map(_id) += user
user.copy(id = newId)
}
我使用的是MySQL,但是相同的代码可以用于PostgreSQL,只是例外情况不同
import scala.util.Try
import scala.util.Success
import scala.util.Failure
db.run(myAction.asTry).map {result =>
result match {
case Success(res) =>
println("success")
// ...
case Failure(e: MySQLIntegrityConstraintViolationException) => {
//code: 1062, status: 23000, e: Duplicate entry 'foo' for key 'name'
println(s"MySQLIntegrityConstraintViolationException, code: ${e.getErrorCode}, sql status: ${e.getSQLState}, message: ${e.getMessage}")
// ...
}
case Failure(e) => {
println(s"Exception in insertOrUpdateListItem, ${e.getMessage}")
// ...
}
}
}
注意:也可以映射操作(myAction.asTry.map…
)而不是db.run
哇,非常好的信息,谢谢。为了澄清一下,要挑出一个“重复键”,我是否必须解析从消息返回的字符串消息,以确定它是否是重复键?(与其他psqlexeptions相反)。要么这样,要么通过匹配SQL状态。我不使用postgres,所以我不确定这是否100%准确(mysql使用错误代码),但例如case e e:psqleexception if(e.getSQLState==“23505”)=>…
查看此页面:匹配Try to scalaz析取的输出,您可以很好地对方法的契约进行建模。这是一个很好的API,很容易与新手一起使用。问题:隐式会话是什么?类DBResult
和DBStatus
是什么?我在光滑的scalado中没有看到它们这些是我自己的cla我还为我的所有数据库结果使用带有自定义状态代码的结果包装器。我将删除它们以避免混淆。