Scala for Backend Engineering & Functional Programming · บทเรียน

การเชื่อมต่อฐานข้อมูลด้วย Slick/Doobie

เรียนรู้การเชื่อมต่อฐานข้อมูลเข้ากับแอปพลิเคชัน Play โดยใช้ ORM หรือไลบรารี Scala ยอดนิยม เช่น Slick หรือ Doobie

บทเรียน 3 จาก 311 ขั้นตอน

การเชื่อมต่อฐานข้อมูลด้วย Slick/Doobie เป็นบทเรียน Scala for Backend Engineering & Functional Programming ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Scala for Backend Engineering & Functional Programming และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 3 บทเรียน

เหตุใดจึงต้องเชื่อมต่อฐานข้อมูล

เว็บแอปพลิเคชันมักจำเป็นต้องจัดเก็บและเรียกดูข้อมูลอย่างถาวร ข้อมูลเหล่านี้อาจเป็นโปรไฟล์ผู้ใช้ ข้อมูลผลิตภัณฑ์ หรือบทความบล็อก

  • การคงอยู่ของข้อมูล: ข้อมูลยังคงพร้อมใช้งานแม้แอปพลิเคชันจะเริ่มทำงานใหม่
  • ความสามารถในการปรับขนาด: รองรับข้อมูลปริมาณมากและผู้ใช้จำนวนมากที่ใช้งานพร้อมกัน
  • ความน่าเชื่อถือ: รับรองความถูกต้องครบถ้วนและการกู้คืนข้อมูล

การเชื่อมต่อฐานข้อมูลมีความสำคัญอย่างยิ่งต่อเว็บแอปพลิเคชันแบบไดนามิกที่สร้างด้วย Play Framework

เครื่องมือฐานข้อมูลของ Scala: Slick และ Doobie

Scala มีไลบรารีที่ทรงพลังสำหรับการทำงานกับฐานข้อมูล โดย Slick และ Doobie เป็นตัวเลือกยอดนิยมสองแบบ

  • Slick: ไลบรารีการแมปเชิงสัมพันธ์เชิงฟังก์ชัน (FRM) ช่วยให้คุณทำงานกับฐานข้อมูลในรูปแบบที่ปลอดภัยด้านชนิดข้อมูลและเป็นเชิงฟังก์ชัน โดยซ่อนรายละเอียดของ SQL ไว้
  • Doobie: ชั้น JDBC เชิงฟังก์ชันอย่างแท้จริง ช่วยให้คุณควบคุมคำสั่ง SQL ได้โดยตรง พร้อมผสานรวมกับแนวคิดการเขียนโปรแกรมเชิงฟังก์ชัน เช่น Cats Effect

ในบทเรียนนี้ เราจะเน้นที่ Slick เนื่องจากมีระดับการแยกซ่อนรายละเอียดที่สูงกว่า ซึ่งมักทำให้การเชื่อมต่อเบื้องต้นกับ Play Framework ง่ายขึ้น

การตั้งค่า Slick ใน Play

ขั้นแรก ให้เพิ่ม Slick และไดรเวอร์ฐานข้อมูลลงใน build.sbt เราจะใช้ H2 ซึ่งเป็นฐานข้อมูลในหน่วยความจำเพื่อให้ตั้งค่าได้ง่าย

จากนั้น ให้กำหนดค่าการเชื่อมต่อฐานข้อมูลใน conf/application.conf

import play.sbt.PlayImport._

libraryDependencies ++= Seq(
  jdbc,
  ws,
  "com.typesafe.play" %% "play-slick" % "5.0.0",
  "com.typesafe.play" %% "play-slick-evolutions" % "5.0.0",
  "com.h2database" % "h2" % "2.2.224"
)

การกำหนดค่าฐานข้อมูล

เพิ่มบรรทัดเหล่านี้ลงใน conf/application.conf เพื่อตั้งค่าฐานข้อมูล H2 และโปรไฟล์ Slick ส่วน slick.dbs.default.profile ใช้ระบุชนิดของฐานข้อมูล

play.db.prototype.slick ใช้กำหนดแม่แบบสำหรับการเชื่อมต่อฐานข้อมูล

slick.dbs.default.profile="slick.jdbc.H2Profile$"

play.db { 
  prototype.slick = {
    db.driver="org.h2.Driver"
    db.url="jdbc:h2:mem:play;DB_CLOSE_DELAY=-1"
    db.username="sa"
    db.password=""
  }

  # Apply the prototype to our default DB
  default = ${play.db.prototype.slick}
}

การกำหนดโมเดลของคุณ (ตาราง Slick)

ใน Slick คุณจะแทนตารางฐานข้อมูลด้วยคลาส Scala ที่สืบทอดจาก slick.jdbc.H2Profile.api.Table แต่ละคอลัมน์จะถูกแมปกับชนิดข้อมูลของ Scala

เราจะกำหนด TableQuery สำหรับแต่ละตาราง ซึ่งเป็นจุดเริ่มต้นสำหรับการสอบถามข้อมูล

import slick.jdbc.H2Profile.api._

// Define a case class for our data model
case class User(id: Option[Long], name: String, email: String)

// Define the table mapping
class Users(tag: Tag) extends Table[User](tag, "users") {
  def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name")
  def email = column[String]("email")
  
  // Every table needs a * projection with the default mapping
  def * = (id, name, email) <> (User.tupled, User.unapply)
}

// TableQuery for accessing the Users table
val users = TableQuery[Users]

โค้ด: การสร้างตารางและโครงสร้างฐานข้อมูล

ตัวอย่างที่เรียกใช้งานได้นี้แสดงวิธีกำหนดตาราง User แล้วสร้างโครงสร้างของตารางในฐานข้อมูล H2 ที่อยู่ในหน่วยความจำ เมธอด db.run จะดำเนินการฐานข้อมูลแบบอะซิงโครนัส

import slick.jdbc.H2Profile.api._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

case class User(id: Option[Long], name: String, email: String)

class Users(tag: Tag) extends Table[User](tag, "users") {
  def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name")
  def email = column[String]("email")
  def * = (id, name, email) <> (User.tupled, User.unapply)
}

object SlickDemo {
  val users = TableQuery[Users]

  def main(args: Array[String]): Unit = {
    val db = Database.forURL("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")
    try {
      val setup = DBIO.seq(
        users.schema.create
      )
      val future = db.run(setup)
      Await.result(future, 2.seconds)
      println("Users table created successfully!")
    } finally {
      db.close()
    }
  }
}

รูปแบบ DAO สำหรับการดำเนินการ

รูปแบบ Data Access Object (DAO) ช่วยรวมการดำเนินการกับฐานข้อมูลไว้เป็นส่วนเดียวกัน และแยกตรรกะทางธุรกิจของแอปพลิเคชันออกจากตรรกะการคงอยู่ของข้อมูล

UserDAO จะมีเมธอดสำหรับเพิ่ม สอบถาม อัปเดต และลบออบเจ็กต์ User

import slick.jdbc.H2Profile.api._
import scala.concurrent.Future

class UserDAO(db: Database) {
  import SlickDemo.users // Assuming users TableQuery is in SlickDemo object

  def insert(user: User): Future[User] = {
    db.run(users returning users.map(_.id) into ((user, id) => user.copy(id = id)) += user)
  }

  def findAll(): Future[Seq[User]] = {
    db.run(users.result)
  }

  def findById(id: Long): Future[Option[User]] = {
    db.run(users.filter(_.id === id).result.headOption)
  }
}

โค้ด: การเพิ่มและสอบถามข้อมูล

ต่อไปนี้คือตัวอย่างการเพิ่มผู้ใช้ใหม่ แล้วสอบถามผู้ใช้ทั้งหมดจากฐานข้อมูลโดยใช้เมธอดของ DAO ที่เราเพิ่งกำหนด

import slick.jdbc.H2Profile.api._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

case class User(id: Option[Long], name: String, email: String)

class Users(tag: Tag) extends Table[User](tag, "users") {
  def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name")
  def email = column[String]("email")
  def * = (id, name, email) <> (User.tupled, User.unapply)
}

class UserDAO(db: Database) {
  val users = TableQuery[Users]
  def insert(user: User): Future[User] = 
    db.run(users returning users.map(_.id) into ((u, id) => u.copy(id = id)) += user)
  def findAll(): Future[Seq[User]] = 
    db.run(users.result)
}

object SlickOperations {
  def main(args: Array[String]): Unit = {
    val db = Database.forURL("jdbc:h2:mem:test2;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")
    val userDAO = new UserDAO(db)
    try {
      Await.result(db.run(userDAO.users.schema.create), 2.seconds)
      println("Table created.")

      val future = for {
        user1 <- userDAO.insert(User(None, "Alice", "alice@example.com"))
        user2 <- userDAO.insert(User(None, "Bob", "bob@example.com"))
        allUsers <- userDAO.findAll()
      } yield allUsers

      val result = Await.result(future, 5.seconds)
      println(s"All users: $result")

    } finally {
      db.close()
    }
  }
}

การผสาน DAO เข้ากับ Play

ในแอปพลิเคชัน Play โดยทั่วไปคุณจะแทรก UserDAO เข้าไปใน controller โดยใช้การฉีดการพึ่งพา วิธีนี้ทำให้การทำงานของ controller สามารถโต้ตอบกับฐานข้อมูลได้

คุณจะกำหนดค่า DI ของ Play (เช่น Guice) เพื่อจัดหาอินสแตนซ์ของ Database และ UserDAO

import play.api.mvc._
import play.api.libs.json._
import scala.concurrent.ExecutionContext
import javax.inject._

// Assuming User and UserDAO are defined as before

@Singleton
class UserController @Inject()(cc: ControllerComponents, userDAO: UserDAO)
                              (implicit ec: ExecutionContext) extends AbstractController(cc) {

  def listUsers = Action.async {
    userDAO.findAll().map { users =>
      Ok(Json.toJson(users))
    }
  }

  def createUser = Action.async(parse.json) {
    request =>
      request.body.validate[User].map { user =>
        userDAO.insert(user).map(u => Created(Json.toJson(u)))
      }.getOrElse(Future.successful(BadRequest("Invalid User Data")))
  }
}

ตรวจสอบสั้น ๆ: ตาราง Slick

พิจารณา case class ของ Scala และการแมป Table ของ Slick ที่กำหนดไว้บางส่วนต่อไปนี้:

case class Product(id: Option[Int], name: String, price: Double)

บรรทัดใดเติมโพรเจกชัน * ของตาราง Product ได้อย่างถูกต้อง โดยสมมติว่ามีการกำหนดคอลัมน์ id, name และ price แล้ว

ทบทวน: การเชื่อมต่อฐานข้อมูล

ในบทเรียนนี้ เราได้สำรวจวิธีเชื่อมต่อฐานข้อมูลเข้ากับแอปพลิเคชัน Play Framework โดยใช้ Slick

  • เราได้เรียนรู้บทบาทของ Slick ในฐานะไลบรารีการแมปเชิงสัมพันธ์เชิงฟังก์ชัน (FRM)
  • เราได้ครอบคลุมการตั้งค่าการพึ่งพา Slick และการกำหนดค่าฐานข้อมูลใน application.conf
  • คุณได้เห็นวิธีกำหนด case class ของ Scala และแมปเข้ากับตารางฐานข้อมูลโดยใช้คลาส Table ของ Slick
  • เราได้แนะนำรูปแบบ DAO เพื่อจัดระเบียบการดำเนินการกับฐานข้อมูล พร้อมยกตัวอย่างการเพิ่มและสอบถามข้อมูล
  • สุดท้าย เราได้กล่าวถึงการผสานการดำเนินการของ DAO เข้ากับ controller ของ Play สำหรับปลายทาง API ของเว็บ

การเชี่ยวชาญด้านการเชื่อมต่อฐานข้อมูลเป็นกุญแจสำคัญในการสร้างแอปพลิเคชัน Play ที่แข็งแกร่งและขับเคลื่อนด้วยข้อมูล!

เริ่มต้นได้ฟรี

เรียนรู้ Scala ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
39
บทเรียน
143

คำถามที่พบบ่อย

บทเรียน “การเชื่อมต่อฐานข้อมูลด้วย Slick/Doobie” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเชื่อมต่อฐานข้อมูลด้วย Slick/Doobie” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Scala for Backend Engineering & Functional Programming ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 3 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเชื่อมต่อฐานข้อมูลด้วย Slick/Doobie”

เรียนรู้การเชื่อมต่อฐานข้อมูลเข้ากับแอปพลิเคชัน Play โดยใช้ ORM หรือไลบรารี Scala ยอดนิยม เช่น Slick หรือ Doobie คุณปฏิบัติ Scala for Backend Engineering & Functional Programming ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Scala for Backend Engineering & Functional Programming หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Scala for Backend Engineering & Functional Programming บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน

บทเรียน “การเชื่อมต่อฐานข้อมูลด้วย Slick/Doobie” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Scala for Backend Engineering & Functional Programming นี้ได้ไหม

ได้ บทเรียน Scala for Backend Engineering & Functional Programming ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐาน Play Framework
  2. การสร้าง RESTful API ด้วย Play
  3. การเชื่อมต่อฐานข้อมูลด้วย Slick/Doobie
← กลับไปที่ Scala for Backend Engineering & Functional Programming