Hibernate Session & SessionFactory | Java ORM | Sinhala Guide

Hibernate Session & SessionFactory | Java ORM | Sinhala Guide

හැඳින්වීම (Introduction)

Java developersලාට database එකක් එක්ක වැඩ කරන්න තියෙන අමාරුකම් ගැන අමුතුවෙන් කියන්න ඕනේ නැහැනේ. SQL queries ලියන එක, Java objects database tables වලට map කරන එක, connections manage කරන එක... මේ හැම දේකටම ගොඩක් code ලියන්න වෙනවා, ඒ වගේම වැරදි වෙන්න තියෙන ඉඩකඩත් වැඩියි. අන්න ඒ වගේ තත්ත්වයකට perfect solution එකක් තමයි Hibernate කියන්නේ.

Hibernate කියන්නේ ජනප්‍රියම Object-Relational Mapping (ORM) framework එකක්. මේකෙන් අපිට පුළුවන් Java objects කෙලින්ම database tables වලට map කරලා, SQL ගැන වැඩිපුර හිතන්නේ නැතුව database operations කරන්න. ඒකෙන් developersලාට business logic එකට වැඩි අවධානයක් දෙන්න පුළුවන් වෙනවා.

අද මේ tutorial එකෙන් අපි බලමු Hibernate වල core components දෙකක් වන SessionFactory සහ Session කියන්නේ මොනවද, ඒවා එකිනෙකට වෙනස් වෙන්නේ කොහොමද, ඒවා කොහොමද හරියට පාවිච්චි කරන්නේ කියලා. අපි practical code examples එක්ක මේවා පැහැදිලිව ඉගෙන ගමු. එහෙනම්, අපි පටන් ගමු!

Hibernate කියන්නේ මොකක්ද?

සරලව කිව්වොත්, Hibernate කියන්නේ අපේ Java application එකේ objects (උදා: Student object එකක්) database එකේ tables වලට (උදා: students table එකට) map කරන්න උදව් කරන framework එකක්. මේ ක්‍රියාවලියට තමයි Object-Relational Mapping (ORM) කියන්නේ.

ORM framework එකක් පාවිච්චි කරනකොට අපිට කෙලින්ම SQL queries ලියනවා වෙනුවට Java objects එක්ක වැඩ කරන්න පුළුවන්. Hibernate විසින් database transactions, connection pooling, caching වගේ සංකීර්ණ දේවල් manage කරන නිසා අපිට ඒ ගැන වැඩිය හිතන්න අවශ්‍ය වෙන්නේ නැහැ.

SessionFactory කියන්නේ මොකක්ද?

Hibernate වල හදවත වගේ, ප්‍රධානම component එකක් තමයි SessionFactory කියන්නේ. මේකේ ප්‍රධාන වැඩේ තමයි database එකත් එක්ක connection pooling, caching වගේ දේවල් manage කරමින් Session objects හදාගන්න එක. SessionFactory එකක ලක්ෂණ කිහිපයක් මෙන්න:

  • Heavyweight Object: SessionFactory එකක් create කරන එක ටිකක් වෙලා යන වැඩක්. ඒකට Hibernate configuration, database connection details, mapping information වගේ ගොඩක් දේවල් load කරලා initialize කරන්න වෙනවා. ඒ නිසා, application එක start කරනකොටම එක පාරක් විතරක් create කරලා, application එක shutdown වෙනකල්ම ඒක use කරන්න recommend කරනවා.
  • Thread-Safe: SessionFactory එක thread-safe නිසා, එකම instance එක application එකේ ඕනෑම thread එකකට share කරන්න පුළුවන්. ඒකෙන් resources නාස්ති වීම වළක්වනවා.
  • Configuration Details: Hibernate වල database connection details (URL, username, password), mapping files (.hbm.xml) හෝ Annotation based entity classes වගේ හැම configuration detail එකක්ම SessionFactory එක ඇතුළේ තියෙනවා.
  • Second-Level Cache: SessionFactory එක application-level cache එකක් (second-level cache) maintain කරනවා. මේකෙන් application එකේ විවිධ Session objects හරහා එකම data එක නැවත නැවත database එකෙන් load කරන එක වළක්වා ගන්න පුළුවන්.

SessionFactory එකක් Configure කරලා හදාගන්නේ කොහොමද?

SessionFactory එකක් හදාගන්න විවිධ ක්‍රම තියෙනවා (උදා: XML configuration, Annotation configuration, Programmatic configuration). අපි බලමු StandardServiceRegistryBuilder එක use කරලා කොහොමද ඒක කරන්නේ කියලා. සාමාන්‍යයෙන් hibernate.cfg.xml කියන configuration file එකක් භාවිතා කරනවා.

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                // Configuration object එකක් හදනවා
                Configuration configuration = new Configuration();
                // hibernate.cfg.xml file එක load කරනවා
                configuration.configure("hibernate.cfg.xml");
                
                // Entity classes add කරන්න පුළුවන් (Annotations use කරනවනම්)
                // configuration.addAnnotatedClass(User.class);
                // configuration.addAnnotatedClass(Product.class);

                ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                    .applySettings(configuration.getProperties()).build();

                sessionFactory = configuration.buildSessionFactory(serviceRegistry);
                
            } catch (Exception e) {
                e.printStackTrace();
                if (serviceRegistry != null) {
                    StandardServiceRegistryBuilder.destroy(serviceRegistry);
                }
            }
        }
        return sessionFactory;
    }

    public static void shutdown() {
        if (sessionFactory != null) {
            sessionFactory.close();
        }
    }
}

hibernate.cfg.xml file එකක් මෙන්න මේ වගේ වෙන්න පුළුවන්:

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- Database connection properties -->
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">your_password</property>
        
        <!-- Dialect for your database -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
        
        <!-- Show generated SQL in console -->
        <property name="hibernate.show_sql">true</property>
        
        <!-- Automatically update the database schema -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        
        <!-- Entity mapping here (if using XML mapping or for annotations to be registered) -->
        <mapping class="com.example.model.User"/>
        
    </session-factory>
</hibernate-configuration>

Session කියන්නේ මොකක්ද?

SessionFactory එකෙන් හදාගන්න පුළුවන් object එක තමයි Session කියන්නේ. Session එක තමයි database එකත් එක්ක සෘජුවම අන්තර් ක්‍රියා කරන්න (interaction) භාවිතා වෙන්නේ. මේක Hibernate වල “unit of work” එකක් විදියටත් හඳුන්වන්න පුළුවන්.

  • Lightweight Object: Session එකක් create කරන එක ගොඩක් වේගවත්. ඒක thread-safe නෙවෙයි. ඒ කියන්නේ, එක් thread එකක් සඳහා එක් Session එකක් විතරක් පාවිච්චි කරන්න ඕනේ.
  • Short-Lived: Session එක සාමාන්‍යයෙන් එක් database transaction එකකට හෝ එක් client request එකකට විතරක් use කරන්න recommend කරනවා. Transaction එක ඉවර වුණාම හෝ request එක ඉවර වුණාම Session එක close කරන්න ඕනේ.
  • First-Level Cache: Session එක first-level cache එකක් (session-level cache) maintain කරනවා. මේක transaction එකක් ඇතුළේ එකම entity එක නැවත නැවත database එකෙන් load කරන එක වළක්වනවා.
  • CRUD Operations: Data saving, retrieving, updating, deleting (CRUD operations) වගේ හැම database interaction එකක්ම Session object එක හරහා තමයි සිද්ධ වෙන්නේ.

Session එකක් පාවිච්චි කරන්නේ කොහොමද? (Practical Example)

අපි හිතමු අපිට User කියන entity එකක් database එකට save කරන්න ඕනේ කියලා. මුලින්ම User entity class එක හදාගමු:

import javax.persistence.*;

@Entity
@Table(name = "users") // database table name එක specify කරන්න පුළුවන්
public class User {
    @Id // Primary key එක identify කරනවා
    @GeneratedValue(strategy = GenerationType.IDENTITY) // Auto-increment ID එකක් generate කරන්න
    private Long id;
    private String name;
    private String email;

    // Constructors
    public User() {
    }

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
               "id=" + id +
               ", name='" + name + '\'' +
               ", email='" + email + '\'' +
               '}';
    }
}

දැන් අපි බලමු User object එකක් database එකට save කරන්නේ කොහොමද කියලා Session එක use කරලා:

import org.hibernate.Session;
import org.hibernate.Transaction;

public class UserDAO {

    public void saveUser(User user) {
        Session session = null;
        Transaction transaction = null;

        try {
            // HibernateUtil එකෙන් SessionFactory එක ලබා ගන්නවා
            session = HibernateUtil.getSessionFactory().openSession(); 
            transaction = session.beginTransaction(); // Transaction එකක් පටන් ගන්නවා

            session.save(user); // User object එක database එකට save කරනවා

            transaction.commit(); // Transaction එක commit කරනවා (වෙනස්කම් database එකට යවනවා)
            System.out.println("User saved successfully: " + user.getName());

        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback(); // මොකක් හරි වැරැද්දක් වුණොත් rollback කරනවා
            }
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close(); // Session එක close කරන්න අමතක කරන්න එපා
            }
        }
    }

    public User getUserById(Long id) {
        Session session = null;
        try {
            session = HibernateUtil.getSessionFactory().openSession();
            return session.get(User.class, id); // ID එකට අදාළ User object එක ලබා ගන්නවා
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }
    
    public static void main(String[] args) {
        UserDAO userDAO = new UserDAO();

        // Save a new user
        User newUser = new User("Kasun Silva", "[email protected]");
        userDAO.saveUser(newUser);

        // Get a user by ID
        User fetchedUser = userDAO.getUserById(newUser.getId());
        if (fetchedUser != null) {
            System.out.println("Fetched User: " + fetchedUser);
        } else {
            System.out.println("User not found.");
        }
        
        // Shutdown the SessionFactory when application exits
        HibernateUtil.shutdown();
    }
}

මේ code එකෙන් පෙන්නන්නේ Session එකක් use කරලා කොහොමද database එකට data save කරන්නේ සහ retrieve කරන්නේ කියලා. session.update(), session.delete() වගේ methods වලින් අනිත් CRUD operations ටිකත් කරන්න පුළුවන්.

SessionFactory සහ Session අතර වෙනස

මේ components දෙක Hibernate වල අත්‍යාවශ්‍ය වුවත්, ඒවායේ කාර්යභාරය සහ lifecycle එක සම්පූර්ණයෙන්ම වෙනස්. ප්‍රධාන වෙනස්කම් ටිකක් මෙන්න:

වෙනසSessionFactorySession
ScopeApplication-wide (application එකේ මුළු කාලය පුරාම තියෙනවා).Transaction-wide or Request-wide (කෙටි කාලීනයි).
CreationHeavyweight, creation takes time, create once per application.Lightweight, creation is fast, create per transaction/request.
Thread-SafetyThread-safe (එකම instance එක share කරන්න පුළුවන්).Not thread-safe (එක් thread එකක් සඳහා එක් Session එකක් තිබිය යුතුයි).
CachingMaintains Second-Level Cache (application-level, multiple sessions සඳහා).Maintains First-Level Cache (transaction-level, current session සඳහා).
Purposedatabase සම්බන්ධතා, configuration, Session objects නිර්මාණය කිරීම කළමනාකරණය කරයි.database සමඟ සෘජුවම අන්තර් ක්‍රියා කරයි (CRUD operations).
InstantiationConfiguration.buildSessionFactory() මගින් නිර්මාණය කරයි.SessionFactory.openSession() මගින් නිර්මාණය කරයි.

හොඳම පුරුදු (Best Practices)

SessionFactory සහ Session use කරනකොට මතක තියාගන්න ඕනේ වැදගත් දේවල් කිහිපයක් තියෙනවා. මේවා අනුගමනය කිරීමෙන් ඔයාලගේ application එක වඩාත් stable, efficient සහ bug-free කරගන්න පුළුවන්:

  1. SessionFactory එක Single Instance එකක් විදියට තියාගන්න: Application එකේ එකම SessionFactory instance එකක් maintain කරන්න. ඒක static field එකක තියාගෙන හෝ Singleton design pattern එකක් use කරලා manage කරන්න පුළුවන්. අපේ උදාහරණයේ HibernateUtil class එක ඒකට හොඳම විසඳුමක්.
  2. Session එක නිතරම Close කරන්න: Session එකක් වැඩේ අවසන් වුණාම session.close() call කරන්න අමතක කරන්න එපා. එහෙම නොකළොත් database connections leak වෙලා memory issues ඇති වෙන්න පුළුවන්. try-catch-finally block එකක් ඇතුළේ finally block එකේදී session.close() කරන එක හොඳම පුරුද්දයි. Java 7+ වලදී try-with-resources statement එකත් පාවිච්චි කරන්න පුළුවන්.
  3. Transactions කළමනාකරණය කරන්න: Database එකට වෙනස්කම් කරන හැම operation එකක්ම transaction එකක් ඇතුළේ කරන්න. beginTransaction(), commit(), rollback() හරියට use කරන්න. Transaction එකක් සාර්ථකව අවසන් වුණොත් commit() කරන්න, නැත්නම් rollback() කරන්න.
  4. Error Handling: try-catch blocks use කරලා database errors හෝ Hibernate exceptions handle කරන්න. Transaction එකක් fail වුණොත් rollback() කරන එක ගොඩක් වැදගත්.
  5. Lazy vs. Eager Loading තේරුම් ගන්න: Hibernate relations වලදී (One-to-Many, Many-to-Many) data load කරන ක්‍රම දෙකක් තියෙනවා. Lazy loading වලින් අවශ්‍ය වෙලාවට විතරක් data load කරන නිසා performance එක වැඩි කරගන්න පුළුවන්. Eager loading වලින් අදාළ හැම data එකක්ම මුලින්ම load කරනවා. මේ දෙක අතරින් තත්ත්වයට ගැලපෙන එක තෝරා ගැනීම වැදගත්.

නිගමනය (Conclusion)

ඉතින් යාළුවනේ, මේ tutorial එකෙන් ඔයාලට Hibernate වල fundamental concepts දෙකක් වන SessionFactory සහ Session ගැන හොඳ අවබෝධයක් ලැබෙන්න ඇති කියලා හිතනවා. මේවා තමයි Hibernate වල හදවත වගේ ක්‍රියා කරන core components. Database operations effectively, safely manage කරන්න මේවා හරි විදියට භාවිතා කරන එක ගොඩක් වැදගත්.

SessionFactory එක application එකේ resource එකක් විදියට manage කරන අතර, Session එක එක් transaction එකක් සඳහා database සමග අන්තර්ක්‍රියා කරන්න අපිට උදව් කරනවා. මේ දෙකේම lifecycle එක, thread-safety, සහ caching mechanisms ගැන හොඳින් තේරුම් ගැනීමෙන් Hibernate වල වැඩිම ප්‍රයෝජන ගන්න පුළුවන්.

ඔයාලගේම project එකකදී මේ concepts ටික implement කරලා බලන්න. මොනවා හරි ප්‍රශ්න තියෙනවා නම්, තව දැනගන්න ඕනේ දේවල් තියෙනවා නම්, පහළින් comment කරන්න. හැමදාම වගේ කියන්නේ, code කරලාම ඉගෙන ගන්න එක තමයි හොඳම දේ! Happy coding!