ScalikeJDBC – Phần 1

1. Giới thiệu

Như chúng ta đã biết, ScalikeJDBC là một thư viện kết nối cơ sở dữ liệu dành cho ngôn ngữ lập trình Scala. Đây là bộ thư viện tiện dụng, có nhiều tính năng như JDBC API, SQLInterpolation, QueryDSL …. Với mục đích giới thiệu về ScalikeJDBC, xin được viết một số bài tổng hợp những kiến thức thu được trong quá trình tìm hiểu về ScalikeJDBC. Bài mở đầu nói về cách cài đặt ScalikeJDBC với Play2 framework, các phép toán trong ScalikeJDBC, và SQLInterpolation

2. Nội dung

2.1. Cài đặt ScalikeJDBC

Các bước cài đặt chi tiết cho từng trường hợp được tổng hợp tại trang chủ của ScalieJDBC: https://scalikejdbc.org/ . Cụ thể với trường hợp ScalikeJDBC kết hợp với Play2 framework, ta có thể thiết lập plugin ScalikeJDBC như sau
– Thêm ScalikeJDBC vào danh sách dependencies trong file build.sbt, khai báo có dạng

libraryDependencies ++= Seq(
  jdbc,
  cache,
  ws,
  specs2 % Test,
  "mysql" % "mysql-connector-java" % "5.1.24",
  "org.scalikejdbc" %% "scalikejdbc"                  % "2.4.1",
  "org.scalikejdbc" %% "scalikejdbc-config"           % "2.4.1",
  "org.scalikejdbc" %% "scalikejdbc-play-initializer" % "2.5.1"
)
  • Trong file conf/application.conf
#db connection config
db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost:3306/scala_example"
db.default.username=scala
db.default.password="scalapass"

#scalikejdbc config
scalikejdbc.global.loggingSQLAndTime.enabled=true
scalikejdbc.global.loggingSQLAndTime.singleLineMode=false
scalikejdbc.global.loggingSQLAndTime.logLevel=debug
scalikejdbc.global.loggingSQLAndTime.warningEnabled=true
scalikejdbc.global.loggingSQLAndTime.warningThresholdMillis=5
scalikejdbc.global.loggingSQLAndTime.warningLogLevel=warn

#need to enable module scalikejdbc
play.modules.enabled += "scalikejdbc.PlayModule"
  • Sau khi ScalikeJDBC đã sẵn sàng, bước cuối cùng là import scalikejdbc._ tại những nơi cần sử dụng

2.2. Các phép toán trong ScalikeJDBC

Phần sau xin trình bày về các tính năng của ScalikeJDBC thông qua ví dụ áp dụng trên bảng dữ liệu employee(id, name, email)

2.2.1. Phép toán truy vấn (Query)

Các phép toán truy vấn gồm có: single, first, list, foreach
– single()
Truy vấn lấy tên Employee theo id

def getNameById(id: Long)(implicit session: DBSession = AutoSession): Option[String] = SQL("select * from employee where id = {id}")
    .bindByName('id -> id)
    .map { rs => rs.string("name") }
    .single().apply()

Trong đó
SQL(“select * from employee where id = {id}”): khai báo lệnh SQL
.bindByName(‘id -> id): truyền giá trị cho tham số trong lệnh SQL thông qua tên
.map { rs => rs.string(“name”) }: xác định giá trị trả về dựa trên kết quả truy vẫn. Ở đây kết quả trả về cần lấy là trường name trong bản employee, có kiểu String
.single(): lấy ra một bản ghi dữ liệu duy nhất và coi đó là giá trị Option. Trong trường hợp câu truy vấn trả về nhiều bản ghi dữ liệu, hàm single() trả lại runtime exception
.apply(): đơn giản là lệnh thực thi
– first()
Hàm first() trả về giá trị đầu tiên trong kết quả của câu truy vấn có nhiều giá trị trả về, giá trị cũng được coi như dưới dạng Option
Lấy ra email của người đầu tiên trong danh sách Employee

def getEmailOfFirstEmployee()(implicit session: DBSession = AutoSession): Option[String] =
  SQL("select * from employee")
    .map { rs => rs.string("email") }
    .first().apply()
  • list()
    Hàm list() đưa các bộ giá trị trả về thành dạng List (immutable)
    Lấy ra danh sách tên của tất cả employee
def getNameList()(implicit session: DBSession = AutoSession): List[String] =
  SQL("select * from employee")
    .map { rs => rs.string("name") }
    .list().apply()
  • foreach()
    Hàm foreach() thực hiện trên từng dòng dữ liệu của kết quả truy vấn
def getNameListByForeach()(implicit session: DBSession = AutoSession): Unit =
  SQL("select * from employee")
    .foreach(rs => print(rs.string("name")))

2.2.2. Phép toán cập nhật (update)

Hàm update() trả về số lượng bản ghi được cập nhật

def updateNameById(id: Long, newName: String)(implicit session: DBSession = AutoSession): Int =
  SQL("update employee set name = {name} where id = {id}")
    .bindByName('id -> id, 'name -> newName)
    .update().apply()

2.2.3. Phép toán thực thi (execute)

Mục đích sử dụng: thực thi các lệnh có dạng: create, delete …

def deleteById(id: Long)(implicit session: DBSession = AutoSession): Boolean =
  SQL("delete from employee where id = {id}")
    .bindByName('id -> id)
    .execute().apply()

2.3. SQLInterpolation

SQLInterpolation là phép nội suy được áp dụng từ phiên bản Scala 2.10 trở lên
Cách sử dụng khá đơn giản: Viết các câu truy vấn dưới đạng sql”SQL String”
Ví dụ ta có thể viết lại hàm lấy tên employee theo id như sau

def getNameById(id: Long)(implicit session: DBSession = AutoSession): Option[String] =
  sql"select * from employee where id = ${id}"
    .map { rs => rs.string("name") }
    .single().apply()

2.3.1. SQLSyntax

Không giống như các biến giá trị được đoán nhận trực tiếp trong truy vấn, SQLSyntax là một phần của truy vấn đó, ví dụ mệnh đề, điều kiện. Để tạo SQLSyntax ta dùng cấu trúc sqls”String”. Trong SQLSyntax, các biến vẫn được nội suy như với lệnh SQL đầy đủ.
Ví dụ

def getNameById(id: Long)(implicit session: DBSession = AutoSession): Option[String] = {
  val idClause = sqls"where id = ${id}"
  sql"select * from employee ${idClause}"
    .map { rs => rs.string("name") }
    .single().apply()
}

2.3.2. SQLSyntaxSupport

Ta khai báo thêm lớp Employee và object EmployeeTable như sau

case class Employee(id: Long, name: String, email: String)
object EmployeeTable  extends SQLSyntaxSupport[Employee] {
  override val tableName = "employee"

  def apply(e: ResultName[Employee])(rs: WrappedResultSet): Employee =
    new Employee(
      rs.long("id"),
      rs.string("name"),
      rs.string("email")
    )
}

Khi đó, có thể viết hàm lấy employee theo id, kết quả trả về mang kiểu Option[Employee]

val e = EmployeeTable.syntax("e")
def getById(id: Long)(implicit session: DBSession = AutoSession): Option[Employee] = {
  sql"select * from ${EmployeeTable.as(e)} where id = ${id}"
    .map{rs => EmployeeTable(e.resultName)(rs)}
    .single().apply()
}

3. Kết luận

Bài viết mở đầu về ScalikeJDBC đã đề cập tới cách cài đặt ScalikeJDBC trong Play2 framework, các phép toán, và cách sử dụng SQLInterpolation. Với sự khởi đầu trên, chúng ta sẽ tiếp tục tìm hiểu thêm các tính năng khác của ScalikeJDBC trong các bài viết tiếp theo.

Tham khảo

http://scalikejdbc.org/

Add a Comment

Scroll Up