Data Persistence means storing the data permanently
Data Persistence has 3 components
Data : represents what to persist Medium : represents how to persist Storage : represents where to persist
Data : Data can be of two types
1. Raw Data 2. Java Object
Medium : Medium can be of three types
1. Java I/O Streams 2. Serialization / De-serialization 3. JDBC (Java Database Connectivity)
Storage : Storage can be of two types
1. File 2. Database
Serialization : It is a process of converting Java object into a stream of bytes. Now these stream of bytes can be stored in a file or can be transferred over a network.
De-Serialization : It is the processing converting a stream of bytes into a Java object.
1. Data Redundancy 2. Data Inconsistency 3. Data Security 4. Storage 5. No transaction support 6. No constraints support
JDBC technology can be used to perform CRUD operations on the data of a Database.
C ---> Create (inserting) R ---> Read (selecting) U ---> Update (modifying) D ---> Delete (removing)
Requirement : I have an Employee object, I want to store the Employee object into a Database using JDBC API ?
executeUpdate(employee) ---> error
executeQueryCemployee) ---> error
insert into emp_table values (employee) ---> error
Solution :
PreparedStatement
object of JDBCPreparedStatement
and then execute itNote: We can't transfer raw data using ORM tools.
Q) What is the difference between writing the DAO classes directly using Hibernate and using JPA ?
select * from emp ---> SQL
select e from Employee e ---> HQL
select empno, ename from emp ---> SQL
select e.employeeNo, e.employeeName from Employee e ---> HQL
Caching improves the performance of an application by loading the objects from cache memory.
In Hibernate, 2 levels cache can be used.
1. Level1 2. Level2
select * from emp ---> untuned query
select empno, ename, sat, deptno from emp ---> tuned query
By default, multiple transactions can work on the same data concurrently.
When multiple tx's are working on same data concurrently, one tx made changes can be overridden by the another tx.
To prevent it, Hibernate has provided locking.
Two types locking can be used when multiple tx's are working on the same data.
1. Optimistic Locking 2. Pessimistic Locking
Hibernate supports associations/ relationships
1. One-to-Many 2. Many-to-One 3. Many-to-Many 4. One-to-One
java.io.Serializable
is called as a POJO class. // Example-1
class A {
// variables
// methods
}
// Example-2
class B extends A {
// variables
// methods
}
A Java class which follows the below rules can be called as a Java Bean class.
1) class must be public 2) class must contain default / parameter-less constructor 3) private members should contain setter / getter methods 4) class can implement Serializable interface
Note: Every Java bean class is a POJO class. But every POJO class is not a Java Bean class.
Mapping file is used to map a java class with a database table and java class variables with table columns.
Mapping can be done in 2 ways
1. xml file 2. annotations (JPA)
Mapping filename can be any name but the extension must be .hbm.xml
We use below attributes to map Java class fields with database table columns
Id ---> Primary Key property ---> Non-Primary Key
<!-- student.hbm.xml -->
<hibernate-mapping>
<class name="in.ashokit.entity.Student" table="TBL_STUDENT">
<id name="sid" column="SID" />
<property name="sname" column="SNAME" />
<property name="gender" column="GENDER" />
<property name="marks" column="MARKS" />
</class>
</hibernate-mapping>
<!-- student.hbm.xml -->
<hibernate-mapping>
<class name="in.ashokit.entity.Student" table="TBL_STUDENT">
<id name="sid" />
<property name="sname" />
<property name="gender" />
<property name="marks" />
</class>
</hibernate-mapping>
Configuration file is for configuring the below things
1. Connection Properties 2. Hibernate Properties 3. Mapping Files
Configuration filename can be any but the extension must be .cfg.xml
. Generally we use hibernate.cfg.xml
as configuration filename.
*.hbm.xml ---> hibernate mapping xml file *.cfg.xml ---> configuration xml file
When a Hibernate application starts it will load configuration file only and configuration file will load all the mapping files.
<!-- hibernate.cfg.xml -->
<hibernate-configuration>
<session-factory>
<!-- connection properties -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hiberdb</property>
<property name="hibernate.connection.username">ashokit</property>
<property name="hibernate.connection.password">AshokIT@123</property>
<!-- hibernate properties -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- mapping resources -->
<mapping resource="student.hbm.xml" />
</session-factory>
</hibernate-configuration>
show_sql
will be false by default. If we set it to true then it will display the query prepared by hibernate on the console.format_sql
will be false by default. It is for formatting the query.hbm2ddl.auto will
create the table automatically, if table doesn't exist in the database.Note: If our application is using two databases (Ex: MySQL, Oracle) then two configuration files need to be created.
Steps to write the client program
1. create SessionFactory object 2. create Session object 3. create Transaction object 4. perform CRUD operations 5. commit/ rollback the transaction 6. close the session 7. close the session factory
High-level object in Hibernate is SessionFactory
object.
SessionFactory
object holds the configuration metadata.
SessionFactory
object is factory for creating Session
objects.
When a Session
is created, a connection with a database is established.
A Session object is the main runtime object to perform Database operations.
In real-time applications, a session object is created for each request.
A Session object can be used to create a Transaction object.
In Hibernate, Transaction is mandatory to perform insert / update / delete operations. For select operation, it is optional.
End the transaction with commit / rollback.
If no more operations are required, then close the session.
If no more sessions are required, then close the session factory object.
Visit Maven Official Website and download the zip file.
Extract the downloaded zip file.
Copy the bin folder path of maven and add it the Path variable (system variable)
Verify the maven settings using below command
mvn --version
Archetype is a template or blueprint for creating new Maven projects
simple java project ---> maven-archetype-quickstart web app project ---> maven-archetype-webapp
Group Id ---> a unique id to identify a group of projects of a client. Artifact ld ---> project name Version ---> project version
pom.xml
(project object model)C:\Users\{username}\.m2\repository
<!-- Hibernate Dependency -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId
<version>5.3.1.Final</version>
</dependency>
src/main/java ---> source code files src/test/java ---> test code files src/main/resources ---> for other resources/files (xml/properties/txt)
There are four allowed values for hibernate.hbm2ddl.auto
property
create update create-drop validate (default)
create : Hibernate drops the existing tables and creates new tables in DB to perform operations.
update : Hibernate uses existing tables to perform DB operations. If tables not exists it creates new tables in DB. (Only in Selected Databases).
create-drop : Hibernate creates new tables to perform operations and drops the tables at the end of the application. Mostly used in unit-testing.
validate : Hibernate validates the tables and columns in the Database. If a table/column doesn't exist, it will throw an exception. This is the default value of this property.
LazyInitializationException
will be thrown.ObjectNotFoundException
.Q) Can we map a table without primary key to a java class ?
Ans : Yes, we can map a table which does not have a primary key to a java class and we can insert the records into the table also. But as the table does not have a primary key we can not retrieve the data from the table.
// How Level1 Cache Works
Session first_session = factory.openSession();
Session second_session = factory.openSession();
Student s1 = first_session.get(Student.class, 11011);
Student s2 = first_session.get(Student.class, 11011);
Student s3 = second_session.get(Student.class, 11011);
Q) How many times Hibernate hits the database for the below code ?
Student s1 = first_session.get(Student.class, 11011);
Student s2 = first_session.get(Student.class, 22022);
Student s3 = first_session.get(Student.class, 11011);
Student s4 = second_session.get(Student.class, 11011);
Ans : 3 times
Q) Can we delete the cache of a session explicitly ?
Ans : We can't delete a cache explicitly. It is removed when session is closed .
Q) I want to remove a specific object from the cache ?
Ans : Yes. call evict() method to remove the object from cache.
session.evict(s1);
Q) I want to remove all the objects from cache at a time?
Ans : Yes. call clear() method to remove all objects from the cache.
session.clear();
Q) what is the drawback of the cache ?
Ans : If any changes are made to the object in database, they are not reflected in cache automatically. So sometimes we can get stale data from cache. This is the drawback.
Solution: You have to explicitly refresh the cache for every some time interval to make the object in cache are in sync with database.
javax.persistence
is the package name for JPA specification.@Entity : It will declare that a POJO class is an entity class.
@Table : It is used to map a POJO class with a table in the database. If the POJO class and database table name is same then writing this annotation is optional.
@Id : It is used to map a variable in our Java class with primary key column in the table.
@Column : It is used to map a variable with a column in the table. If the variable name and column name is same then writing this annotation is optional.
Q) Can we map a java class with a table, which has more variables ?
Ans: Yes. Use @Transient
annotation for a variable which does not have a corresponding column in the table.
Q) Can we map a java class with table having more columns ?
Ans: Yes. But if the remaining columns of the table does not contain not null constraint.
To use JPA with Hibernate as persistence provider, we have to create configuration file persistence.xml
under META-INF
directory.
This META-INF
directory must be created under src/main/resources
folder.
This file is similar to the Hibernate configuration file hibernate.cfg.xml
.
Root element of the persistence.xml
is persistence
.
For each database one persistence-unit
element will be created.
There are two possible values for the transaction-type
RESOURCE_LOCAL ---> for single database JTA (Java Transaction API) ---> for more than one database
<!-- persistence.xml -->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<!-- Persistence provider -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- Entity classes -->
<class>in.ashokit.entity.ProductEntity</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/hiberdb" />
<property name="javax.persistence.jdbc.user" value="ashokit" />
<property name="javax.persistence.jdbc.password" value="AshokIT@123" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
Combination of columns as a primary key is called composite primary key.
To work with composite primary key in JPA, we have to create two classes
1) embeddable class 2) entity class with embedded id
Embeddable class should contain the variables to map with composite primary key columns. This class must implement Serializable
interface.
// Embeddable class
@Embeddable
public class StudentCompositeKey implements Serializable {
@Column(name="roll_no")
private Integer rollNo;
@Column(name="section")
private String section;
// setters & getters
}
// Entity class with embeddable id
@Entity
@Table(name="tbl_student")
public class StudentEntity {
@EmbeddedId
private StudentCompositeKey compositeKey;
@Column(name="name")
private String name;
@Column(name="marks")
private Integer marks;
// setters & getters
}
There are three entity states in JPA
Transient state Persistent state Detached state
Transient State : Whenever a new object is created for an entity class then that entity will be in transient state.
Persistent State : After setting the data to the entity, we are going to persist the entity to the database. Now the entity is in persistent state.
Detached State : When entity manager is closed or when cleared or when an object is detached then the entity enters into detached state.
Q) Suppose I'm calling find() method then how many objects can be loaded at a time from the database ?
Ans: one object
Q) Suppose I'm calling remove() method then how many objects can be removed at a time from the DB ?
Ans: one object
Q) How can I load or update or delete multiple objects or bulk objects at a time from the Database ?
Ans: Use JPQL or SQL queries.
select * from emp ---> SQL
select e from EmployeeEntity e ---> JPQL
from EmployeeEntity e ---> JPQL
select ename, sal from emp ---> SQL
select e.employeeName, e.salary from EmployeeEntity e ---> JPQL
select * from emp where sal > ? ---> SQL
select e from EmployeeEntity e where e.salary > ?1 ---> JPQL
from EmployeeEntity e where e.salary > ?1 ---> JPQL
select * from emp where deptno = ? and sal > ? ---> SQL
select e from EmployeeEntity e where e.deptNo = ?1 and e.salary > ?2 ---> JPQL
from EmployeeEntity e where e.deptNo = ?1 and e.salary > ?2 ---> JPQL
from EmployeeEntity e where e.deptNo = :dno and e.salary > :esal ---> JPQL
update emp set sal = ? where deptno = ? ---> SQL
update EmployeeEntity e set e.salary = ?1 where e.deptNo = ?2 ---> JPQL
update EmployeeEntity e set e.salary = :esal where e.deptNo = :dno ---> JPQL
select e.ename, d.dname from emp e join dept d on e.deptno = d.deptno ---> SQL
select e.empName, d.deptName from EmployeeEntity e join DepartmentEntity d on e.deptNo = d.deptNo ---> JPQL
To run a JPQL query we have to follow the below three steps
1. create Query object 2. set the parameter values 3. execute it
To execute a JPQL query we have below three methods
getSingleResult() ---> returns a single entity getResultList() ---> returns multiple entities executeUpdate() ---> to execute update/delete statements.
// Selecting employees based on deptNo using JPQL
String jpql = "from EmployeeEntity e where e.deptNo = ?1";
Query q = entityManager.createQuery(jpql); // step-1
q.setParameter(1, 20); // step-2
// retrive multiple entities
List listOfEmployees = q.getResultList(); // step-3
// Selecting employee based on empNo using JPQL
String jpql = "from EmployeeEntity e where e.empNo = ?1";
Query q = entityManager.createQuery(jpql); // step-1
q.setParameter(1, 7788); // step-2
// retrives a single entity
Object obj = q.getSingleResult(); // step-3
// Updating salaries based on deptNo using JPQL
String jpql = "update EmployeeEntity e set e.salary = :esal where e.deptNo = :dno";
Query q = entityManager.createQuery(jpql); // step-1
q.setParameter("esal", 20000.0); // step-2
q.setParameter("dno", 30); // step-2
// for non-select operations tx is required
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
int rowsEffected = q.executeUpdate(); // step-3
tx.commit();
There are three type of queries in JPA
1. Typed Queries 2. Native Queries 3. Named Queries
TypedQuery
object.TypedQuery
is a sub interface of Query
interface.Query
object returns untyped results. Which means we need to do type casting the objects into entity type.TypedQuery
object returns typed results. So we don't need to do any type casting.createQuery()
method will return TypedQuery
object instead of Query
object. // Selecting employee based on empNo using Untyped query
String jpql = "from EmployeeEntity e where e.empNo = ?1";
Query q = entityManager.createQuery(jpql);
q.setParameter(1, 7788);
Object obj = q.getSingleResult();
EmployeeEntity e = (EmployeeEntity) obj; // casting
// Selecting employee based on empNo using Typed query
String jpql = "from EmployeeEntity e where e.empNo = ?1";
TypedQuery<EmployeeEntity> tq = entityManager.createQuery(jpql, EmployeeEntity.class);
tq.setParameter(1, 7788);
EmployeeEntity e = tq.getSingleResult(); // casting not required
// How to select specific properties of a entity using Typed query
String jpql = "select e.empName, e.salary from EmployeeEntity e";
TypedQuery<Object[]> tq = entityManager.createQuery(jpql, Object[].class);
List<Object[]> list = tq.getResultList();
// Selecting employees based on deptno using Native query
String sql = "select * from employee where deptno = ?";
Query nativeQuery = entityManager.createNativeQuery(sql, EmployeeEntity.class);
nativeQuery.setParameter(1, 30);
List empList = nativeQuery.getResultList();
// Updating salaries based on deptno using Native query
String sql = "update employee set sal = ? where deptno = ?";
Query nativeQuery = entityManager.createNativeQuery(sql);
nativeQuery.setParameter(1, 20000.0);
nativeQuery.setParameter(2, 30);
// for non-select operations tx is required
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
int count = nativeQuery.executeUpdate();
tx.commit();
@NamedNativeQuery
annotation is used for defining SQL queries at entity class. // Entity class with named query & named native query
@Entity
@Table(name="employee")
@NamedQuery(name="query1", query="from EmployeeEntity e where e.empId = :eid")
@NamedNativeQuery(name="query2", query="select * from employee", resultClass = EmployeeEntity.class)
public class EmployeeEntity {
@Id
@Column(name="emp_id")
private Integer empId;
@Column(name="emp_name")
private String empName;
@Column(name="emp_sal")
private Double empSalary;
@Column(name="dept_no")
private Integer deptNo;
// getters & setters
}
Note: We use wrapper classes instead of primitive types for entity attributes in Java because wrapper classes have a default value of null. This ensures that if no value is provided, null will be stored in the database.
createQuery()
method. // Executing named query
TypedQuery<EmployeeEntity> namedQuery = entityManager.createNamedQuery("query1", EmployeeEntity.class);
namedQuery.setParameter("eid", 7788);
EmployeeEntity emp = namedQuery.getSingleResult();
// Executing named native query
Query namedQuery = entityManager.createNamedQuery("query2");
List resultList = namedQuery.getResultList();
CriteriaQuery
object is used in JPA to construct SQL queries using java methods.CriteriaQuery
object can be used for only select operations.CriteriaQuery
object prepares tuned SQL queries while executing, so the queries returns the data from Database fast. So it improves the performance of an application.CriteriaBuiIder
is a helper class, to construct CriteriaQuery
object and also helps to construct the conditions. // Selecting employee names and salaries using Criteria API
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class);
Root<EmployeeEntity> root = criteriaQuery.from(EmployeeEntity.class);
criteriaQuery.select(criteriaBuilder.array(root.get("empName"), root.get("empSalary")));
TypedQuery<Object[]> query = entityManager.createQuery(criteriaQuery);
List<Object[]> resultList = query.getResultList();
// Selecting employees based on deptNo using Criteria API
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<EmployeeEntity> criteriaQuery = criteriaBuilder.createQuery(EmployeeEntity.class);
Root<EmployeeEntity> root = criteriaQuery.from(EmployeeEntity.class);
criteriaQuery.select(root).where(criteriaBuilder.equal(root.get("deptNo"), 20));
TypedQuery<EmployeeEntity> query = entityManager.createQuery(criteriaQuery);
List<EmployeeEntity> resultList = query.getResultList();
-- PLSQL procedure to calculate experience of employee
CREATE OR REPLACE PROCEDURE EMP_PROCEDURE(
EMP_NO IN NUMBER,
EMP_NAME OUT VARCHAR2,
YOE OUT NUMBER
)
IS
DOJ DATE;
BEGIN
SELECT ENAME, HIREDATE
INTO EMP_NAME, DOJ
FROM EMP
WHERE EMPNO = EMP_NO;
YOE := FLOOR((SYSDATE - DOJ) / 365);
END;
/
// Entity class with stored procedure
@Entity
@Table(name="emp")
@NamedStoredProcedureQuery(
name="procedure",
procedureName = "emp_procedure",
parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, type = Integer.class, name = "emp_no"),
@StoredProcedureParameter(mode = ParameterMode.OUT, type = String.class, name ="emp_name"),
@StoredProcedureParameter(mode = ParameterMode.OUT, type = Integer.class, name ="yoe")
}
)
public class EmpEntity {
// entity class code
}
// Executing stored procedure using JPA
StoredProcedureQuery procedureQuery = entityManager.createNamedStoredProcedureQuery("procedure");
procedureQuery.setParameter("emp_no", 7788);
tx.begin();
procedureQuery.execute();
String name = (String) procedureQuery.getOutputParameterValue("emp_name");
int yoe = (Integer) procedureQuery.getOutputParameterValue("yoe");
tx.commit();
System.out.println(name+", "+yoe);
There are four types of associations in JPA
One to Many Many to One Many to Many One to One
To provide one to many relationship, create a reference variable of type Collection (List/Set/Map) in the source entity class.
Use @OneToMany
annotation to represent that reference variable as a one to many field.
@OneToMany
annotation has attributes like
cascade fetch
Use @JoinColumn
annotation to represent the foreign key
@JoinColumn
annotation has attributes like
name ---> represents the foreign key column name referencedColumnName ---> represents the primary key referred by the foreign key
It represents the operations to be propagated onto the target objects.
It is an attribute of enum type called CascadeType
.
This CascadeType
enum has six constants.
ALL ---> all PERSIST ---> insert REMOVE ---> delete MERGE ---> update REFRESH ---> sync with DB DETACH ---> disconnect from EntityManager
It represents the associated collection is to be lazily loaded or early loaded.
This attribute is an enum type called FetchType
.
The only two constants are LAZY and EAGER
The default FetchType
in one to many is LAZY.
fetch attribute will not affect the loading of source entity.
To load source entity we have two methods
find() ---> for early loading getReference() ---> for lazy loading
Requirement: When a CRUD operation is performed on Category, we would like to propagate that operation onto the Product.
Solution: apply one to many relationship between category and products. Here, source of operations is category and target of the operations is product.
// Source entity
@Entity
@Table(name="tbl_categories")
public class CategoryEntity {
@Id
@Column(name="category_id")
private Integer categoryId;
@Column(name="category_name")
private String categoryName;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "category_id_fk")
private List<ProductEntity> productList; // one to many field
// getters & setters
}
// Target entity
@Entity
@Table(name="tbl_products")
public class ProductEntity {
@Id
@Column(name="product_id")
private Integer productId;
@Column(name="product_name")
private String productName;
private Double price;
// getters & setters
}
@ManyToOne
annotation.@ManyToOne
annotation is called as many to one field. // Source entity
@Entity
@Table(name="tbl_loans")
public class LoanEntity {
@Id
@Column(name="loan_id")
private Integer loanId;
@Column(name="loan_type")
private String loanType;
private Double amount;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="customer_id")
private CustomerEntity customer; // many to one field
// getters & setters
}
// Target entity
@Entity
@Table(name="tbl_customers")
public class CustomerEntity {
@Id
@Column(name="customer_id")
private Integer customerId;
@Column(name="customer_name")
private String customerName;
// getters & setters
}
// Source entity
@Entity
@Table(name="tbl_categories")
public class CategoryEntity {
@Id
@Column(name="category_id")
private Integer categoryId;
@Column(name="category_name")
private String categoryName;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "category")
private List<ProductEntity> productList;
// getters & setters
}
// Source entity
@Entity
@Table(name="tbl_products")
public class ProductEntity {
@Id
@Column(name="product_id")
private Integer productId;
@Column(name="product_name")
private String productName;
private Double price;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "category_id")
private CategoryEntity category;
// getters & setters
}
Many to Many = One to Many + Inverse One to Many one Book has many Authors = One to Many one Author has written many Books = Inverse One to Many Now the relationship is Many to Many
tbl_books
is the parent table and tbl_authors
is the child table.tbl_authors
is the parent table and tbl_books
is the child table. // Source entity
@Entity
@Table(name = "tbl_books")
public class BookEntity {
@Id
@Column(name = "book_id")
private Integer bookId;
@Column(name = "book_name")
private String bookName;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "tbl_books_authors",
joinColumns = @JoinColumn(name = "book_id"),
inverseJoinColumns = @JoinColumn(name = "author_id")
)
private List<AuthorEntity> listOfAuthors;
// getters & setters
}
// Target entity
@Entity
@Table(name = "tbl_authors")
public class AuthorEntity {
@Id
@Column(name = "author_id")
private Integer authorId;
@Column(name = "author_name")
private String authorName;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "listOfAuthors")
private List<BookEntity> listOfBooks;
// getters & setters
}
xxxToMany
FetchType ---> LAZY Variable ---> Collection Variable
xxxToOne
FetchType ---> EAGER Variable ---> Reference Variable
// Source entity
@Entity
@Table(name="tbl_persons")
public class PersonEntity {
@Id
@Column(name="person_id")
private Integer personId;
@Column(name="person_name")
private String personName;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "passport_id", unique = true, nullable = false)
private PassportEntity passport;
// getters & setters
}
// Target entity
@Entity
@Table(name="tbl_passports")
public class PassportEntity {
@Id
@Column(name="passport_id")
private Integer passportId;
@Column(name="expire_date")
private LocalDate expDate;
// getters & setters
}
Q) I want to fetch the name of employee and his department name with JPQL join query ?
select e.empName, d.deptName from Department d join d.listOfEmployees e;
Q) I want to fetch the category name and product name with JPQL query ?
select c.categoryName, p.productName from CategoryEntity c join c.listOfProducts p;
Q) I want to fetch category name and product name where product name should contain a letter 'm' in uppercase or in lowercase ?
select c.categoryName, p.productName from CategoryEntity c join c.listOfProducts p where p.productName like '%m%' or '%M%';
This annotation is used to specify the primary key generation strategy.
This annotation can be used for a primary key attribute
JPA has provided 4 primary key generation strategies
1) GenerationType.AUTO (default) 2) GenerationType.IDENTITY 3) GenerationType.SEQUENCE 4) GenerationType.TABLE
If we don't specify any generation strategy in @GeneratedValue
annotation, then GenerationType.AUTO
(default) generation strategy will be used.
GenerationType.AUTO
is the default generation strategy. In this strategy ORM tool will decide at run time which generation strategy will be used out of three (identity, sequence or table). ORM tool will choose the generation strategy according to the database.
Every database will have it's own set of supported generation strategies.
For Oracle database default generation strategy is GenerationType.SEQUENCE
For MySQL database also default generation strategy is GenerationType.SEQUENCE
Generation strategy GenerationType.IDENTITY
is not supported by Oracle.
GenerationType.SEQUENCE
and GenerationType.TABLE
is same just their implementation is different. In sequence, a sequence with name hibernate_sequence
will be created in database while in table, a table with name hibernate_sequences
will be created which will work as a sequence.
We can use our own oracle sequence also instead of the default sequence ('hibernate_sequence')
. To do so we have to use @SequenceGenerator
annotation.
allocationSize
attribute is used to control how many sequence values are fetched at a time from the database. Default value of allocationSize
is 50.
allocationSize
always should be less or equal to increament by
attribute of the sequence.
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgen")
@SequenceGenerator(name = "idgen", sequenceName = "my_seq", allocationSize = 3)
There are two types of cache
Level1 cache / First-level cache Level2 cache / Second-level cache
Whenever a Session / EntityManager object is created then automatically Level1 cache for that object is created.
The objects in Level1 cache of a Session / EntityManager is not sharable to other Session / EntityManager objects.
When a Session / EntityManager object is closed then Level1 cache is also destroyed.
If you want to share the objects across multiple Sessions / EntityManagers then we have to enable Level2 cache.
JPA / Hibernate has provided cache specification for Level2 cache and multiple vendors has provided implementation for that cache specification.
The most popular cache software is EHCache
(Easy Hibernate cache)
persistence.xml
<property name="hibernate.cache.region.factory_class" value="ehcache"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
hibernate.cache.region.factory_class
property is used to divide the cache into multiple regions according to the configuration provided in the ehcache.xml
file.hibernate.cache.use_query_cache
property is used to enable the query cache, query cache is used to store the query, query-parameter and query-result.persistence.xml
after entity class <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
ALL ---> all entities will be cached NONE ---> no entities will be cached ENABLE_SELECTIVE ---> only entities specified as cacheable will be cached
Note: @Cacheable
annotation is used to specify an entity as cacheable.
pom.xml
file <!-- Hibernate EntityManager dependency -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.6.8.Final</version>
</dependency>
<!-- EHCache dependency -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId
<version>5.6.8.Final</version>
</dependency>
Note: Version of hibernate-core
dependency and hibernate-entitymanager
dependency must be same.
ehcache.xml
file at src/main/resources
folder <!-- ehcache.xml -->
<ehcache>
<!-- default region -->
<defaultCache
maxEntriesLocalHeap = "100"
eternal = "false"
timeToIdleSeconds = "50"
timeToLiveSeconds = "120">
</defaultCache>
<!-- ProductEntity region -->
<cache name = "in.ashokit.entity.ProductEntity"
maxEntriesLocalHeap = "10"
eternal = "false"
timeToIdleSeconds = "20"
timeToLiveSeconds = "60">
</cache>
</ehcache>
name ---> to specify target entity class (it will be used as region name) maxEntriesLocalHeap ---> maximum no of entity objects that can be cached eternal ---> to specify whether the objects can automatically expire or not timeToIdleSeconds ---> after how many idle seconds object will remove from cache timeToLiveSeconds ---> maximum time a object can spent in cache regardless of usage
ehcache.xml
file in that case all the entity objects are cached into default region.true
query.setHint("org.hibernate.cacheable", true);