1. Bun ORM là gì?

Bun là một thư viện ORM và SQL query builder dành cho Go, được thiết kế để làm việc với các cơ sở dữ liệu quan hệ như PostgreSQL, MySQL, SQLite và một số hệ quản trị khác thông qua driver tương ứng. Bun giúp developer ánh xạ dữ liệu giữa database và các Go struct, xây dựng câu truy vấn bằng API Go, thực hiện CRUD, quản lý quan hệ giữa các model và xử lý transaction.

Ví dụ, thay vì viết SQL thủ công:

SELECT id, name, email
FROM users
WHERE active = true
ORDER BY created_at DESC;

Có thể dùng Bun:

var users []User

err := db.NewSelect().
    Model(&users).
    Where("active = ?", true).
    OrderExpr("created_at DESC").
    Scan(ctx)

Bun xây dựng và thực thi truy vấn, sau đó ánh xạ kết quả vào slice users.

2. Bun hoạt động như thế nào?

Bun có thể được nhìn nhận qua ba thành phần chính:

  • Model: Go struct đại diện cho dữ liệu trong database.
  • Query builder: API Go dùng để xây dựng câu lệnh SQL.
  • Database execution: thực thi SQL thông qua driver và ánh xạ kết quả trở lại Go struct.

Luồng xử lý thường diễn ra như sau:

  1. Developer định nghĩa model bằng Go struct.
  2. Bun sử dụng metadata và các tag để xác định bảng, cột và quan hệ.
  3. Query builder xây dựng câu SQL từ các điều kiện đã khai báo.
  4. Database driver gửi truy vấn đến database.
  5. Bun nhận kết quả và ánh xạ các cột vào struct.

3. Khai báo Model và ánh xạ bảng

Model là nền tảng để Bun biết cách ánh xạ giữa struct Go và bảng database.

Ví dụ:

type User struct {
    bun.BaseModel `bun:"table:users,alias:u"`

    ID        int64     `bun:"id,pk,autoincrement"`
    Name      string    `bun:"name,notnull"`
    Email     string    `bun:"email,notnull"`
    IsActive  bool      `bun:"is_active,notnull,default:true"`
    CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
}

Các thành phần quan trọng:

  • table:users: xác định bảng users.
  • alias:u: khai báo alias u để dùng trong truy vấn.
  • pk: đánh dấu khóa chính.
  • autoincrement: khai báo cột tự tăng theo cấu hình database.
  • notnull: mô tả cột không được nhận NULL.
  • default:...: mô tả giá trị mặc định.
  • nullzero: điều khiển cách Bun xử lý giá trị zero trong một số thao tác mapping và ghi dữ liệu.

bun.BaseModel cung cấp metadata về bảng và alias. Với model có nhu cầu phức tạp hơn, có thể sử dụng tag bổ sung hoặc cấu hình quan hệ tương ứng.

4. Quan hệ giữa các Model

Belongs To

Ví dụ mỗi bài viết thuộc về một người dùng.

type User struct {
    bun.BaseModel `bun:"table:users,alias:u"`

    ID   int64  `bun:"id,pk,autoincrement"`
    Name string `bun:"name,notnull"`
}

type Post struct {
    bun.BaseModel `bun:"table:posts,alias:p"`

    ID     int64  `bun:"id,pk,autoincrement"`
    UserID int64  `bun:"user_id,notnull"`
    Title  string `bun:"title,notnull"`

    Author *User `bun:"rel:belongs-to,join:user_id=id"`
}

Quan hệ này mô tả posts.user_id tham chiếu đến users.id. Database vẫn nên có foreign key nếu nghiệp vụ cần bảo vệ tính toàn vẹn tham chiếu.

Has Many

Một người dùng có nhiều bài viết:

type User struct {
    bun.BaseModel `bun:"table:users,alias:u"`

    ID    int64  `bun:"id,pk,autoincrement"`
    Name  string `bun:"name,notnull"`
    Posts []Post `bun:"rel:has-many,join:id=user_id"`
}

5. Transaction – Quản lý giao dịch

Transaction giúp nhóm nhiều thao tác database thành một đơn vị nghiệp vụ.

Ví dụ, tạo đơn hàng và các dòng sản phẩm cần được thực hiện nhất quán. Nếu một thao tác thất bại, các thay đổi trước đó nên được rollback.

err := db.RunInTx(ctx, nil, func(
    ctx context.Context,
    tx bun.Tx,
) error {
    order := &Order{
        UserID: 1,
        Status: "PENDING",
    }

    if _, err := tx.NewInsert().
        Model(order).
        Exec(ctx); err != nil {
        return err
    }

    item := &OrderItem{
        OrderID:  order.ID,
        ProductID: 10,
        Quantity:  2,
    }

    if _, err := tx.NewInsert().
        Model(item).
        Exec(ctx); err != nil {
        return err
    }

    return nil
})

if err != nil {
    return err
}

Đây là ví dụ minh họa. Các model Order và OrderItem cần được khai báo tương ứng với schema thật; nếu ID được sinh từ database, cần bảo đảm nó đã được đọc về trước khi sử dụng. Khi callback trả về lỗi, transaction được rollback; khi callback thành công, Bun hoàn tất transaction theo cơ chế của thư viện.

6. Tổng kết

Bun là thư viện ORM và SQL query builder cho Go, giúp làm việc với database quan hệ thông qua Go struct và API truy vấn.

Bài viết khác

Positive vs Negative Testing(Kiểm thử tích cực và Kiểm thử tiêu cực)

1.Positive vs Negative Testing là gì? Trong ngành công nghệ phần mềm, chất lượng sản phẩm không bao giờ là một khái niệm đơn chiều. Một ứng dụng được lập trình hoàn hảo trên lý thuyết vẫn có thể sụp đổ hoàn toàn ngay trong ngày đầu tiên phát hành nếu nó chỉ được chuẩn […]

State Transition Testing(Kiểm thử chuyển đổi trạng thái)

1.State Transition Testing là gì? Trong các hệ thống phần mềm doanh nghiệp hiện đại, phần lớn các ứng dụng không hoạt động một cách tĩnh (static) mà mang tính động (dynamic) mạnh mẽ. Trạng thái phản hồi của một hệ thống tại một thời điểm không chỉ phụ thuộc vào đầu vào hiện tại, […]

JSON Serialization / Deserialization

       JSON, viết tắt của JavaScript Object Notation, là một trong những định dạng được sử dụng phổ biến nhất hiện nay nhờ cấu trúc đơn giản, dễ đọc và được hỗ trợ bởi hầu hết các ngôn ngữ lập trình. Hai thao tác quan trọng khi làm việc với JSON là serialization […]

REST API & HTTP

        Trong quá trình phát triển của công nghệ thông tin, nhu cầu kết nối các ứng dụng, thiết bị và dịch vụ ngày càng trở nên quan trọng. Một ứng dụng hiện đại hiếm khi hoạt động hoàn toàn độc lập. Ứng dụng di động cần trao đổi dữ liệu với […]

PostgreSQL / MySQL

  1. PostgreSQL và MySQL là gì? PostgreSQL và MySQL là hai hệ quản trị cơ sở dữ liệu quan hệ (Relational Database Management System – RDBMS) được sử dụng phổ biến trong phát triển phần mềm. Cả hai đều cho phép lưu trữ, tổ chức, truy vấn và quản lý dữ liệu bằng SQL. […]

OpenAPI / Swagger

1. OpenAPI / Swagger là gì? OpenAPI và Swagger là những khái niệm thường gặp khi phát triển backend và REST API. Chúng giúp lập trình viên mô tả, tài liệu hóa và kiểm thử API một cách rõ ràng hơn, từ đó thuận tiện cho việc phát triển, bảo trì và phối hợp giữa […]

Leave a Reply

Your email address will not be published. Required fields are marked *