Интеграция с базами данных через Slick/Doobie
Научитесь интегрировать базы данных в приложение Play с помощью популярных ORM и библиотек Scala, таких как Slick и Doobie.
«Интеграция с базами данных через Slick/Doobie» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 3 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 3 уроков всего.
Зачем интегрировать базы данных?
Веб-приложениям часто требуется постоянно хранить и извлекать данные. Это могут быть профили пользователей, сведения о товарах или записи в блоге.
- Сохранность: данные остаются доступными даже после перезапуска приложения.
- Масштабируемость: возможность обрабатывать большие объёмы данных и множество одновременных пользователей.
- Надёжность: обеспечение целостности данных и возможности их восстановления.
Интеграция базы данных важна для любого динамического веб-приложения, созданного с помощью Play Framework.
Слик и Дуби: инструменты работы с базами данных в Scala
Scala предлагает мощные библиотеки для взаимодействия с базами данных; двумя популярными вариантами являются Слик и Дуби.
- Слик: библиотека функционального реляционного отображения (FRM). Она позволяет работать с базами данных типобезопасным и функциональным способом, абстрагируясь от SQL.
- Дуби: полностью функциональный слой JDBC. Он предоставляет прямой контроль над SQL-запросами и при этом интегрируется с парадигмами функционального программирования, такими как Cats Effect.
В этом уроке мы сосредоточимся на Слик благодаря его более высокоуровневой абстракции, которая часто упрощает первоначальную интеграцию с Play Framework.
Настройка Слик в Play
Сначала добавьте Слик и драйвер базы данных в файл 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.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}
}Определение модели (таблица Слик)
В Слик таблицы базы данных представляются классами 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 для операций
Шаблон объекта доступа к данным (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 в контроллер с помощью внедрения зависимостей. Это позволяет действиям контроллера взаимодействовать с базой данных.
Вам потребуется настроить 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")))
}
}Быстрая проверка: таблица Слик
Рассмотрим следующий класс вариантов Scala и частично определённое сопоставление таблицы Слик Table:
case class Product(id: Option[Int], name: String, price: Double)Какая строка корректно завершает проекцию * для таблицы Product, если столбцы id, name и price уже определены?
Повторение: интеграция базы данных
В этом уроке мы изучили интеграцию баз данных в приложения Play Framework с помощью Слик.
- Мы узнали о роли Слик как библиотеки функционального реляционного отображения (FRM).
- Мы рассмотрели добавление зависимостей Слик и настройку базы данных в
application.conf. - Вы увидели, как определять классы вариантов Scala и сопоставлять их с таблицами базы данных с помощью класса Слик
Table. - Мы познакомились с шаблоном DAO для организации операций с базой данных и рассмотрели примеры добавления и поиска данных.
- Наконец, мы затронули интеграцию этих операций DAO с контроллерами Play для конечных точек веб-API.
Освоение интеграции баз данных — ключ к созданию надёжных приложений Play, управляемых данными!
Изучай Scala с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 39
- Уроки
- 143
Часто задаваемые вопросы
Урок «Интеграция с базами данных через Slick/Doobie» бесплатный?
Да — полный текст урока «Интеграция с базами данных через Slick/Doobie» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 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 с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 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 — локальная установка не требуется.
Все уроки этого курса
- Основы Play Framework
- Создание RESTful API с Play
- Интеграция с базами данных через Slick/Doobie