Hibernate

In modern Java development, managing database interactions efficiently is crucial. Spring Data JPA, a powerful abstraction over JPA, uses Hibernate internally as its default ORM provider to simplify persistence logic. This article explores persistence from JDBC to Hibernate, dives deep into Hibernate’s features—including relationships—and ties it all together with Spring Data JPA, covering every essential concept with examples and interview-ready insights.


Persistence Logic: The Foundation

Persistence logic refers to code handling CRUD (Create, Read, Update, Delete) operations between an application and a database. In Java, we have:

- Technology: JDBC (Java Database Connectivity)

- Frameworks: ORM tools like Hibernate, JPA, Spring ORM, and Spring Data JPA (the current “hotcake”).


JDBC: The Baseline and Its Limitations

JDBC is foundational but has drawbacks:

1. Non-Portable: SQL queries are database-specific, clashing with Java’s “Write Once, Run Anywhere” (WORA).

2. Boilerplate Code: Repetitive steps like connection setup, statement creation, and resource closure bloat your codebase.

- Example: Connection con = DriverManager.getConnection(url, user, pass); PreparedStatement ps = con.prepareStatement(query);

3. SQLException: A single checked exception forces try-catch or throws clauses.

4. No Detailed Exceptions: Lacks a hierarchy for specific issues.

5. Non-Serializable ResultSet: Can’t send over networks; requires manual POJO mapping.

6. Resource Management: Closing connections risks NullPointerException without careful checks (e.g., if (con != null) con.close(); in a finally block).

7. No Object Support: Queries expect values, not objects, limiting OOP.

8. Weak Transaction Management: Only local transactions, no global support.

9. Positional Parameters Only: insert into student values(?,?,?)—no named parameters like :name.

10. SQL Expertise Required: Developers must master SQL syntax.

11. No Versioning/Timestamping: No built-in tracking of record changes.


Enter ORM and Hibernate

Object-Relational Mapping (ORM) bridges Java objects and database tables, solving JDBC’s woes. Hibernate, built on the Java Persistence API (JPA), maps classes to tables via annotations or XML.


Spring Data JPA: Hibernate Under the Hood

Spring Data JPA abstracts Hibernate further, reducing boilerplate with repository interfaces. It leverages Hibernate’s features internally while adding declarative query methods.

Example Repository:

  import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
      Employee findByName(String name); // Auto-generated query
  }        

Usage:

  @Autowired
  EmployeeRepository repo;
  Employee emp = new Employee("Alice");
  repo.save(emp); // Hibernate handles persistence        

Hibernate Core Components

1. Model Class (Entity):

Rules: Package, public, @Entity, @Id, private fields, no-arg constructor, getters/setters, optional @Version or @Temporal.

Example:

@Entity
     @Table(name = "employees")
     public class Employee {
         @Id
         @GeneratedValue(strategy = GenerationType.IDENTITY)
         private Integer id;
         @Column(name = "ename")
         private String name;
         @Version
         private int version; // Tracks updates
         public Employee() {}
         public Employee(String name) { this.name = name; }
     }        


2. Mapping:

Annotations: @Table, @Column, @Id.

XML:

<hibernate-mapping>
    <class name="com.example.Employee" table="employees">
        <id name="id" column="eid"/>
        <property name="name" column="ename"/>
    </class>
</hibernate-mapping>        

3. Configuration File (`hibernate.cfg.xml`):

   <hibernate-configuration>
    <session-factory>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/testdb</property>
        <property name="connection.username">root</property>
        <property name="connection.password">password</property>
        <!-- Dialect: DB-specific SQL generation -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="hbm2ddl.auto">update</property>
        <mapping class="com.example.Employee"/>
    </session-factory>
</hibernate-configuration>        

Dialect: Translates Hibernate operations to DB-specific SQL (e.g., MySQLDialect, OracleDialect).

Programmatic Alternative:

   Configuration cfg = new Configuration()
    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
    .addAnnotatedClass(Employee.class);        

4. Test Class Flow:

- Create SessionFactory → Open Session → Begin Transaction (if non-select) → Perform operation → Commit/Rollback → Close.


CRUD Operations: Methods & Rules

1. Create:

- save(): Returns ID, supports generators.

- persist(): Void, JPA-compliant, no generator support.

- Example:

 Session session = factory.openSession();
Transaction tx = session.beginTransaction();
Employee emp = new Employee("Bob");
session.save(emp); // SQL: insert into employees (ename) values ('Bob')
tx.commit();        

2. Read:

- get(): Eager loading, returns null if not found.

- load(): Lazy loading, throws ObjectNotFoundException.

- Example:

Employee emp = session.get(Employee.class, 1); // Immediate DB hit
Employee proxy = session.load(Employee.class, 1); // Proxy until name accessed        

3. Update:

- update(): Direct update, assumes record exists.

- saveOrUpdate(): Insert if new, update if exists.

- merge(): Updates loaded object.

- Example:

  Employee emp = session.get(Employee.class, 1);
emp.setName("Bob Updated");
session.merge(emp); // SQL: update employees set ename='Bob Updated' where eid=1        

4. Delete:

- delete(): Removes by ID.

- Example:

Employee emp = session.get(Employee.class, 1);
session.delete(emp); // SQL: delete from employees where eid=1        

Relationships in Hibernate

1. @Embeddable:

- Embeds a class as a composite value within an entity.

- Example:

 @Embeddable
public class Address {
    private String city;
    private String country;
    // Getters, setters
}

@Entity
public class Employee {
    @Id
    private Integer id;
    private String name;
    @Embedded
    private Address address;
    // Constructors, getters, setters
}        

2. OneToOne:

- One entity linked uniquely to another.

- Example:

 @Entity
public class Employee {
    @Id
    private Integer id;
    private String name;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "passport_id")
    private Passport passport;
}

@Entity
public class Passport {
    @Id
    private Integer id;
    private String number;
    @OneToOne(mappedBy = "passport")
    private Employee employee;
}        

3. OneToMany & ManyToOne:

- One entity has many of another; the reverse is ManyToOne.

- Example:

 @Entity
public class Department {
    @Id
    private Integer id;
    private String name;
    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
    private List<Employee> employees;
}

@Entity
public class Employee {
    @Id
    private Integer id;
    private String name;
    @ManyToOne
    @JoinColumn(name = "dept_id")
    private Department department;
}        

4. ManyToMany:

- Multiple entities linked to multiple others via a join table.

- Example:

 @Entity
public class Student {
    @Id
    private Integer id;
    private String name;
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "student_course",
        joinColumns = @JoinColumn(name = "student_id"),
        inverseJoinColumns = @JoinColumn(name = "course_id"))
    private List<Course> courses;
}

@Entity
public class Course {
    @Id
    private Integer id;
    private String title;
    @ManyToMany(mappedBy = "courses")
    private List<Student> students;
}        

Querying in Hibernate

1. HQL (Hibernate Query Language):

- Object-oriented, works with entities, not tables.

- Example:

Query<Employee> query = session.createQuery("from Employee e where e.name = :name", Employee.class);
query.setParameter("name", "Bob");
List<Employee> employees = query.list(); // SQL: select * from employees where ename='Bob'        

2. Native SQL Queries:

- Use raw SQL when HQL isn’t enough.

- Example:

Query<Employee> query = session.createNativeQuery("select * from employees where ename = :name", Employee.class);
query.setParameter("name", "Bob");
List<Employee> employees = query.getResultList();        

3. Stored Procedures:

- Execute database stored procedures.

- Example (Assuming a procedure getEmployeeById):

 Query<Employee> query = session.createStoredProcedureQuery("getEmployeeById", Employee.class)
    .registerStoredProcedureParameter("empId", Integer.class, ParameterMode.IN)
    .setParameter("empId", 1);
Employee emp = query.getSingleResult();        

Advanced Features

1. Date & Time:

- JDBC: Manual conversion of java.sql.*.

- Hibernate: Native java.time.* support (e.g., LocalDate, LocalDateTime), no conversions needed with @Temporal for older java.util.Date.

- Example:

   @Entity
public class Person {
    @Id
    private int id;
    private LocalDate dob;
    // Setters: person.setDob(LocalDate.of(1990, 1, 1));
}        

2. Caching:

- First-Level Cache (L1): Default, tied to Session. Stores objects until commit().

- Example: session.get(Employee.class, 1) caches in L1.

- Methods: evict(obj), clear().

- Second-Level Cache (L2): Global, tied toSessionFactory, configurable with EHCache.

- Setup:

- ehcache.xml:

 <ehcache>
    <defaultCache maxElementsInMemory="100" timeToLiveSeconds="30"/>
</ehcache>        

- hibernate.cfg.xml:

<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>              

- Entity:

@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Employee { ... }        

- Example:

Employee emp = session.get(Employee.class, 1); // Cached in L1 & L2        

3. Versioning:

- @Version: Tracks modifications with a numeric column.

- Example:

@Version
private int version; // Increments on update        

4. Timestamping:

- @CreationTimestamp, @UpdateTimestamp: Logs record creation and last update.

- Example:

@CreationTimestamp
private LocalDateTime created;
@UpdateTimestamp
private LocalDateTime updated;        

5. Generators:

- Hibernate: identity, increment, sequence.

- JPA: GenerationType.IDENTITY, AUTO.

- Custom: Implement IdentifierGenerator.

- Example:

 public class CustomGenerator implements IdentifierGenerator {
    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) {
        return "FIRST" + String.format("%04d", new Random().nextInt(10000));
    }
}
@GenericGenerator(name = "custom", strategy = "com.example.CustomGenerator")
@GeneratedValue(generator = "custom")
private String id;        

6. LOBs:

- @Lob: For large objects like byte[] (photos) or char[] (resumes).

- Example:

 @Lob
private byte[] photo;        

7. Transaction Management:

- Local: session.beginTransaction().

- Global: Requires JTA (not native in JDBC).

Here is my Hibernate project: [Github]


要查看或添加评论,请登录

Jashwanth Jampala的更多文章

  • Spring Framework

    Spring Framework

    As Java developers, we constantly seek ways to write cleaner, more efficient code. The Spring Framework (stable version…

    2 条评论
  • JDBC

    JDBC

    ?? Why You Should Still Learn Core JDBC in the Era of Spring Data JPA Nowadays, developers rely heavily on Spring Data…

    1 条评论
  • Comparator vs Comparable in Java

    Comparator vs Comparable in Java

    Comparable is used at the class level in Java, while Comparator is used at the object level. ? Comparable (Class-Level)…

    1 条评论
  • Introduction to Java Predefined Functional Interfaces

    Introduction to Java Predefined Functional Interfaces

    Hi everyone! Today, I’m excited to discuss some of the predefined functional interfaces in Java that are commonly used…

    4 条评论

社区洞察