Hibernate Basics

Learn
15 min readDec 31, 2016

--

Hibernate is an ORM tool which does mapping between Objects and Relational data.Enterprise level applications typically need to interact with databases.

What are some of the pain points of manually mapping between the objects on the java layer and the rows on the DB side?
Class corresponds to a table and an instance of the Class corresponds to a row in the table.
a) Mapping between the column in the table and the field in the class is a tedious work,especially when the number of columns are high.
b) Data type mismatch:For instance,databases do not have a boolean data type and a boolean value is often represented as an int or a varchar.There needs to be specific code to handle this conversion of information represented as boolean in the java layer to int/varchar in the db layer and from int/varchar in the db layer to boolean in the java layer.
c) Relationships between entities:When there are related entities,the relationships between the entities needs to be captured in the Java layer and this is not always conducive to the representation of the same relationship in the DB layer.Hence,there needs to be a translation of the representation between the two layers every time there is a flow of data from one layer to the other.
d)Managing state changes:Every time,a class in the business layer or some other layer works on the object and changes the values in it,the same change needs to be propagated back to the DB layer.For this,specific SQL updates have to be designed cognizant of the kind of updates that has happened and these need to be issued to the database.

How do I setup a dev environment for hibernate?
Download the hibernate zip file.Along with the hibernate jar,the zip has a set of dependent jars in the lib and required folders that are part of the zip file.
Properties->Java Build Path->Libraries->Add user library.
Add jars to the user library.The jars needed are hibernate,antlr,hibernate-jpa,commons-collections etc.

What are the specific things that Hibernate needs to be able to connect with a particular type of database?
Hibernate internally uses jdbc to connect with the databases.So,the jdbc driver for that particular database type would be needed by hibernate and needs to be in the classpath.

What are some of the basic things that would be needed to save an instance into a database if we were not using hibernate?
a) A domain class to represent the particular entity type.
b) JDBC driver to be able to communicate with the particular type of DB
c) A service method to actually create a domain instance and save.
d) A database table corresponding to this entity.
e) A DAO layer that the service layer would call which forms the sqls and runs them against the DB.

With hibernate,what changes with regards to the typical development work required to interact with the database?
The DAO layer which refers to the forming to SQL statements by unwrapping the object using getter methods would go away.Hibernate layer is able to understand the objects and it internally forms the corresponding SQL statements.

What is the default name for the hibernate configuration file?
hibernate.cfg.xml. Sample hibernate.cfg.xml files come with the hibernate distribution. Take that sample and change to match the DB type and host and port details,driver details etc.
Also,change the dialect in hibernate.cfg.xml to match the database.
<property name=”dialect”> org.hibernate.dialect.MySQLDialect</property>

<property name=”show_sql”>true</property>:If this property is set to true,then hibernate logs the sql statements that it generates while executing the code.

What is the purpose of “hbm2ddl.auto” property in hibernate.cfg.xml?
If this property is set to true,then hibernate would automatically create the tables corresponding to the insert statements that it is about to issue.If the table already exists,then it drops and re-creates the tables.
<property name=”hbm2ddl.auto”>true</property>

Does the hibernate.cfg.xml need to know about the model classes?
Yes,it does need to know. This is specified using the mapping tag.
<mapping class=”com.test.mydomain.mymodel”/>

How is the model class created?
The model class would have the following characteristics.
a) It has the set of fields and their corresponding getter and setter methods.
Hibernate needs to know to treat this particular class as an entity.This can be configured using either annotations or xml files.Assuming that the annotations approach is taken,the following annotations would be needed.
b)@Entity annotation at the class level to indicate that this class represents an entity.
c)@Id annotation on the field that would act as the Id for the entity.For instance,if employeeId is the field that needs to act as the Id,then the field employeeId would be annotated as @Id

e..g
@Entity
public class Employee{
@Id
public int employeeId;
…}

What is a session factory?
As the name indicates,the session factory is a factory for creating sessions.There is only one session factory per application and this session factory can be used to create sessions.

What are the basic steps to save an object into the database using hibernate?
a) Create the session factory using the hibernate.cfg.xml configuration information as it has all the details about how to connect to the particular database.
b) Create a session from the session factory.
c) Use the session to save the object instance.
To create the session factory,
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Now,to create a session from the session factory,use the openSession() method from the session factory.
Session session = sessionFactory.openSession();
Now,start a transaction on the session.Save the instance using the session.And close the transaction.
session.beginTransaction();
session.save(myEmployee);
session.getTransaction().commit();

Why would a hibernate insert execution cause all existing rows to get deleted and new rows to get inserted?
This can happen if the hibernate configuration file hibernate.cfg.xml has the property hbm2ddl.auto as “create”. If it is needed that the existing data be retained,then the property “hbm2ddl.auto” needs to be set as “update”. When the value is set as “update”,the schema would not be re-created unless there is an update to the Entity model.

How are the table name and column names determined by hibernate?
When no additional specifications are given,the class name is used as the table name and the field names are used as the column names. In order to specify the name of the table and the column explicitly, Name property can be used on the @Entity annotation for the table name and for the column name specification, the @Column annotation can be used.
e.g.
@Entity (name=”EMPLOYEE”)
public class Employee
would cause the table to be created with the name “EMPLOYEE” instead of the name “Employee”.
Similarly,
@Column (name = “EMPLOYEE_ID”)
private long employeeId;
would cause the column name to be EMPLOYEE_ID instead of employeeId.
The column level annotations are typically specified against the field definition.However,such annotations can also be specified against the getter methods.

@Entity (name=”EMPLOYEE”) and @Table (name=”EMPLOYEE”). What is the difference?
While both these annotations would cause the table to have the name as “EMPLOYEE” when the table is being created,the Entity annotation causes the name of the entity to change as “EMPLOYEE” as well. However, when writing hqls, it is more intuitive to have names like Employee to refer to the Employee entity. So, to keep the entity name and the table name separate, the @Table annotation can be used.

If I need a field in my domain object for interim computation purpose as in I don’t want that field to be persisted to the database,how can I specify that?
a) If the field is a static field, it is not persisted.
b) If the field is a transient field,it is not persisted.
c) If the field has @Transient annotation,it is not persisted.
This can be validated by having show_sql as true and noting whether the columns shows up in the generated sql or not.

What is the purpose of @Temporal annotation?
Firstly,temporal means “of or relating to time”
This annotation is used over date fields to indicate whether we are interested in the DATE portion or the TIME portion of the TIMESTAMP portion of the date object to be saved in the database.
@Temporal (TemporalType.DATE)
public Date joiningDate
would cause only the DATE portion to get saved in the DB when the entity on whose field this annotation is applied is saved.On the other hand if @Temporal (TemporalType.TIME) is used,then only the TIME portion would get saved.

What is @Lob annotation?
Lob stands for Large object.Hibernate by default would assign a varchar of about 255 characters to correspond to a String field.However,if we expect that the content for the field can go very high,then we can specify the @Lob annotation on the field.
@Lob
private String description;
This would cause hibernate to associate CLOB data type to the description field.

How to do a simple select using hibernate?
Get the session factory,create a session from there and start a transaction like done earlier to create an instance of entity into the database.Use the session.get() method to retrieve the entity back from the database.Session.get() needs two arguments to be supplied,first is the Class corresponding to the entity being retrieved and second is the primary key corresponding to this particular entity.Also,the get() method signature has Object as the return type.Hence,it needs to be cast to the respective Entity class.Code snippet as below.
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getSession();
Employee employee = (Employee)session.get(Employee.class,1);

What is a surrogate key and what is a natural key?
In the context of an entity,when one of the fields that carry relevant data about the entity can also serve as the unique identifier for that entity,such a key is referred to as the natural key.For instance,if employee email needs to be unique across all employees and the employee email is a valid business field of the entity employee,then the employee email serves as the natural key to identify a particular employee.
Now,if there is no such field on the employee that needs to be unique across all employees.For instance,the email Id is not a mandatory field and some employees do not have it specified,then those employees clearly cannot be identified using the email Id field.In this scenario,a new field is added to the entity that would serve as the unique identifier for a particular instance of the entity.That field is clearly surrogate in nature and such fields are referred to as surrogate keys where the word meaning for “surrogate” is substitute.

In terms of setting the key field,Hibernate can help with computing surrogate keys but not natural keys.Why is that?
Natural keys are specific relevant data about the particular instance of the entity. e.g. the emailId for the employee. There is no way for Hibernate to figure that out. On the contrary,surrogate keys are usually a sequence of increasing numbers that need to be incremented every time a new entity is inserted.Clearly,this is something that can be automated and hence hibernate is able to support that.

How does hibernate support surrogate key generation?
Hibernate asks the developer to mark the field that he wants to be generated as a surrogate key to be marked with the @GeneratedValue annotation.
There are a few different strategies that can be used to compute the next value for the surrogate key.These strategies can be specified in the “strategy” attribute of the GeneratedValue annotation.
@GeneratedValue(strategy=”<Paricular strategy>”)
The possible strategy values are AUTO,SEQUENCE,TABLE and IDENTITY.

What is Identify column?
Identify column is a column whose values are generated by the database.

What do these strategies mean — Auto,Sequence,Table,Identity in the context of @GeneratedValue annotation for generating surrogate keys?
Sequence:Values are generated using a sequence.By default,the sequence used is named hibernate_sequence.
Table:Values are taken from a table.
Identity:Identity column in the database is used for generating new values.Not all databases support the identity column.
Auto:This is where hibernate automatically picks up one of the above strategies.This is the default strategy when strategy is not specified.

What are value objects?
Value objects are pieces of data with a few fields which do not have a meaning by itself unless associated with something else.For instance,an address with City,Street,State,PinCode does not mean anything by itself unless we know what this address is of. Such objects are called value objects.

What is the difference between value object and entity?
Entities have a meaning by themselves(for instance Employee entity) as opposed to value objects(for instance address) which do not have any meaning unless identified with an entity.

If a java class has a set of fields which are just Strings,Integers etc,we are able to do a ORM for it by having one column corresponding to one field in the Java class.If one of the fields in the class is not a simple data type and is instead another class with a few fields of it’s own,how is the ORM done?
There are various scenarios based on what kind of object the containing object.If the containing object is a value object,then the model to be followed for the database table would be to just blow up the value object as it’s fields and have those fields directly represented in the entity table whose part the value object is.For instance,if the Employee table had the fields employeeId,employeeName and Address where Address had street,city,state and pinCode,then the employee table would have the fields employeeId,employeeName,street,city,state,pinCode.

How is the flattening of the value object specified using hibernate?
This can be done using two annotations @Embeddable which is applied on the class name of the value object and @Embedded which can be applied on the field corresponding to the value object in the entity. The @Embedded annotation is not necessary when @Embeddable annotation is already used.

What is the complete list of things to be done to achieve the ORM where one of the components within the entity is a value object?
First,there needs to be a class for the value object which has a set of fields and their corresponding getters and setters.
Second,the class corresponding to the value object is annotated as @Embeddable.
Third,the entity class is defined with it’s set of fields and the corresponding getters and setters. This set would also include the value object which would be annotated as @Embedded.
Forth,the entity class would be annotated as @Entity
@Entity
public class Employee{
@Embedded
private Address address
}

@Embeddable
public class Address{
}

Fifth,the client class would create an entity instance for the employee and a value object instance for the address and set the value object on to the entity.And then persist the entity.
e.g.
Address address = new Address();
address.setStreet(“My Street”);
Employee employee = new Employee();
employee.setName(“Bill Crosby”);
employee.setAddress(address);
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getSession();
session.save(employee);

In case of value objects,it is possible that the same value object be part of multiple entities.For instance,address can be associated with the employee entity,it can also be associated with customer entity,supplier entity etc.Also,the same address entity can potentially be associated to the same entity twice.For instance,home address and office address for a customer.In such cases,how can the column names be specified to not have overlap when hibernate is configured to create the tables?
@AttributeOverride and @AttributeOverrides (plural ) are the two annotations that needs to be used to achieve this. These annotations are applied on the valueObject member variable of the entity. Since the valueObject can have more than one field within it where as there is only one field corresponding to the particular instance of valueObject in the entity class,the @AttributeOverrides annotation is provide to wrap multiple @AttributeOverride annotations, one for each field in the value object.
Each @AttributeOverride annotation would have a name attribute to refer to the particular field in the class for the ValueObject and an @Column annotation to specify the column name that that field would take in the table representation of the entity of whose part it is.
@AttributeOverride(name=”Street”,column=@Column(name=”HOME_STREET”))
Multiple such @AttributeOverride annotations would be wrapped in a single @AttributeOverrides annotation.

@AttributeOverrides({
@AttributeOverride(name=”Street”,column=@Column(name=”HOME_STREET”)),
@AttributeOverride(name=”PinCode”,column=@Column(name=”HOME_PINCODE”))
})

What is the consequence of having such annotations?
The DDL and the insert statements corresponding to the object creations would be generated against these column specifications.A column named HOME_STREET would get created in the EMPLOYEE table and would get populated with the value that was set on the Street field of the instance of Address that was set on the homeAddress field of the employee object instance.

In the above scenario,we have some portion of the entity being subobjects like homeAddress and officeAddress,what if we have a set of fields as the primary key which is quite possible.How would that be specified using hibernate?
Hibernate uses the @EmbeddedId annotation on the component object to mark it as the primary key for the entity.What this would achieve is that hibernate would ensure that the combination of the fields is unique and would fail insertion if it finds data in the DB that already has this set of fields.
@AttributeOverrides annotations are allowed on the id object just like it was allowed on an arbitrary object field within the entity.

If an entity has a set of value objects as it’s member variables as opposed to distinct specific value objects,how would that need to be defined?
The entity class would have a field of type Set<ValueObjectClass> and the corresponding getters and setters.The collection member variable would be annotated as @ElementCollection. Those are the steps that the developer needs to do.

What exactly does hibernate do to do ORM for a collection instance within an entity that is marked as @ElementCollection?
Hibernate creates a table corresponding to the collection.The name of the table would be <EntityName>_<CollectionName> where CollectionName is the name of the variable of the field in the entity that is of collection type,Set in this instance.
Now,for each element included in the collection,rows would be created in the newly created table.These rows would have column values corresponding to each field in the value object class that is part of the collection.
In addition to the standard fields in the value object class,the table corresponding to the collection would also have a columns named <CollectionName>_<EntityIdColumn> e.g. UserDetails_UserId which would be populated with the Id corresponding to the entity onto which this collection was set.

The name <EntityName>_<CollectionName> is not a good one for a table name.Is there a way to override this name using hibernate?
Yes,the annotation @JoinTable can be used to override this name.This annotation would apply to the member variable which has the collection.
@JoinTable(name=”USER_DETAILS”)

Also,the column name <CollectionName>_<EntityIdColumn> is not a friendly name either.How is this overridden?
Yes,this can be done using @JoinColumn annotation within the @JoinTable annotation.
@JoinTable(name=”USER_DETAILS”,joinColumns=@JoinColumn(name=”USER_ID”))

The collection objects which have a collection of ValueObjects within an entity has the set of columns corresponding to the fields in the ValueObject as well as the foreign key column to contain the Id of the entity whose part this collection is.However,the table generated for the collection does not have a primary key.Is it possible to have a primary key for the collection table and what needs to be done to achieve this?
Firstly,the collection instance in the class needs to be of a type that supports indexing.Meaning it cannot be a hashset and instead needs to be an implementation of collection that supports indexing list ArrayList.
Set<Address> addresses = new ArrayList<Address>();
Second,the collection instance has to be annotated with a hibernate annotation(not JPA annotation) called @CollectionId.
The collectionId annotation has three attributes.
1) The columns attribute that would point to a column annotation where the name of the column can be provided.
(columns= {@Column(name=”ADDRESS_ID”)})
2) The generator attribute which is used to specify how the column value is to be generated.This is a generated surrogate value.For the generator,the @Generator annotation is used to create a generator and that generator is referenced in the generator attribute of the @CollectionId annotation. @GenericGenerator(name=”hilo-gen” strategy=”hilo”). This name of the generator would be used in the generator attribute. @CollectionId(columns={@Column(name=”ADDRESS_ID”)}, generator=”hilo-gen”)
3) Type attribute which specifies the type of the surrogate column being created.e.g. type=”long”.
@Generator(name=”hilo-gen” strategy=”hilo”)
@CollectionId(columns={@Column(name=”ADDRESS_ID”)}, generator=”hilo-gen” type=”long”)

What would happen once all these annotations are specified?
The table corresponding to the collections instance of the entity would have an additional column called ADDRESS_ID which would function as the surrogate key for the table for the collection. The values for the ADDRESS_ID column would be generate using the hilo generator named “hilo-gen”.

Why is it important to stick to JPA annotations when the same annotations are available in Hibernate as well?
JPA is a standard that is implemented by multiple providers.Hibernate is one of those providers.Tomorrow,if a better implementation comes along,then we will be able to replace hibernate with that implementation without changing our code as our code depends only on JPA annotations.

Cascade Types
When an entity has collection instance variables which refer to related entities,then when a save or update or delete is done on the main entity,the same operation has to be done on all the related instance variables as otherwise hibernate would complain accordingly.For instance if the operation was a save,hibernate complains that the object references an unsaved transient instance.Hibernate is unable to assume that at the point of saving the main entity,the related entities need to be saved as well.Hibernates lets the application developer have the control on when he wants to save the particular type of entity.
However,hibernate lets you cascade the operation on to the collection entity as well using the cascade property on the OneToMany annotation.
@OneToMany(cascade=CascadeType.PERSIST).In addition to this,session.persist(myEntity) needs to be done in place of session.save(myEntity).This would cause hibernate to automatically save the collection instance when the main entity is saved.
Similary,CascadeType.REMOVE would take care of deleting the collection instances when the main entity is deleted.
If CascadeType.ALL is specified,then the cascading effect is applied on all the cascade types — be it persist,delete etc.

Transient,Persistent and Detached states
These are the three states that the entity instance pass through in it’s life cycle which is based on how it is associated with a session.An instance is in a transient state when it has not yet been associated with a session.Once a session.save(myEntity) is done,this entity instance is associated with a session and it is is the persistent state.After the session is closed,the instance is in detached state.
Hibernate keeps track of the instance in persistent state.After session.save(myEntity) is done which does an insert into the database,if properties of myEntity are changed,when session.commit() is done,the final state of that instance would get sent to the database as an update statement.This is because hibernate tracks the persistent instance even while the developer code does not specifically ask for it.
However,note that only one update is fired even when there are multiple changes done to the entity.That is hibernate efficiency in action.
This tracking happens only till the point the session is closed.At this point,the instance is in detached state.If you change any fields on the entity after the session is closed,then the update for that does not get fired.

--

--