Conectar con un transactor
Configure el acceso a la base de datos
Conectar con un transactor es una lección gratuita de Scala for Backend Engineering & Functional Programming en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Scala for Backend Engineering & Functional Programming, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.
¿Qué es un Transactor?
Doobie es una capa JDBC funcional pura para Scala. Un Transactor[F] conecta los programas puros de Doobie con una conexión real a la base de datos.
Un Transactor sabe cómo adquirir una Connection JDBC, ejecutar su programa dentro de una transacción y liberar los recursos de forma segura.
Está parametrizado por un tipo de efecto F[_], como cats.effect.IO.
import doobie._
import cats.effect.IO
val xa: Transactor[IO] = ???El programa ConnectionIO
Las consultas de Doobie son valores de tipo ConnectionIO[A]. Describen un cálculo que necesita una conexión JDBC, pero todavía no se ejecutan.
Puede construir estos programas de forma pura y, después, entregárselos a un Transactor para ejecutarlos. La base de datos no se toca hasta que se ejecuta el programa.
import doobie.implicits._
val program: ConnectionIO[Int] =
sql"select 42".query[Int].uniqueDriverManagerTransactor
El Transactor más sencillo es Transactor.fromDriverManager. Abre una conexión completamente nueva para cada transacción mediante el DriverManager de JDBC.
Necesita el nombre de la clase del driver, la URL JDBC, el nombre de usuario y la contraseña. Es adecuado para pruebas y scripts, pero no dispone de un pool de conexiones.
val xa = Transactor.fromDriverManager[IO](
driver = "org.postgresql.Driver",
url = "jdbc:postgresql://localhost:5432/app",
user = "postgres",
password = "secret",
logHandler = None
)Ejecución de un programa
Para ejecutar un ConnectionIO, llame a .transact(xa). Esto produce un F[A], en este caso un IO[A].
El Transactor envuelve el programa en una transacción: confirma los cambios si tiene éxito y revierte la transacción si falla, liberando la conexión en ambos casos.
import doobie.implicits._
val result: IO[Int] =
sql"select 42".query[Int].unique.transact(xa)Pooling con HikariCP
En producción necesitará un pool de conexiones. Doobie incluye HikariTransactor, respaldado por HikariCP.
Se crea como un Resource para que el pool se cierre correctamente. También debe proporcionar un contexto de ejecución para las operaciones JDBC bloqueantes.
import doobie.hikari.HikariTransactor
import cats.effect.IO
val xaRes: Resource[IO, HikariTransactor[IO]] =
HikariTransactor.newHikariTransactor[IO](
"org.postgresql.Driver",
"jdbc:postgresql://localhost/app",
"postgres", "secret",
connectEC
)¿Por qué un Resource?
Un Transactor con pool posee estado de larga duración: conexiones abiertas e hilos en segundo plano. Resource[F, A] garantiza que la adquisición y la liberación estén emparejadas incluso si se producen errores o cancelaciones.
Normalmente se construye el Transactor una vez al iniciar la aplicación y se reutiliza durante toda su vida útil.
xaRes.use { xa =>
program.transact(xa)
}El pool connectEC
HikariCP necesita un ExecutionContext para esperar conexiones del pool. Doobie proporciona ExecutionContexts.fixedThreadPool para este fin, que también es un Resource.
Mantenerlo separado del pool de cómputo evita que la adquisición bloqueante de conexiones deje sin recursos al trabajo limitado por la CPU.
import doobie.util.ExecutionContexts
val poolRes =
for {
ec <- ExecutionContexts.fixedThreadPool[IO](8)
xa <- HikariTransactor.newHikariTransactor[IO](
"org.postgresql.Driver", url, user, pass, ec)
} yield xaConfiguración de un DataSource existente
Si ya dispone de un javax.sql.DataSource configurado (por ejemplo, una instancia de Hikari ajustada), envuélvalo directamente con Transactor.fromDataSource.
Esto es habitual cuando un framework administra el pool y solo desea que Doobie lo utilice.
val xa = Transactor.fromDataSource[IO](
dataSource = myDataSource,
connectEC = connectEC
)Prueba básica de la conexión
Una comprobación de estado sencilla consiste en ejecutar select 1 mediante el Transactor. Si devuelve un resultado, el driver, la URL y las credenciales funcionan correctamente.
Es un buen primer paso antes de conectar consultas reales.
val check: IO[Int] =
sql"select 1".query[Int].unique.transact(xa)
// check.unsafeRunSync() == 1Internals de Transactor: Strategy
Un Transactor se construye a partir de intérpretes y una Strategy. La Strategy controla lo que ocurre alrededor de cada transacción: before, after, oops (en caso de error) y always.
La estrategia predeterminada desactiva el commit automático, confirma los cambios tras el éxito, revierte la transacción si hay un error y cierra siempre la conexión.
import doobie.util.transactor.Strategy
val noCommit = xa.copy(
strategy0 = Strategy.default.copy(after = doobie.free.connection.unit)
)Registro y observabilidad
Doobie puede registrar cada sentencia, sus argumentos y sus tiempos. Las versiones modernas asocian un LogHandler[F] a cada consulta en lugar de a cada Transactor.
Esto resulta esencial para detectar consultas lentas y verificar la vinculación de parámetros en producción.
import doobie.util.log._
val handler: LogHandler[IO] = (ev: LogEvent) =>
IO.println(ev.sql)Comprobación rápida
Compruebe su comprensión de los Transactors.
Resumen
Un Transactor[F] conecta programas puros ConnectionIO con una base de datos real. fromDriverManager es adecuado para pruebas; HikariTransactor y fromDataSource son apropiados para producción mediante pooling.
Construya los Transactors con pool como un Resource, ejecute los programas con .transact(xa) y deje que la Strategy predeterminada gestione la confirmación, la reversión y la limpieza.
Preguntas frecuentes
¿La lección «Conectar con un transactor» es gratis?
Sí — el texto completo de «Conectar con un transactor» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Scala for Backend Engineering & Functional Programming, actualiza a CoddyKit PRO. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.
¿Qué aprenderé en «Conectar con un transactor»?
Configure el acceso a la base de datos Practicas Scala for Backend Engineering & Functional Programming con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Scala for Backend Engineering & Functional Programming?
No se requiere experiencia previa. Scala for Backend Engineering & Functional Programming en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Conectar con un transactor»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Scala for Backend Engineering & Functional Programming?
Sí. Cada lección de Scala for Backend Engineering & Functional Programming incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Conectar con un transactor
- Ejecutar consultas
- Inserciones y actualizaciones
- Componer transacciones