Hibernate

Hibernate standalone HelloWorld application

You can download it from here.
Another example using the old hibernate.cfg.xml without entity manager can be downloaded from here.

Under src\hibtest we have two files: User.java and Client.java as follows:

package hibtest;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.EntityTransaction;
 
public class Client {
    public Client() {
    }
 
    public static void main(String[] args) {
        EntityManagerFactory emf =  Persistence.createEntityManagerFactory("reza");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        User u = new User();
        u.setId(1);
        u.setName("sdf");
        em.persist(u);
        tx.commit();
        em.close();
        emf.close();
    }
}
 
package hibtest;
 
import javax.persistence.Entity;
import javax.persistence.Id;
 
@Entity
public class User {
    public User() {
    }
 
    @Id
    private long id;
 
    private String name;
 
    public long getId() {
        return id;
    }
 
    public void setId(long id) {
        this.id = id;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getName() {
        return name;
    }
}

Also we need persistence.xml under hibtest\META-INF that works with MySQL in my case:

<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" 
        version="1.0">
  <persistence-unit name="reza" transaction-type="RESOURCE_LOCAL">
    <properties>
      <property name="hibernate.dialect"
                value="org.hibernate.dialect.MySQL5Dialect"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.connection.driver_class"
                value="com.mysql.jdbc.Driver"/>
      <property name="hibernate.connection.username" value="root"/>
      <property name="hibernate.connection.password" value="passw"/>
      <property name="hibernate.connection.url"
                value="jdbc:mysql://localhost/think"/>
    </properties>
  </persistence-unit>
</persistence>

I also have the following jar files: Ant-1.6.5.jar,Ant-antlr-1.6.5.jar,Ant-junit-1.6.5.jar,Ant-launcher-1.6.5.jar,Ant-swing-1.6.5.jar,Antlr-2.7.6.jar,
Asm-attrs.jar,Asm.jar,C3p0-0.9.1.jar,Cglib-2.1.3.jar,Checkstyle-all.jar,Cleanimports.jar,Commons-collections-2.1.1.jar,
Commons-logging-1.0.4.jar,Concurrent-1.3.2.jar,Dom4j-1.6.1.jar,Ehcache-1.2.3.jar,Jaas.jar,Jacc-1_0-fr.jar,Javassist.jar,
Jaxen-1.1-beta-7.jar,Jboss-cache.jar,Jboss-common.jar,Jboss-jmx.jar,Jboss-system.jar,Jgroups-2.2.8.jar,Jta.jar,Junit-3.8.1.jar,
Log4j-1.2.11.jar,Oscache-2.1.jar,Proxool-0.8.3.jar,Swarmcache-1.0rc2.jar,Syndiag2.jar,Versioncheck.jar,Xerces-2.6.2.jar,
Xml-apis.jar,Hibernate3.jar,Ejb3-persistence.jar,Hibernate-annotations.jar,Hibernate-commons-annotations.jar,Hibernate-entitymanager.jar
Mysql-connector-java-5.1.6-bin.jar

I never tested to see which one is redundant but we definitely need entitymanager, Hibernate3.jar, Hibernate-annotations and Mysql-connector!

SessionFactory and Session

A SessionFactory can open up new Session's. A Session represents a single-threaded unit of work, the SessionFactory is a
thread-safe global object, instantiated once. A Session begins when it is first needed, when the first call to getCurrentSession() is made. It is then bound by Hibernate to the current thread. When the transaction ends, either through commit or rollback, Hibernate automatically unbinds the Session from the thread and closes it for you. If you call getCurrentSession() again, you get a new Session
and can start a new unit of work. This thread-bound programming model is the most popular way of using Hibernate. You should never use a new Hibernate Session for every database operation, this is wrong.

Designing Associations

The design questions we have to deal with are: directionality (bi or uni), multiplicity(1-1, m-n, 1-m, m-1), and collection behaviour. A m-n association can easily be bi or uni directional. The first thing to decide should be direction.

Bidirectional Navigation (m-m)

To allow bidirectional navigation of the association, we require one attribute in each side. In a m-m association, both sides must use an interface collection type.

m-m bidirectional example:

public class Category {
    private Set items;
    ...
}
 
public class Item {
    private Set cats;
    ...
}

As another example suppose we have Event/Person bidirectional m-m relation. So in Event.hbm.xml:

<set name="persons" table="PERSON_EVENT" inverse="true">
    <key column="EVENT_ID"/>
    <many-to-many column="PERSON_ID" class="events.Person"/>
</set>

All bi-directional associations need one side as inverse. In a one-to-many association it has to be the many-side, in many-to-many association you can pick either side.

Bidirectional Navigation (1-m)

public class Order {
    private Set items;
    ...
}
 
public class Item {
    private Order order;
    ...
}

Unidirectional Navigation (m-m)

Suppose we have a m-m relation between Person and Event and we want to have a method like person.getEvents() but we don't care about event.getPersons(). This is our choice. Order is not important to us so we use Set.

<class name="events.Person" table="PERSON">
    <id name="id" column="PERSON_ID">
        <generator class="native"/>
    </id>
    ....
          <!-- Association table is created on the fly -->
    <set name="events" table="PERSON_EVENT"> 
          <!-- Id of the other side is in the column attribute of key element -->
          <!-- FK in events-->
        <key column="PERSON_ID"/>
          <!-- Id of the many side is in the column attribute of many-to-many element -->
        <many-to-many column="EVENT_ID" class="events.Event"/>
    </set>
 
</class>

Self referenced 1-m

Suppose every Person can have many email addresses and email address is a field in Person table itself.

<!-- Association table created on the fly-->
<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
    <key column="PERSON_ID"/>
    <element type="string" column="EMAIL_ADDR"/>
</set>

Mapping Entity Bean Associations/Relationships with Annotations

Hibernate Classifies them as follows:

  1. one-to-one
  2. many-to-one
  3. Collections Mapping
    1. one-to-many Bi
    2. one-to-many Uni
    3. many-to-many (Uni/Bi)

Flush Entities

By default Hibernate flushes entities to synchronize the cached entities state with the database. Due to this, whenever a query is executed, hibernate performs dirty checking on collections to see if they have been modified. This dirty checking activity is expensive. By changing the session flushing mode to MANUAL, hibernate no longer performs those dirty checks which helps improve performance significantly. Specially if you projects just reads the db then your don't need this dirty checking: query.setHint("org.hibernate.flushMode", FlushMode.MANUAL);

Readonly Query

Be careful when using "org.hibernate.readOnly" hint for queries. Such queries can not be changed and even if you change them the changes are not reflected in the database.

Cache

When you enable second level cache it doesn't cache queries and for that you should use query cache.
Second level cache is not enabled by default. If enabled entities and collections will be cached.
You have to set annotations on entities and collections to use second level cache. They do not pick it by default even though it is enabled. This is similar to query cache that you have to set setCacheable(true) even though query cache is enabled.

Remove Duplicate Results

Outer join by default results in duplicates in SQL/Hibernate. In order to remove duplicates put the list in a LinkedHashSet or similar or use setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License