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

Quill-JDBC-ZIO适配Oracle 11与12版本的查询生成问题

解决Quill对接不同Oracle版本的SQL兼容问题

核心思路

Quill针对Oracle 11g和12c+提供了不同的方言实现:Oracle11Dialect会生成基于ROWNUM的嵌套查询,Oracle12Dialect则使用FETCH FIRST ... ROWS ONLY语法。我们需要为两个数据库分别创建独立的Quill上下文,绑定对应的方言和数据源,实现版本适配。

具体实现步骤

1. 确认依赖(已使用4.6.0可跳过)

确保build.sbt中包含正确的quill-jdbc-zio依赖,按需添加Oracle JDBC驱动:

libraryDependencies += "io.getquill" %% "quill-jdbc-zio" % "4.6.0"
// Oracle 11g可使用ojdbc6,12c+推荐ojdbc8
libraryDependencies += "com.oracle.database.jdbc" % "ojdbc8" % "12.2.0.1"

2. 创建分版本的Quill上下文

分别为Oracle 11和12定义独立的上下文,指定对应方言并绑定专属数据源:

import io.getquill._
import io.getquill.jdbczio.OracleJdbcZioContext
import zio._
import zio.jdbc._

// Oracle 11g专属上下文:使用Oracle11Dialect生成ROWNUM兼容查询
object Oracle11Context extends OracleJdbcZioContext(Oracle11Dialect) {
  // 绑定Oracle11数据源
  override val dataSourceLayer: ZLayer[Any, Throwable, DataSource] = 
    ZLayer.scoped {
      Jdbc.dataSource(
        JdbcConfig.driverClassName("oracle.jdbc.OracleDriver"),
        JdbcConfig.url("jdbc:oracle:thin:@//oracle11-host:1521/ORCL"),
        JdbcConfig.user("oracle11_user"),
        JdbcConfig.password("oracle11_pass")
      )
    }
}

// Oracle 12c+专属上下文:使用Oracle12Dialect生成FETCH FIRST语法
object Oracle12Context extends OracleJdbcZioContext(Oracle12Dialect) {
  // 绑定Oracle12数据源
  override val dataSourceLayer: ZLayer[Any, Throwable, DataSource] = 
    ZLayer.scoped {
      Jdbc.dataSource(
        JdbcConfig.driverClassName("oracle.jdbc.OracleDriver"),
        JdbcConfig.url("jdbc:oracle:thin:@//oracle12-host:1521/ORCLCDB"),
        JdbcConfig.user("oracle12_user"),
        JdbcConfig.password("oracle12_pass")
      )
    }
}

3. 分上下文执行查询

使用各自的上下文执行查询,Quill会自动生成对应版本兼容的SQL:

// 示例实体类
case class User(id: Int, name: String)

// 针对Oracle11执行查询,生成ROWNUM嵌套SQL
val oracle11Query: ZIO[Any, Throwable, List[User]] = 
  Oracle11Context.run(query[User].take(2))

// 针对Oracle12执行查询,生成FETCH FIRST语法
val oracle12Query: ZIO[Any, Throwable, List[User]] = 
  Oracle12Context.run(query[User].take(2))

4. 生产环境优化:用配置文件管理数据源

避免硬编码连接参数,可通过ZIO Config读取配置文件(如application.conf):

oracle11 {
  url = "jdbc:oracle:thin:@//oracle11-host:1521/ORCL"
  user = "oracle11_user"
  password = "oracle11_pass"
  driver = "oracle.jdbc.OracleDriver"
}

oracle12 {
  url = "jdbc:oracle:thin:@//oracle12-host:1521/ORCLCDB"
  user = "oracle12_user"
  password = "oracle12_pass"
  driver = "oracle.jdbc.OracleDriver"
}

修改上下文读取配置:

import zio.config._
import zio.config.typesafe._

case class DbConfig(url: String, user: String, password: String, driver: String)

// 加载Oracle11配置
val oracle11ConfigLayer: ZLayer[Any, Config.Error, DbConfig] = 
  ZLayer.fromZIO(read(deriveConfig[DbConfig].from(ConfigSource.fromResourcePath.at("oracle11"))))

// 重新定义Oracle11上下文,依赖配置层
object Oracle11Context extends OracleJdbcZioContext(Oracle11Dialect) {
  override val dataSourceLayer: ZLayer[DbConfig, Throwable, DataSource] = 
    ZLayer.scoped {
      for {
        config <- ZIO.service[DbConfig]
        ds <- Jdbc.dataSource(
          JdbcConfig.driverClassName(config.driver),
          JdbcConfig.url(config.url),
          JdbcConfig.user(config.user),
          JdbcConfig.password(config.password)
        )
      } yield ds
    }
}

// Oracle12上下文同理,读取oracle12节点配置

验证效果

  • Oracle11上下文生成的SQL:

SELECT t.* FROM (SELECT id, name FROM USER) t WHERE ROWNUM <= 2

  • Oracle12上下文生成的SQL:

SELECT id, name FROM USER FETCH FIRST 2 ROWS ONLY

这样就能同时兼容两个Oracle版本,避免ORA-00933错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:13:31