Integracja z bazą danych za pomocą Slick/Doobie
Naucz się integrować bazy danych z aplikacją Play, korzystając z popularnych ORM-ów i bibliotek Scali, takich jak Slick lub Doobie.
Integracja z bazą danych za pomocą Slick/Doobie to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 3 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 3 lekcji w sumie.
Dlaczego integrować bazy danych?
Aplikacje internetowe często muszą trwale przechowywać dane i pobierać je w późniejszym czasie. Mogą to być profile użytkowników, informacje o produktach lub wpisy na blogu.
- Trwałość: Dane pozostają dostępne nawet po ponownym uruchomieniu aplikacji.
- Skalowalność: Możliwość obsługi dużych ilości danych i wielu jednoczesnych użytkowników.
- Niezawodność: Zapewnienie integralności i możliwości odzyskania danych.
Integracja z bazą danych ma kluczowe znaczenie dla każdej dynamicznej aplikacji internetowej zbudowanej za pomocą Play Framework.
Slick i Doobie: narzędzia bazodanowe Scali
Scala oferuje zaawansowane biblioteki do interakcji z bazami danych, a Slick i Doobie to dwa popularne rozwiązania.
- Slick: biblioteka Functional Relational Mapping (FRM). Umożliwia pracę z bazami danych w bezpieczny typowo i funkcyjny sposób, abstrahując od SQL.
- Doobie: w pełni funkcyjna warstwa JDBC. Zapewnia bezpośrednią kontrolę nad zapytaniami SQL, jednocześnie integrując je z paradygmatami programowania funkcyjnego, takimi jak Cats Effect.
W tej lekcji skupimy się na Slick ze względu na wyższy poziom abstrakcji, który często upraszcza początkową integrację z Play Framework.
Konfigurowanie Slick w Play
Najpierw należy dodać Slick i sterownik bazy danych do pliku build.sbt. Użyjemy H2, czyli bazy danych przechowywanej w pamięci, aby uprościć konfigurację.
Następnie należy skonfigurować połączenie z bazą danych w pliku 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"
)Konfiguracja bazy danych
Dodaj te wiersze do pliku conf/application.conf, aby skonfigurować bazę danych H2 i profil Slick. Element slick.dbs.default.profile określa typ bazy danych.
Element play.db.prototype.slick definiuje szablon połączeń z bazą danych.
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}
}Definiowanie modelu (tabela Slick)
W Slick tabele baz danych reprezentuje się za pomocą klas Scali, które rozszerzają slick.jdbc.H2Profile.api.Table. Każda kolumna jest mapowana na typ Scali.
Dla każdej tabeli definiujemy element TableQuery, który stanowi punkt wejścia do wykonywania zapytań.
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]Kod: tworzenie tabeli i schematu
Ten wykonywalny przykład pokazuje, jak zdefiniować tabelę User, a następnie utworzyć jej schemat w bazie danych H2 przechowywanej w pamięci. Metoda db.run asynchronicznie wykonuje operacje na bazie danych.
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()
}
}
}Wzorzec DAO do obsługi operacji
Wzorzec Data Access Object (DAO) pomaga hermetyzować operacje na bazie danych. Oddziela logikę biznesową aplikacji od logiki trwałego przechowywania danych.
Element UserDAO zawierałby metody do wstawiania, wyszukiwania, aktualizowania i usuwania obiektów 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)
}
}Kod: wstawianie i wyszukiwanie danych
Oto sposób wstawienia nowego użytkownika, a następnie wyszukania wszystkich użytkowników w bazie danych za pomocą właśnie zdefiniowanych metod 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()
}
}
}Integracja DAO z Play
W aplikacji Play zazwyczaj wstrzykuje się element UserDAO do kontrolera za pomocą wstrzykiwania zależności. Dzięki temu akcje kontrolera mogą współpracować z bazą danych.
Należy skonfigurować DI w Play (np. Guice), aby udostępniał instancję Database i 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")))
}
}Szybki test: tabela Slick
Rozważ następującą klasę case Scali i częściowo zdefiniowane mapowanie Slick Table:
case class Product(id: Option[Int], name: String, price: Double)Która linia prawidłowo uzupełnia projekcję * dla tabeli Product, przy założeniu, że kolumny id, name i price zostały zdefiniowane?
Podsumowanie: integracja z bazą danych
W tej lekcji omówiliśmy sposób integrowania baz danych z aplikacjami Play Framework za pomocą Slick.
- Poznaliśmy rolę Slick jako biblioteki Functional Relational Mapping (FRM).
- Omówiliśmy dodawanie zależności Slick i konfigurowanie bazy danych w pliku
application.conf. - Zobaczyli Państwo, jak definiować klasy case Scali i mapować je na tabele baz danych za pomocą klasy Slick
Table. - Przedstawiliśmy wzorzec DAO do organizowania operacji na bazie danych oraz przykłady wstawiania i wyszukiwania danych.
- Na koniec omówiliśmy integrację tych operacji DAO z kontrolerami Play na potrzeby endpointów internetowych API.
Opanowanie integracji z bazami danych ma kluczowe znaczenie dla tworzenia solidnych aplikacji Play opartych na danych!
Ucz się Scala dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 39
- Lekcje
- 143
Często zadawane pytania
Czy lekcja „Integracja z bazą danych za pomocą Slick/Doobie” jest bezpłatna?
Tak — pełny tekst „Integracja z bazą danych za pomocą Slick/Doobie” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 3 lekcji w sumie.
Co nauczysz się w „Integracja z bazą danych za pomocą Slick/Doobie”?
Naucz się integrować bazy danych z aplikacją Play, korzystając z popularnych ORM-ów i bibliotek Scali, takich jak Slick lub Doobie. Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?
Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 3.
Ile czasu zajmuje lekcja „Integracja z bazą danych za pomocą Slick/Doobie”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?
Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Podstawy Play Framework
- Tworzenie API RESTful za pomocą Play
- Integracja z bazą danych za pomocą Slick/Doobie