tags:

views:

731

answers:

3

I'm trying to get started with hibernate, but I can't find any tutorials I understand. I'm trying to create a simple app to get started, but I've really no idea where to get started.

I'm pretty advanced with java, although only used eclipse really. So.. where do I configure what DB it uses, and alike?

[edit]
I'm familiar with the concepts of ORM, and what Hibernate is. What I don't know or understand, is where to begin my application. I intend to use annotations, but, after annotating my POJOs, what do I do? Where do I specify database server, user, etc? What else do I need to do?

+2  A: 

I'll assume that you're having trouble with the Hibernate reference docs?

Maybe this Hibernate tutorial would be better.

duffymo
The tutorial is far too... "abstract", and I'm already familiar with the concepts. I need something more like a concrete example, of a small hibernate-powered application, what I should do to start my application, etc.
Hugo
+4  A: 

My experiences and background were similar, and I also had a hard time finding a tutorial that addressed my development preferences (which seem similar to yours):

  • Prefer JPA annotations over XML, only adding Hibernate annotations when the JPA counterparts do not suffice
  • Use Hibernate's SessionFactory / Session to access persistent data rather than JPA EntityManager
  • Use immutable classes wherever possible

I read most of Java Persistence with Hibernate, and it took a long time to separate this use case from all the other options that it presents (XML configuration in Hibernate/JPA format, xdoclet "annotations", etc...).

It would have made so much more sense to me if the available documentation would take a stand and actively push me in this direction instead of giving me a bunch of options and wondering where to go. Lacking that, I learned the following lessons by converting the standard Hibernate Tutorial over to annotations.

Configuration

  • Keep hibernate.cfg.xml to the bare minimum (see below).
  • Define database column / table names explicitly with the JPA annotations so you get exactly the schema you want. You can double-check it by using SchemaExport.create(true, false). Note that you may not get the exact schema you expect if Hibernate tries to update the schema on an existing database (for example, you can't add a NOT NULL constraint to a column that already contains null values).
  • Create the SessionFactory's Configuration using AnnotationConfiguration.addAnnotatedClass().addAnnotatedClass()...

Here's my copy of hibernate.cfg.xml. It only sets properties, and explicitly avoids any mapping configuration.

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;
<hibernate-configuration>
    <session-factory>
     <!-- Information about the database to be used -->
     <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
     <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
     <property name="connection.username">sa</property>
     <property name="connection.password"></property>
     <property name="connection.pool_size">1</property>
     <property name="dialect">org.hibernate.dialect.HSQLDialect</property>

     <!-- Misc. Hibernate configuration -->
     <property name="hbm2ddl.auto">update</property>
     <property name="current_session_context_class">thread</property>
     <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
     <property name="show_sql">false</property>
    </session-factory>
</hibernate-configuration>

Scope

  • Begin/commit/rollback transactions outside each Manager / DAO class. I have no idea why the tutorial's EventManager starts/commits its own transactions, as the book identifies this as being an anti-pattern. For the servlet in the tutorial, this can be done by making a Filter that starts the transaction, invokes the rest of the FilterChain, and then commits/rolls back the transaction.
  • Similarly, make the SessionFactory outside and pass it in to each Manager / DAO class, which then calls SessionFactory.getCurrentSession() any time it needs to access data. When it comes time to unit test your DAO classes, make your own SessionFactory that connects to an in-memory database (such as "jdbc:hsqldb:mem:test") and pass it into the DAO being tested.

For example, some snippets from my version of EventManager:

public final class EventManager {

private final SessionFactory sessionFactory;

/** Default constructor for use with JSPs */
public EventManager() {

 this.sessionFactory = HibernateUtil.getSessionFactory();
}

/** @param Nonnull access to sessions with the data store */
public EventManager(SessionFactory sessionFactory) {

 this.sessionFactory = sessionFactory;
}

    /** @return Nonnull events; empty if none exist */
public List<Event> getEvents() {

 final Session db = this.sessionFactory.getCurrentSession();
 return db.createCriteria(Event.class).list();
}

/**
 * Creates and stores an Event for which no people are yet registered.
 * @param title Nonnull; see {@link Event}
 * @param date Nonnull; see {@link Event}
 * @return Nonnull event that was created
 */
public Event createEvent(String title, Date date) {

 final Event event = new Event(title, date, new HashSet<Person> ());
 this.sessionFactory.getCurrentSession().save(event);
 return event;
}

/**
 * Registers the specified person for the specified event.
 * @param personId ID of an existing person
 * @param eventId ID of an existing event
 */
public void register(long personId, long eventId) {

 final Session db = this.sessionFactory.getCurrentSession();
 final Person person = (Person) db.load(Person.class, personId);
 final Event event = (Event) db.load(Event.class, eventId);
 person.addEvent(event);
 event.register(person);
}

...other query / update methods...
}

Data classes

  • Fields are private
  • Getter methods return defensive copies since Hibernate can access the fields directly
  • Don't add setter methods unless you really have to.
  • When it is necessary to update some field in the class, do it in a way that preserves encapsulation. It's much safer to call something like event.addPerson(person) instead of event.getPeople().add(person)

For example, I find this implementation of Event much simpler to understand as long as you remember that Hibernate accesses fields directly when it needs to.

@Entity(name="EVENT")
public final class Event {

 private @Id @GeneratedValue @Column(name="EVENT_ID") Long id; //Nullable

 /* Business key properties (assumed to always be present) */
 private @Column(name="TITLE", nullable=false) String title;

 @Column(name="DATE", nullable=false) 
 @Temporal(TemporalType.TIMESTAMP)
 private Date date;

 /* Relationships to other objects */
 @ManyToMany
 @JoinTable(
  name = "EVENT_PERSON",
  joinColumns = {@JoinColumn(name="EVENT_ID_FK", nullable=false)},
  inverseJoinColumns = {@JoinColumn(name="PERSON_ID_FK", nullable=false)})
 private Set<Person> registrants; //Nonnull

 public Event() { /* Required for framework use */ }

 /**
  * @param title Non-empty name of the event
  * @param date Nonnull date at which the event takes place
  * @param participants Nonnull people participating in this event
  */
 public Event(String title, Date date, Set<Person> participants) {

  this.title = title;
  this.date = new Date(date.getTime());
  this.registrants = new HashSet<Person> (participants);
 }

 /* Query methods */

 /** @return Nullable ID used for persistence */
 public Long getId() {

  return this.id;
 }

 public String getTitle() {

  return this.title;
 }

 public Date getDate() {

  return new Date(this.date.getTime());
 }

 /** @return Nonnull people registered for this event, if any. */
 public Set<Person> getRegistrants() {

  return new HashSet<Person> (this.registrants);
 }

 /* Update methods */

 public void register(Person person) {

  this.registrants.add(person);
 }
}

Hope that helps!

Kyle Krull
+1 - well done, Kyle Krull. An excellent answer, very helpful.
duffymo
Some things I can't seem to find on the net, is, which JAR contains "HibernateUtil" for example. I've added the required JARs to my classpath, but there are some things that are just CAN'T seem to come across. These are the sort of things that have kept me stuck, I practically haven't gotten to code anything yet.
Hugo
It would be nice if the Hibernate tutorial made this more clear, but they want you to implement HibernateUtil yourself for some reason. It usually just has a static method as follows:public static SessionFactory getSessionFactory() { return new AnnotationConfiguration() //Add data model / POJO classes here .addAnnotatedClass(Event.class) .addAnnotatedClass(Person.class) .configure().buildSessionFactory();}I've also had trouble getting compatible versions of everything (Hibernate Core, Annotations, SLF4J). Hibernate's compatibility matrix (https://www.hibernate.org/6.html) helps
Kyle Krull
+1 for the detailed answer. One quick question if I may- You use the @JoinTable annotation and I wanted to know if when specifying it on the People entity would it be the same (apart for the joinColumns and inverseJoinColumns properties switching between them)? Thanks
Ittai
@Ittai: I haven't found anything suggesting that there would be any difference, and the output schemas look the same as far as I can tell (see org.hibernate.tool.hbm2ddl.SchemaExport).That said, convention usually puts this kind of information on the "owning" entity's side. In this case, Person.events (with mappedBy="registrants") instructs Hibernate to ignore changes in Person.events, and to instead update the database based upon the contents of Event.registrants.The SO community would have more insight and can probably provide more details.
Kyle Krull
A: 

I just post some link for you because I have same problem too it's good Link for You that use Eclipse Hibernate Tool For Eclipse

some helpful Link:

http://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html#d0e2911
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/
http://boris.kirzner.info/blog/archives/2008/07/19/hibernate-annotations-the-many-to-many-association-with-composite-key/
http://docs.jboss.org/hibernate/stable/core/reference/en/html_single/

but you must notice some thing 1- create your Entity (java Class) 2- create Dao for each Entity 3- Create QueryManager and HibernateUtil(get SessionFactory) 4- and make your repos(Facade Layer)

Am1rr3zA