原始 SQL 执行

概述

在某些场景下,我们可能需要直接执行 SQL 语句而不是通过 XML 配置。Juice 提供了简单的 API 来支持这种需求。

基础用法

最简单的方式是使用 engine.Raw() 方法:

var engine *juice.Engine

// 执行查询并获取结果
rows, err := engine.Raw("SELECT * FROM user WHERE id = #{id}").
    Select(context.TODO(), juice.H{"id": 1})

结果集映射

Juice 提供了多种方式来映射查询结果到 Go 结构体:

// 定义数据结构
type User struct {
    ID   int64  `column:"id"`
    Name string `column:"name"`
}

// 创建查询
runner := engine.Raw("SELECT id, name FROM user WHERE id = #{id}")

// 方式 1: 直接绑定到切片
users, err := juice.NewGenericRunner[[]User](runner).
    Bind(context.TODO(), juice.H{"id": 1})
// users 类型为 []User

// 方式 2: 使用 List 方法
users, err := juice.NewGenericRunner[User](runner).
    List(context.TODO(), juice.H{"id": 1})
// users 类型为 []User

// 方式 3: 使用 List2 方法(返回指针切片)
users, err := juice.NewGenericRunner[User](runner).
    List2(context.TODO(), juice.H{"id": 1})
// users 类型为 []*User

事务支持

在事务中执行原始 SQL 同样简单:

var engine *juice.Engine

// 开启事务
tx := engine.Tx()
if err := tx.Begin(); err != nil {
    // 处理错误
}

// 在事务中执行查询
runner := tx.Raw("SELECT id, name FROM user WHERE id = #{id}")
// 后续用法与非事务相同

// 别忘了提交或回滚事务
if err := tx.Commit(); err != nil {
    tx.Rollback()
}

注意事项

  • 参数绑定使用 #{paramName} 语法

  • 记得正确处理事务的提交和回滚

sql.DB 执行

当 engine 成功初始化之后,可以通过 engine.DB() 获取到底层的 sql.DB 对象。

我们可以通过 DB.Exec()DB.Query() 方法来执行 SQL 语句。

那么它跟上面的 engine.Raw() 方法有什么区别?

engine.DB().Query("SELECT id, name FROM user WHERE id = ?", 1)
engine.Raw("SELECT id, name FROM user WHERE id = {id}").Select(context.TODO(), juice.H{"id": 1})
  • engine.Raw() 可以屏蔽底层驱动占位符的差异,而 DB.Exec()DB.Query() 需要开发者手动指定占位符。

  • engine.Raw() 会走中间件,而 DB.Exec()DB.Query() 不会走。