স্কালার সাথে ডেটাবেস ইন্টিগ্রেশন বেশ সহজ এবং কার্যকরী, কারণ স্কালা একাধিক লাইব্রেরি এবং ফ্রেমওয়ার্ক সমর্থন করে, যা ডেটাবেসের সাথে সহজে সংযোগ স্থাপন, কিউরি এক্সিকিউট, এবং ডেটা ম্যানিপুলেট করতে সহায়তা করে। এখানে আমরা স্কালায় ডেটাবেস ইন্টিগ্রেশনের জন্য ব্যবহৃত সাধারণ কিছু টুলস এবং লাইব্রেরি আলোচনা করব, যেমন Slick, Doobie, এবং JDBC।
১. Slick - Functional Relational Mapping (FRM)
Slick একটি শক্তিশালী ফাংশনাল রিলেশনাল মডেলিং (FRM) লাইব্রেরি, যা আপনাকে ডেটাবেসের সাথে কোড লেখার সময় টাইপ সেফ কিউরি এবং কোড জেনারেট করতে সহায়তা করে। এটি SQL এবং ফাংশনাল প্রোগ্রামিংয়ের শক্তিশালী সংমিশ্রণ।
১.১ Slick Setup in SBT
প্রথমে, আপনার build.sbt ফাইলে Slick এবং হাইবারনেট (যদি ব্যবহার করতে চান) বা JDBC ড্রাইভার ডিপেন্ডেন্সি যুক্ত করুন:
name := "ScalaSlickExample"
version := "1.0"
scalaVersion := "2.13.6"
libraryDependencies ++= Seq(
"com.typesafe.slick" %% "slick" % "3.3.3",
"com.typesafe.slick" %% "slick-hikaricp" % "3.3.3", // For connection pool
"org.postgresql" % "postgresql" % "42.2.5" // For PostgreSQL
)১.২ Basic Slick Example
এখন Slick ব্যবহার করে একটি ডেটাবেসে সংযোগ এবং একটি সিম্পল টেবিল তৈরি করা যাক।
Example:
import slick.jdbc.PostgresProfile.api._
import scala.concurrent.Await
import scala.concurrent.duration._
case class User(id: Int, name: String)
class Users(tag: Tag) extends Table[User](tag, "users") {
def id = column[Int]("id", O.PrimaryKey)
def name = column[String]("name")
def * = (id, name) <> (User.tupled, User.unapply)
}
object SlickExample {
val db = Database.forConfig("mydb") // "mydb" configuration in application.conf
val users = TableQuery[Users]
def createTable(): Unit = {
val setup = DBIO.seq(
users.schema.create
)
val setupFuture = db.run(setup)
Await.result(setupFuture, 2.seconds)
}
def insertUser(): Unit = {
val insertAction = users += User(1, "Alice")
val insertFuture = db.run(insertAction)
Await.result(insertFuture, 2.seconds)
}
def main(args: Array[String]): Unit = {
createTable()
insertUser()
println("Table created and user inserted")
}
}এখানে:
TableQuery[Users]দিয়ে টেবিলের রেফারেন্স তৈরি করা হয়েছে।DBIO.seqব্যবহার করে ডেটাবেসে স্নাতক পর্যায়ে কর্ম তৈরি এবংdb.runদিয়ে রিচালনা করা হয়েছে।
১.৩ Configuration (application.conf)
Slick ডেটাবেস সংযোগের জন্য application.conf ফাইলে কনফিগারেশন সেটআপ করা প্রয়োজন।
mydb = {
driver = "slick.jdbc.PostgresProfile$"
db {
url = "jdbc:postgresql://localhost:5432/mydatabase"
user = "user"
password = "password"
driver = "org.postgresql.Driver"
connectionPool = "HikariCP"
keepAliveConnection = true
}
}২. Doobie - Functional JDBC
Doobie একটি ফাংশনাল JDBC লাইব্রেরি যা স্কালায় খুবই জনপ্রিয় এবং ফাংশনাল স্টাইলের ডেটাবেস অ্যাক্সেস সহজ করে। এটি আপনার SQL কোডকে ফাংশনাল স্টাইলে লেখার সুবিধা প্রদান করে।
২.১ Doobie Setup in SBT
Doobie ব্যবহার করতে build.sbt ফাইলে নিম্নলিখিত ডিপেন্ডেন্সি যুক্ত করুন:
libraryDependencies ++= Seq(
"org.tpolecat" %% "doobie-core" % "0.8.8",
"org.tpolecat" %% "doobie-hikari" % "0.8.8",
"org.postgresql" % "postgresql" % "42.2.5"
)২.২ Basic Doobie Example
Example:
import doobie._
import doobie.implicits._
import cats.effect.{IO, ExitCode, IOApp}
case class User(id: Int, name: String)
object DoobieExample extends IOApp {
val xa: Transactor[IO] = Transactor.fromDriverManager[IO](
"org.postgresql.Driver", // Driver
"jdbc:postgresql://localhost:5432/mydatabase", // JDBC URL
"user", // Username
"password" // Password
)
def createTable: ConnectionIO[Int] =
sql"""
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT
)
""".update.run
def insertUser: ConnectionIO[Int] =
sql"INSERT INTO users (name) VALUES ('Alice')".update.run
def queryUsers: ConnectionIO[List[User]] =
sql"SELECT id, name FROM users".query[User].to[List]
def run(args: List[String]): IO[ExitCode] = {
val program = for {
_ <- createTable
_ <- insertUser
users <- queryUsers
_ <- IO(println(users))
} yield users
program.transact(xa).map(_ => ExitCode.Success)
}
}এখানে:
Transactorডেটাবেস সংযোগ পরিচালনা করে।ConnectionIOদিয়ে ডেটাবেস অ্যাকশন তৈরি করা হয় এবংtransact(xa)মাধ্যমে সেই অ্যাকশন কার্যকর করা হয়।
৩. JDBC (Java Database Connectivity)
JDBC হল স্ট্যান্ডার্ড ডেটাবেস ইন্টারফেস যা স্কালাতে ডেটাবেস সংযোগ এবং কিউরি এক্সিকিউশন করতে ব্যবহার করা যেতে পারে।
৩.১ JDBC Example
Example:
import java.sql.{Connection, DriverManager, ResultSet}
object JdbcExample {
def main(args: Array[String]): Unit = {
val url = "jdbc:postgresql://localhost:5432/mydatabase"
val username = "user"
val password = "password"
var connection: Connection = null
try {
connection = DriverManager.getConnection(url, username, password)
val statement = connection.createStatement()
val resultSet: ResultSet = statement.executeQuery("SELECT id, name FROM users")
while (resultSet.next()) {
println(s"${resultSet.getInt("id")} - ${resultSet.getString("name")}")
}
} catch {
case e: Exception => e.printStackTrace()
} finally {
if (connection != null) connection.close()
}
}
}এখানে:
- JDBC ড্রাইভার ব্যবহার করে ডেটাবেসে সংযোগ স্থাপন এবং কিউরি এক্সিকিউট করা হয়েছে।
DriverManager.getConnectionদিয়ে ডেটাবেস সংযোগ করা হয়েছে এবংexecuteQueryব্যবহার করে SQL কিউরি চালানো হয়েছে।
সারাংশ
স্কালাতে ডেটাবেস ইন্টিগ্রেশন করার জন্য বেশ কয়েকটি লাইব্রেরি রয়েছে, যা ডেটাবেস অপারেশন সহজ এবং কার্যকরী করে তোলে:
- Slick: এটি একটি Functional Relational Mapping (FRM) লাইব্রেরি, যা SQL কিউরি এবং ডেটাবেস অ্যাক্সেস ফাংশনাল স্টাইলে পরিচালনা করতে সহায়তা করে।
- Doobie: এটি একটি ফাংশনাল JDBC লাইব্রেরি, যা ফাংশনাল প্রোগ্রামিং স্টাইল ব্যবহার করে ডেটাবেসের সাথে যোগাযোগ করতে সহায়তা করে।
- JDBC: স্কালায় স্ট্যান্ডার্ড JDBC ব্যবহার করে ডেটাবেসের সাথে সরাসরি যোগাযোগ করা যায়, যা আরও বেশি কাস্টমাইজেবল।
এই লাইব্রেরিগুলি স্কালাকে ডেটাবেস সংযোগ, কিউরি এক্সিকিউশন এবং ডেটা ম্যানিপুলেশন করার জন্য শক্তিশালী এবং নমনীয় টুলস প্রদান করে।
JDBC (Java Database Connectivity) হল একটি API যা Java প্রোগ্রামগুলিকে ডাটাবেসের সাথে যোগাযোগ করতে সহায়তা করে। স্কালার মধ্যে JDBC ব্যবহার করতে, স্কালা ডেটাবেস অপারেশন সম্পাদন করার জন্য Java JDBC API ব্যবহার করে। স্কালার জন্য JDBC একটি সাধারণ এবং শক্তিশালী উপায়, যেখানে SQL কোয়েরি রিটার্ন করতে এবং ডাটাবেসে ডাটা ম্যানিপুলেট করতে সহায়তা করে।
এই গাইডে, আমরা দেখব কিভাবে স্কালায় JDBC ব্যবহার করে ডাটাবেসের সাথে সংযোগ স্থাপন করবেন এবং কিছু সাধারণ ডাটাবেস অপারেশন (যেমন: SELECT, INSERT) করব।
১. স্কালায় JDBC ডিপেন্ডেন্সি যুক্ত করা
প্রথমে, আপনার build.sbt ফাইলে JDBC ডিপেন্ডেন্সি যোগ করতে হবে। এখানে আমরা H2 ডাটাবেস (একটি ইন-মেমরি ডাটাবেস) ব্যবহার করব, তবে আপনি অন্য কোন ডাটাবেস যেমন MySQL বা PostgreSQL ব্যবহার করতে পারেন।
libraryDependencies += "com.h2database" % "h2" % "1.4.200"এখানে:
"com.h2database" % "h2" % "1.4.200"হ'ল H2 ডাটাবেস ডিপেন্ডেন্সি।
আপনি যদি MySQL বা PostgreSQL ব্যবহার করতে চান, তাহলে তাদের যথাযথ ডিপেন্ডেন্সি যোগ করতে হবে।
MySQL জন্য ডিপেন্ডেন্সি উদাহরণ:
libraryDependencies += "mysql" % "mysql-connector-java" % "8.0.23"২. ডাটাবেসের সাথে সংযোগ স্থাপন করা
এখন, আমাদের ডাটাবেসের সাথে সংযোগ স্থাপন করতে হবে। এটি করার জন্য, স্কালায় JDBC Connection তৈরি করতে হবে।
উদাহরণ: H2 ডাটাবেসের সাথে সংযোগ স্থাপন
import java.sql.{Connection, DriverManager, ResultSet}
object JDBCExample {
def main(args: Array[String]): Unit = {
// JDBC URL, User এবং Password
val jdbcUrl = "jdbc:h2:~/test;MODE=MySQL"
val username = "sa"
val password = ""
// ডাটাবেসের সাথে সংযোগ স্থাপন
val connection: Connection = DriverManager.getConnection(jdbcUrl, username, password)
// কোয়েরি এক্সিকিউট করা
val statement = connection.createStatement()
val resultSet: ResultSet = statement.executeQuery("SELECT * FROM test_table")
// রেজাল্ট প্রিন্ট করা
while (resultSet.next()) {
println(s"ID: ${resultSet.getInt("id")}, Name: ${resultSet.getString("name")}")
}
// সংযোগ বন্ধ করা
resultSet.close()
statement.close()
connection.close()
}
}এখানে:
DriverManager.getConnectionএর মাধ্যমে ডাটাবেসের সাথে সংযোগ স্থাপন করা হয়েছে।Statementতৈরি করেexecuteQueryব্যবহার করে SQL কোয়েরি চালানো হয়েছে।ResultSetব্যবহার করে SQL কোয়েরির ফলাফল রিটার্ন করা হয়েছে।
৩. INSERT, UPDATE এবং DELETE অপারেশন
JDBC এর মাধ্যমে আপনি INSERT, UPDATE, এবং DELETE অপারেশনও করতে পারেন।
উদাহরণ: ডাটাবেসে ডাটা ইনসার্ট করা
object JDBCExampleInsert {
def main(args: Array[String]): Unit = {
val jdbcUrl = "jdbc:h2:~/test;MODE=MySQL"
val username = "sa"
val password = ""
val connection: Connection = DriverManager.getConnection(jdbcUrl, username, password)
val insertQuery = "INSERT INTO test_table (id, name) VALUES (?, ?)"
val preparedStatement = connection.prepareStatement(insertQuery)
// মান সেট করা
preparedStatement.setInt(1, 1)
preparedStatement.setString(2, "Alice")
// ইনসার্ট কোয়েরি এক্সিকিউট করা
preparedStatement.executeUpdate()
println("Data inserted successfully")
// সংযোগ বন্ধ করা
preparedStatement.close()
connection.close()
}
}এখানে:
prepareStatementব্যবহার করে SQL ইনসার্ট কোয়েরি তৈরি করা হয়েছে।setIntএবংsetStringমেথড দ্বারা প্যারামিটার সেট করা হয়েছে এবং ইনসার্ট কোয়েরি এক্সিকিউট করা হয়েছে।
উদাহরণ: ডাটাবেসে ডাটা আপডেট করা
object JDBCExampleUpdate {
def main(args: Array[String]): Unit = {
val jdbcUrl = "jdbc:h2:~/test;MODE=MySQL"
val username = "sa"
val password = ""
val connection: Connection = DriverManager.getConnection(jdbcUrl, username, password)
val updateQuery = "UPDATE test_table SET name = ? WHERE id = ?"
val preparedStatement = connection.prepareStatement(updateQuery)
// মান সেট করা
preparedStatement.setString(1, "Bob")
preparedStatement.setInt(2, 1)
// আপডেট কোয়েরি এক্সিকিউট করা
preparedStatement.executeUpdate()
println("Data updated successfully")
// সংযোগ বন্ধ করা
preparedStatement.close()
connection.close()
}
}উদাহরণ: ডাটাবেস থেকে ডাটা ডিলিট করা
object JDBCExampleDelete {
def main(args: Array[String]): Unit = {
val jdbcUrl = "jdbc:h2:~/test;MODE=MySQL"
val username = "sa"
val password = ""
val connection: Connection = DriverManager.getConnection(jdbcUrl, username, password)
val deleteQuery = "DELETE FROM test_table WHERE id = ?"
val preparedStatement = connection.prepareStatement(deleteQuery)
// মান সেট করা
preparedStatement.setInt(1, 1)
// ডিলিট কোয়েরি এক্সিকিউট করা
preparedStatement.executeUpdate()
println("Data deleted successfully")
// সংযোগ বন্ধ করা
preparedStatement.close()
connection.close()
}
}৪. ট্রানজেকশন (Transaction)
JDBC ব্যবহার করে আপনি ট্রানজেকশন পরিচালনা করতে পারেন, যেখানে একাধিক SQL অপারেশন একত্রে কার্যকর করা হয়। এক বা একাধিক অপারেশন ব্যর্থ হলে সব অপারেশন রিভার্স করা হয়।
object JDBCExampleTransaction {
def main(args: Array[String]): Unit = {
val jdbcUrl = "jdbc:h2:~/test;MODE=MySQL"
val username = "sa"
val password = ""
val connection: Connection = DriverManager.getConnection(jdbcUrl, username, password)
// ট্রানজেকশন শুরু
connection.setAutoCommit(false)
try {
val statement = connection.createStatement()
statement.executeUpdate("INSERT INTO test_table (id, name) VALUES (1, 'Alice')")
statement.executeUpdate("INSERT INTO test_table (id, name) VALUES (2, 'Bob')")
// কমিট করা
connection.commit()
println("Transaction committed successfully")
} catch {
case e: Exception =>
// কোনো সমস্যা হলে রিভার্স করা
connection.rollback()
println("Transaction rolled back due to error: " + e.getMessage)
} finally {
connection.setAutoCommit(true)
connection.close()
}
}
}এখানে:
setAutoCommit(false)ব্যবহার করে ট্রানজেকশন শুরু করা হয়েছে।- যদি কোনো ত্রুটি ঘটে, তাহলে
rollbackব্যবহার করে সমস্ত পরিবর্তন রিভার্স করা হয়। - যদি সবকিছু ঠিক থাকে, তাহলে
commitকরা হয়।
৫. স্কালায় JDBC ব্যবহার করার সময় কিছু পরামর্শ
- ডিপেন্ডেন্সি ম্যানেজমেন্ট:
sbtবা অন্য বিল্ড টুল ব্যবহার করে JDBC ডিপেন্ডেন্সি সঠিকভাবে যুক্ত করুন। - রিসোর্স ক্লোজিং: ডাটাবেস সংযোগ ব্যবহারের পর
close()মেথড ব্যবহার করে সংযোগ এবং স্টেটমেন্ট বন্ধ করুন। - এক্সসেপশন হ্যান্ডলিং: অ্যাকশন চলাকালীন কোনো ত্রুটি হলে, সেগুলিকে যথাযথভাবে হ্যান্ডল করুন এবং রিভার্স (rollback) করার ব্যবস্থা রাখুন।
সারাংশ
- JDBC স্কালায় ডাটাবেসের সাথে ইন্টারঅ্যাক্ট করার জন্য ব্যবহৃত হয়।
- আপনি
Connection,Statement,PreparedStatement, এবংResultSetএর মাধ্যমে SQL কোয়েরি রন করতে পারেন। - INSERT, UPDATE, DELETE, SELECT অপারেশনগুলি JDBC দিয়ে পরিচালনা করা যায়।
- ট্রানজেকশন এবং এক্সসেপশন হ্যান্ডলিং ব্যবহার করে আরও কার্যকরী ডাটাবেস অপারেশন করা সম্ভব।
এই নির্দেশিকাগুলির মাধ্যমে আপনি স্কাল
ার মধ্যে JDBC ব্যবহারের ভিত্তি শিখতে পারবেন এবং ডাটাবেসের সাথে স্কালার অ্যাপ্লিকেশন তৈরি করতে সক্ষম হবেন।
Slick হল একটি ফাংশনাল রিলেশনাল মাপিং (Functional Relational Mapping - FRM) লাইব্রেরি যা স্কালায় ব্যবহৃত হয় ডেটাবেসের সাথে যোগাযোগ করার জন্য। এটি SQL কোডের মতো স্টেটিক কোড লেখার চেয়ে ডেটাবেসের সাথে ফাংশনাল প্রোগ্রামিংয়ের মাধ্যমে যোগাযোগ করার সুযোগ প্রদান করে। Slick লাইব্রেরি স্কালার টাইপ সিস্টেম এবং ফাংশনাল প্রোগ্রামিংয়ের শক্তি ব্যবহার করে ডেটাবেস অপারেশনগুলো সহজ এবং নিরাপদ করে তোলে।
Slick লাইব্রেরি ডেটাবেসের সাথে সরাসরি কাজ করার জন্য JDBC অথবা H2, PostgreSQL, MySQL, এবং আরও অনেক ডেটাবেস সাপোর্ট প্রদান করে।
এখানে আমরা দেখব কিভাবে Slick লাইব্রেরি ব্যবহার করে একটি সিম্পল ডেটাবেস অ্যাপ্লিকেশন তৈরি করা যায়।
১. Slick লাইব্রেরি ডিপেন্ডেন্সি যোগ করা
প্রথমে আপনার build.sbt ফাইলে Slick লাইব্রেরির ডিপেন্ডেন্সি যোগ করতে হবে।
name := "SlickExample"
version := "0.1"
scalaVersion := "2.13.6"
libraryDependencies ++= Seq(
"com.typesafe.slick" %% "slick" % "3.3.3", // Slick core library
"com.typesafe.slick" %% "slick-hikaricp" % "3.3.3", // Slick HikariCP for connection pooling
"com.typesafe.slick" %% "slick-testkit" % "3.3.3" // For testing
)এখানে:
slickলাইব্রেরি Slick-এর মূল ফাংশনাল লাইব্রেরি।slick-hikaricpলাইব্রেরি HikariCP পুল ব্যবহার করার জন্য যা কানেকশন পুলিংয়ের জন্য ব্যবহৃত হয়।
২. Slick ব্যবহার করে ডেটাবেস কানেকশন সেটআপ
এখন আমরা একটি ডেটাবেস সংযোগ সেটআপ করব এবং Slick ব্যবহার করে কিছু বেসিক অপারেশন করব।
২.১ ডেটাবেস কানেকশন সেটআপ (PostgreSQL বা H2)
প্রথমে ডেটাবেস কানেকশন পুলিং সেটআপ করতে হবে।
import slick.jdbc.H2Profile.api._ // Use H2 in-memory database for simplicity
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
// Database configuration
val db = Database.forConfig("mydb") // Configuration from application.conf
// Define a simple Table
class Users(tag: Tag) extends Table[(Int, String, String)](tag, "USER") {
def id = column[Int]("ID", O.PrimaryKey)
def firstName = column[String]("FIRST_NAME")
def lastName = column[String]("LAST_NAME")
def * = (id, firstName, lastName)
}
val users = TableQuery[Users]Database.forConfig("mydb") থেকে ডেটাবেস কানেকশন সেট করা হয়, যেখানে mydb হল application.conf ফাইলে নির্দিষ্ট করা কনফিগারেশন সেকশন।
৩. Slick দিয়ে ডেটাবেস অপারেশন
এখন আমরা কিছু সাধারণ ডেটাবেস অপারেশন (যেমন INSERT, SELECT, UPDATE, DELETE) দেখতে পারি।
৩.১ ডেটাবেসে ইনসার্ট করা (Insert into Database)
val insertAction = users += (1, "John", "Doe")
// Running the insert action
val insertFuture: Future[Int] = db.run(insertAction)
insertFuture.onComplete {
case Success(result) => println(s"Inserted $result row(s)")
case Failure(exception) => println(s"Failed to insert row: ${exception.getMessage}")
}এখানে += অপারেটর দিয়ে একটি নতুন রেকর্ড ইনসার্ট করা হচ্ছে।
৩.২ ডেটাবেস থেকে সিলেক্ট করা (Select from Database)
val query = users.filter(_.firstName === "John").result
val selectFuture: Future[Seq[(Int, String, String)]] = db.run(query)
selectFuture.onComplete {
case Success(result) => println(s"Query result: ${result.mkString(", ")}")
case Failure(exception) => println(s"Query failed: ${exception.getMessage}")
}এখানে filter পদ্ধতি ব্যবহার করে একটি কন্ডিশন দিয়ে রেকর্ড ফিল্টার করা হয়েছে।
৩.৩ ডেটাবেসে আপডেট করা (Update in Database)
val updateAction = users.filter(_.id === 1).map(u => (u.firstName, u.lastName)).update(("John", "Smith"))
val updateFuture: Future[Int] = db.run(updateAction)
updateFuture.onComplete {
case Success(result) => println(s"Updated $result row(s)")
case Failure(exception) => println(s"Update failed: ${exception.getMessage}")
}এখানে map এবং update পদ্ধতি ব্যবহার করে একটি নির্দিষ্ট রেকর্ড আপডেট করা হয়েছে।
৩.৪ ডেটাবেস থেকে ডিলিট করা (Delete from Database)
val deleteAction = users.filter(_.id === 1).delete
val deleteFuture: Future[Int] = db.run(deleteAction)
deleteFuture.onComplete {
case Success(result) => println(s"Deleted $result row(s)")
case Failure(exception) => println(s"Delete failed: ${exception.getMessage}")
}এখানে delete পদ্ধতি ব্যবহার করে একটি রেকর্ড ডিলিট করা হচ্ছে।
৪. ডেটাবেস কনফিগারেশন
application.conf ফাইলে ডেটাবেস কানেকশনের কনফিগারেশন সেট করা হয়।
mydb = {
driver = "slick.jdbc.H2Profile$"
db {
url = "jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1"
driver = "org.h2.Driver"
connectionPool = "HikariCP"
numThreads = 10
keepAliveConnection = true
}
}এখানে H2 ইন-মেমরি ডেটাবেস ব্যবহার করা হয়েছে। আপনি চাইলে PostgreSQL বা MySQL কনফিগারেশনও ব্যবহার করতে পারেন।
৫. Future ব্যবহার
Slick এর কার্যক্রম Future ব্যবহার করে অ্যাসিঙ্ক্রোনাসলি পরিচালিত হয়। একাধিক ডেটাবেস অপারেশনকে db.run() পদ্ধতি ব্যবহার করে চালানো হয়, যা একটি Future রিটার্ন করে।
৬. Slick টেস্টিং
Slick তে টেস্টিং করার জন্য Slick TestKit ব্যবহার করা হয়। এটি ইন-মেমরি ডেটাবেস এবং DBIO অ্যাকশন ব্যবহার করে টেস্টিং করতে সাহায্য করে।
import slick.jdbc.H2Profile.api._
val testDB = Database.forConfig("mydb")
// Define test query
val queryTest = testDB.run(users.result)সারাংশ
- Slick হল একটি ফাংশনাল রিলেশনাল মাপিং (FRM) লাইব্রেরি যা স্কালায় ডেটাবেসের সাথে যোগাযোগ করার জন্য ব্যবহৃত হয়।
- এটি SQL কোডের মতো স্টেটিক কোড লেখার চেয়ে ডেটাবেসের সাথে ফাংশনাল প্রোগ্রামিংয়ের মাধ্যমে যোগাযোগ করার সুবিধা দেয়।
- Slick লাইব্রেরি ব্যবহারের মাধ্যমে ডেটাবেস অপারেশনগুলো অ্যাসিঙ্ক্রোনাসলি পরিচালনা করা যায় এবং কার্যকরভাবে SQL এবং স্কালা কোডের মধ্যে সংযোগ স্থাপন করা যায়।
রিঅ্যাকটিভ ডাটাবেস প্রোগ্রামিং এমন একটি পদ্ধতি যার মাধ্যমে ডাটাবেস অ্যাপ্লিকেশনগুলি অ্যাসিঙ্ক্রোনাস, নন-ব্লকিং এবং স্ট্রীমিং উপায়ে ডেটা প্রসেস করে। এটি ইভেন্ট-ড্রিভেন এবং স্ট্রিমিং আর্কিটেকচার ব্যবহার করে ডাটাবেস অপারেশনগুলিকে আরও দ্রুত এবং স্কেলেবল করে তোলে। স্কালায় রিঅ্যাকটিভ ডাটাবেস প্রোগ্রামিং সাধারণত Akka Streams, Slick, Doobie, এবং Quill ব্যবহার করে করা হয়।
রিঅ্যাকটিভ ডাটাবেস প্রোগ্রামিংয়ের মূল লক্ষ্য হল ডাটাবেস অপারেশনগুলোকে অ্যাসিঙ্ক্রোনাসভাবে চালানো, যা আই/ও ব্লকিংকে এড়িয়ে যায় এবং ডাটাবেসে আরও দ্রুত প্রবেশাধিকার নিশ্চিত করে।
১. Akka Streams ব্যবহার করে রিঅ্যাকটিভ ডাটাবেস প্রোগ্রামিং
Akka Streams হল একটি রিঅ্যাকটিভ স্ট্রিম প্রসেসিং লাইব্রেরি যা Akka ফ্রেমওয়ার্কের অংশ। এটি ডেটা স্ট্রিমিং এবং অ্যাসিঙ্ক্রোনাস অপারেশন পরিচালনা করার জন্য ব্যবহৃত হয়। Akka Streams-এর মাধ্যমে ডাটাবেস থেকে ডেটা অ্যাসিঙ্ক্রোনাসভাবে স্ট্রীম করা এবং বিভিন্ন ডাটাবেস অপারেশন পরিচালনা করা যায়।
১.১ Akka Streams এবং Slick ব্যবহার করে রিঅ্যাকটিভ ডাটাবেস
Slick হল একটি Scala-based ডাটাবেস লাইব্রেরি যা অ্যাসিঙ্ক্রোনাস এবং রিঅ্যাকটিভ ডাটাবেস অপারেশন সাপোর্ট করে। এটি SQL কোয়েরি এবং টাইপ-সেফ ডাটাবেস অপারেশন চালানোর জন্য ব্যবহৃত হয়।
Akka Streams এবং Slick একসাথে ব্যবহার করার জন্য প্রথমে প্রয়োজনীয় লাইব্রেরি যোগ করতে হবে:
build.sbt ফাইল:
libraryDependencies += "com.typesafe.akka" %% "akka-stream" % "2.6.10",
"com.typesafe.slick" %% "slick" % "3.3.3",
"com.typesafe.slick" %% "slick-akka-streams" % "3.3.3"১.২ Akka Streams এবং Slick উদাহরণ
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl._
import slick.jdbc.H2Profile.api._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
// Define a case class and a table mapping
case class User(id: Int, name: String)
class Users(tag: Tag) extends Table[User](tag, "USER") {
def id = column[Int]("ID", O.PrimaryKey)
def name = column[String]("NAME")
def * = (id, name) <> (User.tupled, User.unapply)
}
object ReactiveDatabaseExample extends App {
implicit val system: ActorSystem = ActorSystem("ReactiveDatabase")
implicit val materializer: ActorMaterializer = ActorMaterializer()
val db = Database.forConfig("h2mem1") // Configure database connection in application.conf
val users = TableQuery[Users]
// Creating the table in the database
val setup = DBIO.seq(
users.schema.create,
users += User(1, "Alice"),
users += User(2, "Bob"),
users += User(3, "Charlie")
)
// Running the setup
db.run(setup)
// Querying the database and using Akka Streams for reactive processing
val queryStream: Future[Seq[User]] = db.stream(users.result).runWith(Sink.seq)
queryStream.onComplete {
case scala.util.Success(result) =>
println(s"Users: ${result.mkString(", ")}")
system.terminate()
case scala.util.Failure(ex) =>
println(s"Error occurred: $ex")
system.terminate()
}
}এখানে:
- Slick লাইব্রেরি ব্যবহার করে একটি ডাটাবেস টেবিল এবং সেই টেবিলের জন্য case class ডিফাইন করা হয়েছে।
- Akka Streams ব্যবহার করে ডাটাবেস থেকে
streamতৈরি করা হয়েছে, যা asynchronous এবং non-blocking। db.streamকমান্ড দিয়ে অ্যাসিঙ্ক্রোনাস কোয়েরি চালানো হচ্ছে এবংrunWith(Sink.seq)দিয়ে প্রাপ্ত ডেটা Akka Streams এর মাধ্যমে প্রসেস করা হচ্ছে।
২. Doobie ব্যবহার করে রিঅ্যাকটিভ ডাটাবেস প্রোগ্রামিং
Doobie হল একটি Scala লাইব্রেরি যা SQL কোয়েরি চালানোর জন্য ব্যবহৃত হয় এবং এটি cats-effect এবং FS2 স্ট্রিমিং লাইব্রেরির ওপর ভিত্তি করে। Doobie একটি functional API প্রদান করে এবং asynchronous ডাটাবেস অপারেশন করে।
২.১ Doobie লাইব্রেরি সেটআপ
build.sbt ফাইল:
libraryDependencies += "org.tpolecat" %% "doobie-core" % "0.8.8",
"org.tpolecat" %% "doobie-h2" % "0.8.8",
"org.tpolecat" %% "doobie-scalatest" % "0.8.8" % "test"২.২ Doobie উদাহরণ
import doobie._
import doobie.implicits._
import cats.effect.IO
import cats.effect.unsafe.implicits.global
case class User(id: Int, name: String)
object DoobieExample extends App {
val xa: Transactor[IO] = Transactor.fromDriverManager[IO](
"org.h2.Driver", // JDBC driver
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", // URL
"sa", // Username
"" // Password
)
// Query to insert data
val insertQuery: ConnectionIO[Int] = sql"insert into users (name) values ('Alice')".update.run
// Query to retrieve data
val selectQuery: ConnectionIO[List[User]] = sql"select id, name from users".query[User].to[List]
// Running the insert query
val setup = insertQuery.transact(xa)
// Running the select query
val fetch = selectQuery.transact(xa)
// Fetching and printing results
setup.unsafeRunSync() // Perform the insert
val result = fetch.unsafeRunSync() // Fetch the users
println(result) // Output: List(User(1,Alice))
}এখানে:
- Doobie লাইব্রেরি ব্যবহার করে SQL কোয়েরি চালানো হয়েছে এবং
Transactorদিয়ে ডাটাবেস সংযোগ করা হয়েছে। - Cats Effect ব্যবহার করে IO মনডান পরিচালনা করা হচ্ছে, এবং
unsafeRunSync()ব্যবহার করে অ্যাসিঙ্ক্রোনাস অপারেশনকে সিঙ্ক্রোনাসভাবে চালানো হয়েছে।
৩. Quill ব্যবহার করে রিঅ্যাকটিভ ডাটাবেস প্রোগ্রামিং
Quill একটি লাইব্রেরি যা স্কালার জন্য compile-time SQL query generation প্রদান করে। এটি ডাটাবেসের সাথে কার্যকরীভাবে কাজ করার জন্য ব্যবহৃত হয় এবং asynchronous ডেটাবেস অপারেশনকে সহজ করে তোলে।
৩.১ Quill লাইব্রেরি সেটআপ
build.sbt ফাইল:
libraryDependencies += "io.getquill" %% "quill-jdbc" % "3.9.0"৩.২ Quill উদাহরণ
import io.getquill._
case class Person(id: Int, name: String)
object QuillExample extends App {
val ctx = new MysqlJdbcContext[SnakeCase](SnakeCase)
import ctx._
val people = quote {
query[Person]
}
val insertAction = quote {
(name: String) => query[Person].insert(_.name -> name)
}
// Running the query asynchronously
val result = ctx.run(insertAction("John"))
// Execute the insertion
ctx.close()
}এখানে:
- Quill ব্যবহার করে SQL কোয়েরি তৈরি করা এবং query দিয়ে
Personঅবজেক্টের ইনসার্ট করা হয়েছে। - Quill asynchronous ডেটাবেস অপারেশন পরিচালনা করতে সক্ষম।
সারাংশ
- রিঅ্যাকটিভ ডাটাবেস প্রোগ্রামিং একটি শক্তিশালী পদ্ধতি, যার মাধ্যমে অ্যাসিঙ্ক্রোনাস, নন-ব্লকিং, এবং স্ট্রীমিং ডেটাবেস অপারেশন করা যায়।
- **Ak
ka Streams**, Slick, Doobie, এবং Quill লাইব্রেরিগুলি স্কালায় রিঅ্যাকটিভ ডাটাবেস প্রোগ্রামিংয়ের জন্য ব্যবহৃত হয়।
- এই লাইব্রেরিগুলি ডাটাবেসের সাথে অ্যাসিঙ্ক্রোনাস অপারেশনগুলো দ্রুত এবং স্কেলেবল করতে সাহায্য করে, এবং ডেটার স্ট্রীমিং প্রক্রিয়া সহজ করে তোলে।
স্কালা ডেটাবেস স্কিমা এবং ORM (Object Relational Mapping) ব্যবহারের মাধ্যমে, আপনি ডেটাবেসের টেবিলগুলির সাথে কোডকে সংযুক্ত করতে পারেন এবং ডেটাবেস অপারেশন যেমন CRUD (Create, Read, Update, Delete) সহজে পরিচালনা করতে পারেন। স্কালার জন্য বেশ কিছু শক্তিশালী ORM লাইব্রেরি এবং ফ্রেমওয়ার্ক রয়েছে, যেমন Slick এবং Doobie, যা ডেটাবেস ম্যানিপুলেশনকে আরও কার্যকরী এবং সুসংগঠিত করে তোলে।
এই লেখায় আমরা স্কালার ডেটাবেস স্কিমা এবং ORM সম্পর্কে বিস্তারিত জানবো, এবং কীভাবে সেগুলি ব্যবহার করতে হয় তা উদাহরণসহ ব্যাখ্যা করা হবে।
১. স্কালা ডেটাবেস স্কিমা (Database Schema)
ডেটাবেস স্কিমা হল ডেটাবেসের কাঠামো বা ডিজাইন, যা টেবিল এবং টেবিলের মধ্যে সম্পর্ক বর্ণনা করে। স্কালা ডেটাবেস স্কিমা তৈরি করতে, সাধারণত ORM ফ্রেমওয়ার্ক ব্যবহার করা হয়, যা স্কিমার ডিজাইন এবং ডেটাবেস ম্যানিপুলেশন সহজ করে তোলে।
২. স্কালা ORM ফ্রেমওয়ার্ক: Slick
Slick হল স্কালার জন্য একটি জনপ্রিয় ORM লাইব্রেরি, যা Functional Relational Mapping (FRM) ধারণায় কাজ করে এবং ডেটাবেসের সাথে সম্পর্কিত কার্যকলাপ সহজ এবং কার্যকরী করে তোলে। Slick কোডের মধ্যে SQL ক্যোয়ারি লেখার জন্য Scala DSL প্রদান করে, যার মাধ্যমে আপনি প্রোগ্রামিং ভাষাতেই ডেটাবেসের টেবিল এবং রিলেশন ডিফাইন করতে পারবেন।
Slick সেটআপ এবং কনফিগারেশন
Slick ডিপেন্ডেন্সি যোগ করা:
আপনার
build.sbtফাইলে Slick লাইব্রেরি এবং ডেটাবেস কনেকশন পুলের জন্য ডিপেন্ডেন্সি যোগ করুন:libraryDependencies ++= Seq( "com.typesafe.slick" %% "slick" % "3.3.3", "com.typesafe.slick" %% "slick-hikari" % "3.3.3", // Connection pool "com.h2database" % "h2" % "1.4.200" // H2 Database for example (can replace with another DB) )Slick স্কিমা এবং টেবিল ডিফাইন করা:
Slick-এ ডেটাবেস স্কিমা তৈরি করতে, আপনি
Tableট্রেইটটি ব্যবহার করেন যা টেবিলের জন্য একটি মডেল হিসেবে কাজ করে।উদাহরণ:
import slick.jdbc.H2Profile.api._ // টেবিল ডিফাইন করা class Users(tag: Tag) extends Table[(Int, String, String)](tag, "USERS") { def id = column[Int]("ID", O.PrimaryKey) def firstName = column[String]("FIRST_NAME") def lastName = column[String]("LAST_NAME") def * = (id, firstName, lastName) } val users = TableQuery[Users]এখানে:
Usersক্লাসটি একটি টেবিল মডেল, যেখানেid,firstName, এবংlastNameহল টেবিলের কলাম।TableQuery[Users]হল টেবিলের জন্য একটি কুয়েরি যা ডেটাবেসের সাথে যোগাযোগ করবে।
ডেটাবেস কনফিগারেশন এবং চালানো:
Slick-এর মাধ্যমে ডেটাবেসের সাথে কাজ করতে, আপনি
Databaseঅবজেক্ট ব্যবহার করে ডেটাবেস কনফিগারেশন এবং কননেকশন সেটআপ করেন।val db = Database.forConfig("h2mem1") // H2 database config in application.confডেটাবেস অপারেশন (CRUD):
স্লিক ব্যবহার করে ডেটাবেসের কার্যকরী অপারেশন যেমন CRUD করতে পারেন। এখানে একটি উদাহরণ:
val setup = DBIO.seq( // Create table users.schema.create, // Insert some data users += (1, "John", "Doe"), users += (2, "Jane", "Doe") ) val result = db.run(setup) result.onComplete { case Success(_) => println("Database setup complete") case Failure(ex) => println(s"Database setup failed: ${ex.getMessage}") }এখানে:
users.schema.create: টেবিল তৈরি করছে।users += (1, "John", "Doe"): ডেটাবেসে নতুন রেকর্ড ইনসার্ট করা হচ্ছে।
৩. Slick-এ কুয়েরি এবং ডেটা রিট্রিভাল
Slick-এ কুয়েরি করতে, আপনি filter, map, sortBy ইত্যাদি ফাংশন ব্যবহার করতে পারেন।
উদাহরণ: ডেটা রিট্রিভাল
val query = users.filter(_.firstName === "John").result
val result = db.run(query)
result.onComplete {
case Success(usersList) =>
usersList.foreach(println)
case Failure(ex) =>
println(s"Query failed: ${ex.getMessage}")
}এখানে:
filter(_.firstName === "John"): স্কিমার মধ্যেfirstNameকলাম থেকেJohnনামের ব্যবহারকারী খুঁজে বের করছে।result: এটি একটি কুয়েরি রেজাল্ট যা প্রাপ্ত ডেটার একটি ফিউচার হিসেবে রিটার্ন করবে।
৪. টাইপ সেফটি এবং টেবিল রিলেশন
Slick টাইপ সেফটি (Type Safety) বজায় রাখে, অর্থাৎ আপনি যখন কুয়েরি লিখবেন তখন এটি টাইপ চেকিং করবে এবং কম্পাইল টাইমে ত্রুটি ধরতে সহায়তা করবে।
উদাহরণ: রিলেশনাল টেবিল
ধরা যাক আমাদের দুটি টেবিল Users এবং Orders রয়েছে, এবং আমরা তাদের মধ্যে একটি সম্পর্ক তৈরি করতে চাই।
class Orders(tag: Tag) extends Table[(Int, Int, Double)](tag, "ORDERS") {
def id = column[Int]("ID", O.PrimaryKey)
def userId = column[Int]("USER_ID")
def amount = column[Double]("AMOUNT")
def user = foreignKey("user_fk", userId, users)(_.id)
def * = (id, userId, amount)
}এখানে:
foreignKey("user_fk", userId, users)(_.id): এটিOrdersটেবিলেরuserIdকলামকেUsersটেবিলেরidকলামের সাথে যুক্ত করে।
৫. Slick এবং টাইপ ক্লাস
Slick-এ টাইপ ক্লাসের মতো কনসেপ্ট ব্যবহার করা যায়, যেখানে আপনি এক্সটেনশন মেথড ব্যবহার করে কাস্টম কোড তৈরি করতে পারেন।
import slick.jdbc.MySQLProfile.api._
import slick.lifted.{TableQuery, Tag}
trait CustomTypes {
implicit val userStatusColumnType = MappedColumnType.base[UserStatus, String](
status => status.toString,
status => UserStatus.withName(status)
)
}এখানে:
MappedColumnType.baseএকটি কাস্টম টাইপ মেপিং তৈরি করছে, যাতেUserStatusটাইপকেString-এ রূপান্তরিত করা যাবে।
সারাংশ
- Slick একটি শক্তিশালী ORM লাইব্রেরি যা স্কালায় ডেটাবেস স্কিমা তৈরি এবং ডেটাবেসের সাথে সহজভাবে যোগাযোগ করতে সাহায্য করে। এটি SQL অপারেশনগুলোকে ফাংশনাল স্টাইল দিয়ে মোকাবেলা করে।
- Akka HTTP এর মাধ্যমে আপনি একটি reactive HTTP সার্ভার এবং ক্লায়েন্ট তৈরি করতে পারেন, যা রিয়েল-টাইম ডেটা প্রসেসিংয়ের জন্য উপযোগী।
- Slick ও Akka HTTP একত্রে ব্যবহার করে আপনি ডেটাবেস এবং HTTP কমিউনিকেশন ইন্টারঅ্যাক্টিভভাবে পরিচালনা করতে পারেন।
Read more