Showing posts with label Hibernate. Show all posts
Showing posts with label Hibernate. Show all posts

Saturday, 22 September 2012

Hibernate Annotation One-to-One Mapping Example

While the Hibernate documentation section 2.2.5 is a good place to start for a concrete example for an example of a one-to-one annotation based relationship mapping, the example below describes a couple of scenarios and the annotations that worked in setting up the relationships.

Give below is an example of  a One-to-One  bi-directional relationship between a User object and a Registration object,

In the User object, set up the annotations as follows :

@Entity
@Table(name = "user")
public class User implements Serializable {
........
........
private UserRegistration userRegistration;
.........
  @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
  @JoinColumn(name = "USR_REG_SYS_ID")
   public UserRegistration getUserRegistration() {
        return this.userRegistration;
    }
.........
} // End of User class

The JoinColumn annotation refers to the to the USER_REGN_ID column in the User table that has a Foreign Key reference to the User_Registration table.

In the UserRegistration object, set up the annotation as follows:

@Entity
@Table(name = " userRegistration")
public class UserRegistration implements Serializable {

........
........
private User user;

........
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "userRegistration")
 public  User  getUser() {
        return this.user;
 }

The mappedBy annotation implies that the userRegistration attribute in the User object manages the relationship reference between the objects. In other words, the User table holds the (Foreign) key reference to the relationship.


Sunday, 26 August 2012

Setting up HIbernate Search on a Maven build

Hibernate Search is an interesting companion of the Hibernate core components. Since most applications with a public facing view invariably require, a search capability, Hibernate Search presents itself as an east to configure and implement, search tool that fits in well with the Hibernate ORM framework, Under the covers, Hibernate Search uses the Apache Lucene search engine and it is possible to write search queries directly targeting Lucene.Since Hibernate Search is annotation driven, it is preferable to have an annotation based implementation of Hibernate Core of your data model.

The following dependency definitions in your pom.xml will add the required Hibernate Search jars to your project.


org.hibernate
hibernate-search 
3.4.2.Final 

Add the following property settings to your Hibernate.cfg.xml file.



org.hibernate.search.store.FSDirectoryProvider


lucene

These setting will direct Hibernate Search to create the Index base and store it on the File System in a directory named Lucene.

This is all you need to add Hibernate Search to your current project setup. Now all you need is to annotate the fields in your domain model that need to be searchable,

The key annotations are as follows:

@Indexed
@Table(name = "User")
public class User implements Serializable
{

@Field(index=Index.TOKENIZED, store=Store.NO)
private String userName;
}

The @Indexed annotation tells Search to Index this particular table.
The @Field(index=Index.TOKENIZED, store=Store.NO) annotations on the attribute definition tells Search to tokenize the field using the default analyzer. The store annotation tells Hibernate not to store the data with the index and this is the default behaviour. Storing data within the index is required is using a Projection.

You can read more about setting up Hibernate Search at Getting Started

Sunday, 29 July 2012

Upgrade Hibernate from 3.1.3 to 3.6.10.Final using Maven

At the time of writing Hibernate is well into its 4.X releases with 5.X in sight so if you are looking to migrate from 3.x to 4.x read this or If you need a specific migration guide look here.

In my case I needed to migrate our application from 3.1.3 to 3.6.10.for which I have detailed the steps below.


  • Make sure that you have the necessary repositories to download the required Jars. You might need.


       mvn-public
       MVNRepository
       http://mvnrepository.com


       repository.jboss.org-public
       JBoss.org Maven repository
       https://repository.jboss.org/nexus/content/groups/public
  


  • Add the following dependencies into your pom.xml
   
  
   org.hibernate
   hibernate-core
   3.6.10.Final
  
  
  
   javassist
   javassist
   3.12.1.GA
  

Since Hibernate 3.4.X onwards, Hibernate switched to SL4J, you'll need:


   org.slf4j
   slf4j-log4j12
   1.5.6
  
  
   log4j
   log4j
   1.2.16
  

Now, configure your connection poolDownload the c3p0-0.9.1.2.jar from here and load it into your Tomcat/lib along with your MySQL driver jar.


Add the following configuration settings in your Hibernate (.properties or .cfg.) file.

5
20
300
50
3000

That's it !!
You WAR/lib should have the following jars present post-migration.
  • commons-collections-3.1.jar
  • hibernate-commons-annotations-3.2.0.Final.jar
  • hibernate-core-3.6.10.Final.jar
  • hibernate-jpa-2.0-api-1.0.1.Final.jar

  • javassist-3.12.1.GA.jar
  • jta-1.1.jar
  • slf4j-api-1.5.6.jar
  • slf4j-log4j12-1.5.6.jar


Saturday, 6 June 2009

Mapping Hibernate to Computed Columns

Most applications require a unique id to be assigned to the record. While a unique id can be implemented in several ways, SQL Server offers the option of using a Computed Column to generate and maintain these values.

Computed Columns enable the implementation of some complex logic via a User Defined Function (UDF) in generating the value of the corresponding row. For example: Consider an Employee table that has Employee_Location as a unique field. The Employee_Location changes every time, the employee's department is changed. This field can have values such as E001,Y001 and T009. While there are several ways of implementing this scenario, the Computed Column feature offered by SQL Server is an effective option. Values stored in a Computed Column can be persisted or kept virtual. Thus, it gives you a performance boost as you don't need to store data on the disk that is changing frequently but is required. On the other hand, if the data does need to be stored, the Computed Column can be persisted. This article explains the creation of indexes on Computed Columns.

If your Computed Column is being refrenced from within the application via an ORM such as Hibernate. The corresponding column mapping in the Hibernate POJO has to be annotated using the following set of annotations on the getter of the associated column attribute.
@Column(name = "Employee_Location", length = 25, insertable = false, updatable = false)
@Generated(GenerationTime.INSERT)

What the annotations do is tell Hibernate, that the Computed Column is not to be updated by the application AND that the value in the Computed Column is created when the record is inserted. That's it. Hibernate will not attempt to insert any value into the Employee_Location column but will retrieve the value stored in the column and associate it with any related mapping.

Sunday, 10 May 2009

Hibernate Annotations : A powerful addition to the Hibernate family.

I recently used Hibernate Annotations in a project and was impressed by the power and relative flexibility offered by annotations and the difference it made with regards to cleaning up the project build. While the major advantage of using annotations was that I could completely get rid of the hibernate mapping xmls, it also made life easier when it came to specifying relationships between my entity beans.

To get started with Hibernate Annotations, follow the Hibernate learning trail and download the required jars and set up your project. If you are using Maven, you can specify the dependencies in a Maven POM as outlined in this example. Once you have a project set up, take a look at this reference guide. Mapping entity bean associations and relationships is simple and this is a good example that demonstrates the annotation entries for mapping different relationships. One major advantage of using Annotations is that several mappings and associations can be configured by default. For example, if I defined a primary key mapping of an entity bean to a database as follows:
@Id
public Long getId() {
return id;
}
and left out @GeneratedValue(strategy=GenerationType.AUTO)

Hibernate would assume that the application will provide the Primary Key or in other words, the strategy for the primary key, if I were to specify the same in an hbm file would be equivalent to "assigned". Similarly, If the Annotation @Table(name="EMPLOYEE") on a bean can be used to map the bean to the table EMPLOYEE but if not given, the name of the bean would be used as a key by Hibernate for mapping the table to a bean.

Thus, Hibernate Annotations reduces the setup time in adding Hibernate to a project while simplifying the maintenance of the associated code.

Monday, 20 October 2008

Software caused connection abort: recv failed with MySQL and Hibernate

If you get "Software caused connection abort: recv failed" after attempting to login to your JBOSS server after a long period of idle time then you need to take a cup of coffee and sit down as this is going to take a while to fix.

In a web application that we developed,  we were using a JBOSS server version 4.04, connecting to MYSQL 5.0.24 with Hibernate 3.1 and we started getting these messages after the server had been sitting idle for some time and a login was attempted. The initial diagnosis was that the MySQL /JDBC connection was getting stale and it could be resolved by updating your MySQL driver to the latest version and adding a few properties to your data-source connection file. We updated the driver to mysql-connector-java-5.0.8 and as explained in this excellent post we added the following lines :
       
 (exception-sorter-class-name)
com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
(/exception-sorter-class-name)
(valid-connection-checker-class-name)
com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker
(/valid-connection-checker-class-name)        
The basic idea was that the JNDI would ping the DB periodically and keep the data source alive. Well, it didn't work for us but atleast we had the latest driver.

The next approach was to write a custom class that would operate on the database every hour or so and keep the connection fresh. (According to the docs, MySQL marked the connection stale after 8 hours but I was not in a trusting mood). I wrote a Java Timer class that was called by a servlet every 30 minutes. The objective of the class was to check the table which housed our support requests and if found a new request, it would shoot me an email. The Timer class and the Servlet hookup worked fine and I stated getting emails if there was a support request waiting to be serviced but the original problem still remained. The server would still spit out a long stream of exceptions, starting with Software caused connection abort: recv failed if a login was attempted after a few hours of idle time.This was getting annoying!

I then approached the problem in a different way and went over my Hibernate connection pooling setup. We were using C3PO but maybe something was missing? I reset the Hibernate connection pooling parameters to the following :
(property name="connection.provider_class")org.hibernate.connection.C3P0ConnectionProvider(/property)
(property name="c3p0.acquire_increment")1(/property)
(property name="c3p0.idle_test_period")100(/property) (!-- seconds --)
(property name="c3p0.max_size")100(/property)
(property name="c3p0.max_statements")0(/property)
(property name="c3p0.min_size")10(/property)
(property name="c3p0.timeout")100(/property) (!-- seconds --)

and Voila, the exceptions disappeared. We finally had a clean console when attempting login ever after several hours. So while, the Hibernate connection pooling params appear to be the main culprit, I feel that its equally important to update your MySQL driver and make sure that there are no loose ends in the JNDI data-source params.

Friday, 29 February 2008

Hibernate is Lazy : The LazyInitializationException scenario

While Lazy Instantiation is an important feature and does improve performance in J2EE applications, it can be a bit of a headache if not correctly used or should I say implemented.

Consider a J2EE scenario where you might have a one-to-many parent-child relationship defined between two classes.In the scenario, data retrieval is handled by the DAO layer. In it a DAO retrieves a dataset and passes it to a view. The view is controller by a servlet and rendered by a JSP. The JSP attempts to print out the parent's name and voila, you have a LazyInitializationException.

As section 19.1.4 of the Hibernate documentation states " A LazyInitializationException will be thrown by Hibernate if an uninitialized collection or proxy is accessed outside of the scope of the Session, ie. when the entity owning the collection or having the reference to the proxy is in the detached state."

Two obvious (and suggested) counter strategies would be
1. Keep the session open until all objects that are required have been initialised.

In my opinion, this is not a good approach as you are liable to forget closing a session and will end up nesting transactions. Something which the J2EE container does not like.
(Yes, Yes..you can use a servlet filter to ensure that you do close the session but you can have performance degradation with requests being parsed by the filter. In addition to this, you will also need to have a robust exception handling mechanism in place to ensure that sessions do get closed when exceptions occur.

2. Prepare all uninitialized collections in the business layer before they get passed to the view.
I feel that this is a better and a much more organised strategy as you can initialise the objects and their associated objects in the same DAO call (and the same session).
Of course you need to be sure that you are going to really use these objects otherwise you will end up with a lot of unused objects on the heap and a sluggish application to boot.

While there are several strategies to counter the LazyInitializationException scenario, To fully understand the solution, one should have a good grasp of the Fetching strategies employed by Hibernate as they are the key to the problem and to the solution.

Thursday, 11 October 2007

Configuring Middlgen to generate Hibernate files from MySQL

Following on from my earlier post , I'll now show you how to configure Middlegen and talk to your MySQL database. You will need to have ANT installed in order to run the ANT tasks that I customized to build the hbms and the Java objects.

I performed the Middlegen connection tasks using ANT version 1.7, MySQL version 5.0.24-community-nt and MySQL client version 5.1.11 and Middlegen 2.1

In your build.xml, set the following Middlegen property
<property name="Middlegen.home" value="${lib}/Middlegen"/>

The lib directory has 2 main jars, Middlegen-2.1.jar and Middlegen-hibernate-plugin-2.1.jar.

Both these jars are required to
(1) Run Middlegen and connect to MySQL
(2) Create Hbm mappings from the database and convert the hbm mappings into Java objects.

Firstly create a directory where you are going to store your generated files using the Middlegen-init ANT task.

<target name="Middlegen-init"
description="Initializes everything, creates directories, etc.">
<mkdir dir="${gen.java}" />
</target>


The next task is Middlegen which talks to the database but inorder to do so, it needs to know where the database is located, what driver file to use and what connection properties to use, so make the task know all this by defining the following properties in the build.xml

<property name="database.initialise.script" value="${main.resources}/database/ddl/FULL_DROP_INITIALISE.sql"/>
<property name="database.driver.file" value="${lib}/mysql-connector-java-3.0.14-production-bin.jar"/>
<property name="database.driver.classpath" value="${database.driver.file}"/>
<property name="database.driver" value="org.gjt.mm.mysql.Driver"/>
<property name="database.url" value="jdbc:mysql://localhost/testdatabase"/>
<property name="database.userid" value="root"/>
<property name="database.password" value="root"/>
<property name="database.schema" value="testdatabase"/>
<property name="database.catalog" value=""/>

You'll notice that the properties talk about a 'database.driver' which should be on the 'database.driver.classpath'.
This driver can be found within the mysql-connector-java-3.0.14-production-bin.jar so it should be downloaded and made available to the application.

Now, write the following ANT tasks in your build.xml

<!-- Middlegen related Tasks --->
<!-- =================================================================== -->
<!-- Run Middlegen -->
<!-- =================================================================== -->
<target
name="Middlegen"
description="Run Middlegen"
unless="Middlegen.skip"
depends="Middlegen-init"
>

<taskdef
name="Middlegen"
classname="Middlegen.MiddlegenTask"
classpathref="lib.class.path"
/>

<Middlegen
appname="${name}"
prefsdir="${Middlegen.prefs}"
gui="${gui}"
databaseurl="${database.url}"
initialContextFactory="${java.naming.factory.initial}"
providerURL="${java.naming.provider.url}"
datasourceJNDIName="${datasource.jndi.name}"
driver="${database.driver}"
username="${database.userid}"
password="${database.password}"
schema="${database.schema}"
catalog="${database.catalog}"
includeViews="false"
>

<!-- Sets up the hibernate plug-in for Middlegen -->

<hibernate
destination="${gen.java}"
package="${name}.persistence"
genXDocletTags="true"
javaTypeMapper="Middlegen.plugins.hibernate.HibernateJavaTypeMapper"
/>
</Middlegen>

</target>

<!-- =================================================================== -->
<!-- Run hbm2java -->
<!-- =================================================================== -->
<target name="hbm2java" description="Generate .hbm and then .java from .hbm files.">
<taskdef
name="hbm2java"
classname="net.sf.hibernate.tool.hbm2java.Hbm2JavaTask"
classpathref="lib.class.path"
/>
<hbm2java output="${gen.java}">
<fileset dir="${gen.java}">
<include name="**/*.hbm.xml"/>
</fileset>
</hbm2java>
</target>
<!-- End of Middlegen related Tasks --->

To create the HBM mappings for ALL tables in your 'testdatabase' schema:
Run the 'Middlegen' task which will
(1) create a directory to store the generated files
(2) connect to your MySQL database based on the params supplied and generate the hbm mapping files.

You can customize the hbm files according to your requirements, now run the hbm2java mapper task on these files by invoking the target 'hbm2java'. The java files will be generated and stored in the same directory alongside their respective hbms.

Well, that's all there is to it.

Middlegen is a very useful tool as it takes away the pain of manually creating these files and helps you setup your Hibernate environment within a couple of hours.

For more info on the subject refer to the Middlegen homepage.

Friday, 14 September 2007

MiddleGen and Hibernate: Making life easy in the middle

If you have been working in the Hibernate or in the EJB space, chances are high that you have had to write intermediate files such as hbms, in the case of Hibernate, that bridge the gap between the database tables and the Java objects (read POJOs) that exist within the application and are responsible for transporting data around.

While writing the hbm files manually, is a good idea if you really want to learn about how they are structured and the different types of relationships that they can be define within the data model, it becomes a tedious task if your data architect is not sure of what he or she is doing and/or keeps changing the DDL regularly.

In an AGILE project scenario, where requirements are welcomed at late stages of the build process, having a tool that can generate the hbm files and the related Java files (which are essentially POJOs) can be a boon. This is where MiddleGen comes in.

While MiddleGen is basically (an open source) database driven tool for generating code from the database to the presentation layer (Struts), I found its confluence with Hibernate to be really useful. It took me basically half-an-hour to set up MiddleGen and configure the Ant Tasks that came with the sample set of examples (in the MiddleGen download), to connect to my MYSQL database and generate a set of hbm files and their corresponding Java counterparts. In my next post, I'll explain the sequence of steps that I followed in setting up MiddleGen to talk to my database and generating the hbms and the Java files.