You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala、Slick与Cats:如何用OptionT映射不同SQL错误?

解决Slick查询中数据库异常的多错误映射问题

你的问题核心在于没分清OptionT处理的是查询结果为空(None)的场景,而数据库的约束异常是在database.run执行时就会触发Future失败,根本不会走到OptionT的流程里。所以不能在.toRight里处理数据库异常,得先在Future层面捕获异常,再处理空值情况。

正确的实现方式

首先定义PostgreSQL约束对应的SQL状态常量(这类错误码是SQL标准定义的,外键约束为23503、唯一约束为23505):

import org.postgresql.util.PSQLException

// PostgreSQL约束错误SQL状态码
val FOREIGN_KEY_CONSTRAINT_VIOLATION = "23503"
val UNIQUE_CONSTRAINT_VIOLATION = "23505"

然后修改方法,分两步处理异常和空值:

def method(): Future[Either[Error, MyCustomDTO]] = {
  database.run(query)
    // 第一步:捕获数据库执行时的异常,映射为自定义Error
    .recover {
      case e: PSQLException =>
        e.getSQLState match {
          case FOREIGN_KEY_CONSTRAINT_VIOLATION => Left(constraintError())
          case UNIQUE_CONSTRAINT_VIOLATION => Left(uniqueError())
          case _ => Left(dataNotFound()) // 其他数据库异常返回通用错误
        }
    }
    // 第二步:处理查询结果的Option,映射为DTO或空值错误
    .flatMap {
      case Some(entity) => Future.successful(Right(MyCustomDTO(entity)))
      case None => Future.successful(Left(dataNotFound()))
    }
}

用OptionT简化链式调用(可选)

如果想保留OptionT的链式风格,可以结合Future的recover和最终结果的异常捕获:

def method(): Future[Either[Error, MyCustomDTO]] = {
  OptionT(
    database.run(query)
      .recover {
        case e: PSQLException =>
          // 将异常转换为自定义Error后抛出,后续在value阶段捕获
          throw e.getSQLState match {
            case FOREIGN_KEY_CONSTRAINT_VIOLATION => constraintError()
            case UNIQUE_CONSTRAINT_VIOLATION => uniqueError()
            case _ => dataNotFound()
          }
      }
  )
    .map(MyCustomDTO(_))
    .toRight(dataNotFound())
    .value
    // 捕获之前抛出的自定义Error,转为Left结果
    .recover { case err: Error => Left(err) }
}

关键说明

  • .toRight(dataNotFound()) 仅处理查询结果为None的场景,和数据库执行异常完全无关;
  • 数据库约束异常属于Future的Failure分支,必须用recover/recoverWith在Future层面捕获;
  • PSQLException是PostgreSQL驱动的特定异常,需确保依赖中包含PostgreSQL驱动包并正确导入。

内容的提问来源于stack exchange,提问作者Developus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 10:16:07