Cascade in Hibernate
1. inverse: This is used to decide which side is the
relationship owner to manage the relationship (insert or update of the foreign
key column).
2. cascade: In cascade, after one operation (save,
update and delete) is done, it decide whether it need to call other operations
(save, update and delete) on another entities which has relationship with each
other.
Conclusion: In short, the “inverse” is decide which
side will update the foreign key, while “cascade” is decide what’s the follow
by operation should execute. Both are look quite similar in relationship, but
it’s totally two different things. Hibernate developers are worth to spend time
to research on it, because misunderstand the concept or misuse it will bring
serious performance or data integrity issue in your application.
Cascading
in Hibernate has
many options like save-update, persist,merge, delete etc. Cascade='all'
is a way of saying apply all cascading options.
---------------------------------------------------------------------------------------------------------------------------
Hibernate Transaction Management Example
A transaction simply represents a unit of work.
In such case, if one step fails, the whole transaction fails (which is termed
as atomicity). A transaction can be described by ACID properties (Atomicity,
Consistency, Isolation and Durability).
1.2.1 Transaction Interface in Hibernate
In hibernate framework, we have Transaction interface
that defines the unit of work. It maintains abstraction from the transaction
implementation (JTA,JDBC).
A transaction is associated with Session and instantiated by
calling session.beginTransaction().
The methods of Transaction interface are as follows:
1. void begin() starts
a new transaction.
2. void commit() ends
the unit of work unless we are in FlushMode.NEVER.
3. void rollback() forces this transaction to rollback.
4. void setTimeout(int seconds) it sets a transaction timeout for any transaction started by
a subsequent call to begin on this instance.
5. boolean isAlive() checks if the transaction is still alive.
6. void registerSynchronization(Synchronization s) registers a user synchronization callback
for this transaction.
7. boolean wasCommited() checks if the transaction is commited successfully.
8. boolean wasRolledBack() checks if the transaction is rolledback successfully.
Example of Transaction Management in Hibernate
In hibernate, it is better to rollback the transaction if any
exception occurs, so that resources can be free. Let's see the example of
transaction management in hibernate.
1. Session session = null;
2. Transaction tx = null;
3.
4. try {
5. session = sessionFactory.openSession();
6. tx = session.beginTransaction();
7. //some action
8.
9. tx.commit();
10.
11. }catch (Exception ex) {
12. ex.printStackTrace();
13. tx.rollback();
14. }
15. finally {session.close();}
------------------------------------------------------------------------------------------------------------------------
5) What is SessionFactory?
SessionFactory provides the
instance of Session. It is a factory of Session. It holds the data of second
level cache that is not enabled by default.
6) Is
SessionFactory a thread-safe object?
Yes, SessionFactory is a
thread-safe object, many threads can access it simultaneously.
Batch Processing
Consider a situation when you need to upload a
large number of records into your database using Hibernate. Following is the
code snippet to achieve this using Hibernate:
Sessionsession=SessionFactory.openSession();
Transactiontx=session.beginTransaction();
for(inti=0;i<100000;i++){
Employeeemployee=newEmployee(.....);
session.save(employee);
}
tx.commit();
session.close();
Because by default, Hibernate will cache all the
persisted objects in the session-level cache and ultimately your application
would fall over with anOutOfMemoryException somewhere around the
50,000th row. You can resolve this problem if you are using batch
processing with Hibernate.
To use the batch processing feature, first
set hibernate.jdbc.batch_size as batch size to a number either
at 20 or 50 depending on object size. This will tell the hibernate container
that every X rows to be inserted as batch. To implement this in your code we
would need to do little modification as follows:
Session session=SessionFactory.openSession();
Transaction tx=session.beginTransaction();
for(inti=0;i<100000;i++){
Employee employee=new Employee(.....);
session.save(employee);
if(i%50==0){// Same as the JDBC
batch size
//flush a batch of
inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Above code will work fine for the INSERT
operation, but if you are willing to make UPDATE operation then you can achieve
using the following code:
Sessionsession=sessionFactory.openSession();
Transactiontx=session.beginTransaction();
ScrollableResultsemployeeCursor=session.createQuery("FROM EMPLOYEE")
.scroll();
int count =0;
while(employeeCursor.next()){
Employeeemployee=(Employee)employeeCursor.get(0);
employee.updateEmployee();
seession.update(employee);
if(++count %50==0){
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Batch Processing
Example:
Let us modify configuration file as to add hibernate.jdbc.batch_sizeproperty:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE
hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<propertyname="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<propertyname="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- Assume
students is the database name -->
<propertyname="hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<propertyname="hibernate.connection.username">
root
</property>
<propertyname="hibernate.connection.password">
root123
</property>
<propertyname="hibernate.jdbc.batch_size">
50
</property>
<!-- List of XML
mapping files -->
<mappingresource="Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Consider the following POJO Employee class:
publicclassEmployee{
privateint id;
privateStringfirstName;
privateStringlastName;
privateint salary;
publicEmployee(){}
publicEmployee(Stringfname,Stringlname,int salary){
this.firstName=fname;
this.lastName=lname;
this.salary= salary;
}
publicintgetId(){
return id;
}
publicvoidsetId(int id ){
this.id = id;
}
publicStringgetFirstName(){
returnfirstName;
}
publicvoidsetFirstName(Stringfirst_name){
this.firstName=first_name;
}
publicStringgetLastName(){
returnlastName;
}
publicvoidsetLastName(Stringlast_name){
this.lastName=last_name;
}
publicintgetSalary(){
return salary;
}
publicvoidsetSalary(int salary ){
this.salary= salary;
}
}
Let us create the following EMPLOYEE table to
store Employee objects:
create table
EMPLOYEE (
id
INT NOT NULL auto_increment,
first_name VARCHAR(20)default NULL,
last_name VARCHAR(20)default NULL,
salary INT default NULL,
PRIMARY
KEY (id)
);
Following will be mapping file to map Employee
objects with EMPLOYEE table.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE
hibernate-mapping PUBLIC
"-//Hibernate/Hibernate
Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="Employee"table="EMPLOYEE">
<metaattribute="class-description">
This
class contains the employee detail.
</meta>
<idname="id"type="int"column="id">
<generatorclass="native"/>
</id>
<propertyname="firstName"column="first_name"type="string"/>
<propertyname="lastName"column="last_name"type="string"/>
<propertyname="salary"column="salary"type="int"/>
</class>
</hibernate-mapping>
Finally, we will create our application class
with the main() method to run the application where we will use flush() and clear() methods
available with Session object so that Hibernate keep writing these records into
the database instead of caching them in the memory.
importjava.util.*;
importorg.hibernate.HibernateException;
importorg.hibernate.Session;
importorg.hibernate.Transaction;
importorg.hibernate.SessionFactory;
importorg.hibernate.cfg.Configuration;
publicclassManageEmployee{
privatestaticSessionFactory factory;
publicstaticvoid main(String[]args){
try{
factory =newConfiguration().configure().buildSessionFactory();
}catch(Throwable ex){
System.err.println("Failed to create
sessionFactory object."+ ex);
thrownewExceptionInInitializerError(ex);
}
ManageEmployee ME =newManageEmployee();
/* Add employee
records in batches */
ME.addEmployees();
}
/* Method to create
employee records in batches */
publicvoidaddEmployees(){
Sessionsession=factory.openSession();
Transactiontx=null;
IntegeremployeeID=null;
try{
tx=session.beginTransaction();
for(inti=0;i<100000;i++){
Stringfname="First Name
"+i;
Stringlname="Last Name "+i;
Integer salary =i;
Employeeemployee=newEmployee(fname,lname, salary);
session.save(employee);
if(i%50==0){
session.flush();
session.clear();
}
}
tx.commit();
}catch(HibernateException e){
if(tx!=null)tx.rollback();
e.printStackTrace();
}finally{
session.close();
}
return;
}
}
Compilation and
Execution:
Here are the steps to compile and run the above
mentioned application. Make sure you have set PATH and CLASSPATH appropriately
before proceeding for the compilation and execution.
· Create hibernate.cfg.xml configuration file as
explained above.
· Create Employee.hbm.xml mapping file as shown
above.
· Create Employee.java source file as shown above
and compile it.
· Create ManageEmployee.java source file as shown
above and compile it.
· Execute ManageEmployee binary to run the program
which will create 100000 records in EMPLOYEE table.
Annotation
|
Package
Detail/Import statement
|
import javax.persistence.Entity;
|
|
import javax.persistence.Table;
|
|
import javax.persistence.Column;
|
|
import javax.persistence.Id;
|
|
import
javax.persistence.GeneratedValue;
|
|
import javax.persistence.Version;
|
|
import javax.persistence.OrderBy;
|
|
import javax.persistence.Transient;
|
|
import javax.persistence.Lob;
|
|
import javax.persistence.OneToOne;
|
|
import
javax.persistence.ManyToOne;
|
|
import
javax.persistence.OneToMany;
|
|
import
javax.persistence.ManyToMany;
|
|
import
javax.persistence.PrimaryKeyJoinColumn;
|
|
import
javax.persistence.JoinColumn;
|
|
import
javax.persistence.JoinTable;
|
|
import javax.persistence.MapsId;
|
|
import
javax.persistence.Inheritance;
|
|
import
javax.persistence.DiscriminatorColumn;
|
|
import
javax.persistence.DiscriminatorValue;
|
Annotate
all your entity beans with @Entity.
@Entity
public class Company implements Serializable
{
...
}
|
Specify
the database table this Entity maps to using the name attribute of @Table
annotation. In the example below, the data will be stored in 'company' table in
the database.
@Entity
@Table(name = "company")
public class Company implements Serializable
{
...
}
@Column
Specify
the column mapping using @Column annotation.
|
No comments:
Post a Comment