Archive

Posts Tagged ‘hibernate’

Debugging Hibernate generated SQL

April 13th, 2010 Nicolas Frankel 1 comment

In this article, I will explain how to debug Hibernate’s generated SQL so that unexpected query results be traced faster either to a faulty dataset or a bug in the query.

There’s no need to present Hibernate anymore. Yet, for those who lived in a cave for the past years, let’s say that Hibernate is one of the two ORM frameworks (the second one being TopLink) that dramatically ease database access in Java.

One of Hibernate’s main goal is to lessen the amount of SQL you write, to the point that in many cases, you won’t even write one line. However, chances are that one day, Hibernate’s fetching mechanism won’t get you the result you expected and the problems will begin in earnest. From that point and before further investigation, you should determine which is true:

  • either the initial dataset is wrong
  • or the generated query is
  • or both if you’re really unlucky

Being able to quickly diagnose the real cause will gain you much time. In order to do this, the greatest step will be viewing the generated SQL: if you can execute it in the right query tool, you could then compare pure SQL results to Hibernate’s results and assert the true cause. There are two solutions for viewing the SQL.

Show SQL

The first solution is the simplest one. It is part of Hibernate’s configuration and is heavily documented. Just add the following line to your hibernate.cfg.xml file:

<hibernate-configuration>
  <session-factory>
...
    <property name="hibernate.show_sql">true</property>
  </session-factory>
</hibernate-configuration>

The previous snippet will likely show something like this in the log:
select this_.PER_N_ID as PER1_0_0_, this_.PER_D_BIRTH_DATE as PER2_0_0_, this_.PER_T_FIRST_NAME as PER3_0_0_, this_.PER_T_LAST_NAME as PER4_0_0_ from T_PERSON this_

Not very readable but enough to copy/paste in your favourite query tool.

The main drawback of this is that if the query has parameters, they will display as ? and won’t show their values, like in the following output:

select this_.PER_N_ID as PER1_0_0_, this_.PER_D_BIRTH_DATE as PER2_0_0_, this_.PER_T_FIRST_NAME as PER3_0_0_, this_.PER_T_LAST_NAME as PER4_0_0_ from T_PERSON this_ where (this_.PER_D_BIRTH_DATE=? and this_.PER_T_FIRST_NAME=? and this_.PER_T_LAST_NAME=?)

If they’re are too many parameters, you’re in for a world of pain and replacing each parameter with its value will take too much time.

Yet, IMHO, this simple configuration should be enabled in all environments (save production), since it can easily be turned off.

Proxy driver

The second solution is more intrusive and involves a third party product but is way more powerful. It consists of putting a proxy driver between JDBC and the real driver so that all generated SQL will be logged. It is compatible with all ORM solutions that rely on the JDBC/driver architecture.

P6Spy is a driver that does just that. Despite its age (the last release dates from 2003), it is not obsolete and server our purpose just fine. It consists of the proxy driver itself and a properties configuration file (spy.properties), that both should be present on the classpath.

In order to leverage P6Spy feature, the only thing you have to do is to tell Hibernate to use a specific driver:

<hibernate-configuration>
  <session-factory>
    <!-- Only this line changes -->
    <property name="connection.driver_class">com.p6spy.engine.spy.P6SpyDriver</property>
...
 </session-factory>
</hibernate-configuration>

This is a minimal spy.properties:

module.log=com.p6spy.engine.logging.P6LogFactory
realdriver=org.hsqldb.jdbcDriver
autoflush=true
excludecategories=debug,info,batch,result
appender=com.p6spy.engine.logging.appender.StdoutLogger

Notice the realdriver parameter so that P6Spy knows where to redirect the calls.

With just these, the above output becomes:
1270906515233|3|0|statement|select this_.PER_N_ID as PER1_0_0_, this_.PER_D_BIRTH_DATE as PER2_0_0_, this_.PER_T_FIRST_NAME as PER3_0_0_, this_.PER_T_LAST_NAME as PER4_0_0_ from T_PERSON this_ where (this_.PER_D_BIRTH_DATE=? and this_.PER_T_FIRST_NAME=? and this_.PER_T_LAST_NAME=?)|select this_.PER_N_ID as PER1_0_0_, this_.PER_D_BIRTH_DATE as PER2_0_0_, this_.PER_T_FIRST_NAME as PER3_0_0_, this_.PER_T_LAST_NAME as PER4_0_0_ from T_PERSON this_ where (this_.PER_D_BIRTH_DATE=’2010-04-10′ and this_.PER_T_FIRST_NAME=’Johnny’ and this_.PER_T_LAST_NAME=’Be Good’)

Of course, the configuration can go further. For example, P6Spy knows how to redirect the logs to a file, or to Log4J (it currently misses a SLF4J adapter but anyone could code one  easily).

If you need to use P6Spy in an application server, the configuration should be done on the application server itself, at the datasource level. In that case, every single use of this datasource will be traced, be it from Hibernate, TopLink, iBatis or plain old JDBC.

In Tomcat, for example, put spy.properties in common/classes and update the datasource configuration to use P6Spy driver.

The source code for this article can be found here.

To go further:

  • P6Spy official site
  • Log4jdbc, a Google Code contender that aims to offer the same features
Categories: Java Tags: , ,

Spring Persistence with Hibernate

March 1st, 2010 Nicolas Frankel No comments

This review is about Spring Persistence with Hibernate by Ahmad Reza Seddighi from Packt Publishing.

Facts

  1. 15 chapters, 441 pages, 38€99
  2. This book is intended for beginners but more experienced developers can learn a thing or two
  3. This book covers Hibernate and Spring in relation to persistence

Pros

  1. The scope of this book is what makes it very interesting. Many books talk about Hibernate and many talk about Spring. Yet, I do not know of many which talk about the use of both in relation to persistence. Explaining Hibernate without describing the transactional side is pointless
  2. The book is well detailed, taking you by the hand from the bottom to reach a good level of knowledge on the subject
  3. It explains plain AOP, then Spring proxies before heading to the transactional stuff

Cons

  1. The book is about Hibernate but I would have liked to see a more tight integration with JPA. It is only described as an another way to configure the mappings
  2. Nowadays, I think Hibernate XML configuration is becoming obsolete. The book views XML as the main way of configuration, annotations being secondary
  3. Some subjects are not documented: for some, that’s not too important (like Hibernate custom SQL operations), for others, that’s a real loss (like the @Transactional Spring annotation)

Conclusion

Despite some minor flaws, Spring Persistence with Hibernate let you go head first into the very complex sujbect of Hibernate. I think that Hibernate has a very low entry ticket, and you can be more productive with it very quickly. On the downside, mistakes will cost you much more than with old plain JDBC. This book serves you Hibernate and Spring concepts on a platter, so you will make less mistakes.

Categories: Book review Tags: , ,

Hibernate hard facts – Part 5

March 1st, 2010 Nicolas Frankel 2 comments

In the fifth article of this serie, I will show you how to manage logical DELETE in Hibernate.

Most of the time, requirements are not concerned about deletion management. In those cases, common sense and disk space plead for physical deletion of database records. This is done through the DELETE keyword in SQL. In turn, Hibernate uses it when calling the Session.delete() method on entities.

Sometimes, though, for audit or legal purposes, requirements enforce logical deletion. Let’s take a products catalog as an example. Products regularly go in and out of the catalog. New orders shouldn’t be placed on outdated products. Yet, you can’t physically remove product records from the database since they could have been used on previous orders.

Some strategies are available in order to implement this. Since I’m not a DBA, I know of only two. From the database side, both add a column, which represents the deletion status of the record:

  • either a boolean column which represent either active or deleted status
  • or, for more detailed information, a timestamp column which states when the record was deleted; a NULL meaning the record is not deleted and thus active

Managing logical deletion is a two steps process: you have to manage both selection so that only active records are returned and deletion so that the status marker column is updated the right way.

Selection

A naive use of Hibernate would map this column to a class attribute. Then, selecting active records would mean a WHERE clause on the column value and deleting a record would mean setting the attribute and calling the update() method. This approach has the merit of working. Yet, it fundamentally couples your code to your implementation. In the case you migrate your status column from boolean to timestamp, you’ll have to update your code everywhere it is used.

The first thing you have to do to mitigate the effects of such a migration is to use a filter.

Hibernate3 provides an innovative new approach to handling data with “visibility” rules. A Hibernate filter is a global, named, parameterized filter that can be enabled or disabled for a particular Hibernate session.

Such filters can the be used throughout your code. Since the filtering criteria is thus coded in a single place, updating the database schema has only little incidence on your code. Back to the product example, this is done like this:

@Entity
@FilterDef(name = "activeProducts")
@Filter(name = "activeProducts", condition = "DELETION_DATE IS NULL")
public class Product {

  @Id
  @Column(nullable = false)
  @GeneratedValue(strategy = AUTO)
  private Integer id;

...
}

Note: in the attached source, I also map the DELETION_DATE on an attribute. This is not needed in most cases. In mine, however, it permits me to auto-create the schema with Hibernate.

Now, the following code will filter out logically deleted records:

session.enableFilter("activeProducts");

In order to remove the filter, either use Session.disableFilter() or use a new Session object (remember that factory.getCurrentSession() will probably use the same, so factory.openSession() is in order).

Deletion

The previous step made us factorize the “select active-only records” feature. Logically deleting a product is still coupled to your implementation. Hibernate let us decouple further: you can overload any CRUD operations on entities! Thus, deletion can be overloaded to use an update of the right column. Just add the following snippet to your entity:

@SQLDelete(sql = "UPDATE PRODUCT SET DELETION_DATE=CURRENT_DATE WHERE ID=?")

Now, calling session.delete() on an Product entity will produce the updating of the record and the following output in the log:

UPDATE PRODUCT SET DELETION_DATE=CURRENT_DATE WHERE ID=?

With CRUD overloading, you can even suppress the ability to select inactive records altogether. I wouldn’t recommend this approach however, since you wouldn’t be able to select inactive records then. IMHO, it’s better to stick to filters since they can be enabled/disabled when needed.

Conclusion

Hibernate let you loosen the coupling between your code and the database so that you can migrate from physical deletion to logical deletion with very localized changes. In order to do this, Hibernate offers two complementary features: filters and CRUD overloading. These features should be part of any architect’s bag of tricks since they can be lifesavers, like in previous cases.

You can find the sources of this article here in Maven/Eclipse format.

To go further:

Categories: Java Tags:

Hibernate hard facts – Part 4

February 17th, 2010 Nicolas Frankel No comments

In the fourth article of this serie, I will show the subtle differences between get() and load() methods.

Hibernate, like life, can be full of suprises. Today, I will share one with you: have you ever noticed that Hibernate provides you with 2 methods to load a persistent entity from the database tier? These two methods are get(Class, Serializable) and load(Class, Serializable) of the Session class and their respective variations.

Strangely enough, they both have the same signature. Strangely enough, both of their API description starts the same:

Return the persistent instance of the given entity class with the given identifier.

Most developers use them indifferently. It is a mistake since, if the entity is not found, get() will return null when load() will throw an Hibernate exception. This is well described in the API:

Return the persistent instance of the given entity class with the given identifier, assuming that the instance exists. You should not use this method to determine if an instance exists (use get() instead). Use this only to retrieve an instance that you assume exists, where non-existence would be an actual error.

Truth be told, the real difference lies elsewhere: the get() method returns an instance, whereas the load() method returns a proxy. Not convinced? Try the following code snippet:

Session session = factory.getCurrentSession();

Owner owner = (Owner) session.get(Owner.class, 1);

// Test the class of the object
assertSame(owner.getClass(), Owner.class);

The test pass, asserting that the owner’s class is in fact Owner. Now, in another session, try the following:

Session session = factory.getCurrentSession();

Owner owner = (Owner) session.load(Owner.class, 1);

// Test the class of the object
assertNotSame(owner.getClass(), Owner.class);

The test will pass too, asserting that the owner’s class is not Owner. If you spy the object in the debugger, you’ll see a Javassist proxyed instance and that fields are not initialized! Notice that in both cases, you are able to safely cast the instance to Owner. Calling getters will also return expected results.

Why call the load() method then? Because since it is a proxy, it won’t hit the DB until a getter method is called.

Moreover, these features are also available in JPA from the EntityManager, respectively with the find() and getReference() methods.

Yet, both behaviours are modified by Hibernate’s caching mechanism. Try the following code snippet:

// Loads the reference
session.load(Owner.class, 1);

Owner owner = (Owner) session.get(Owner.class, 1);

According to what was said before, owner’s real class should be the real McCoy. Dead wrong! Since Hibernate previously called load(), the get() looks in the Session cache (the 1st level one) and returns a proxy!

The behaviour is symmetrical with the following test, which will pass although it’s counter-intuitive:

// Gets the object
session.get(Owner.class, 1);

// Loads the reference, but looks for it in the cache and loads
// the real entity instead
Owner owner = (Owner) session.load(Owner.class, 1);

// Test the class of the object
assertSame(owner.getClass(), Owner.class);

Conclusion: Hibernate does a wonderful job at making ORM easier. Yet, it’s not an easy framework: be very wary for subtle behaviour differences.

The sources for the entire hard facts serie is available here in Eclipse/Maven format.

Categories: Java Tags: , , , ,

Hibernate hard facts part 3

December 13th, 2009 Nicolas Frankel No comments

Hibernate LogoIn the third article of this serie, I will show how to tweak Hibernate so as to convert any database data types to and from any Java type and thus decouple your database model from your object model.

Custom type mapping

Hibernate is a very powerful asset in any application needing to persist data. As an example, I was tasked this week to generate the Object-Oriented model for a legacy database. It seemed simple enough, at first glance. Then I discovered a big legacy design flaw: for historical reasons, dates were stored as number in the YYYYMMDD format. For example, 11th december 2009 was 20091211. I couldn’t or rather wouldn’t change the database and yet, I didn’t want to pollute my neat little OO model with Integer instead of java.util.Date.

After browsing through Hibernate documentation, I was confident it made this possible in a very simple way.

Creating a custom type mapper

The first step, that is also the biggest, consist in creating a custom type. This type is not a real “type” but a mapper that knows how to convert from the database type to the Java type and vice-versa. In order to do so, all you have is create a class that implements org.hibernate.usertype.UserType. Let’s have a look at each implemented method in detail.

The following method gives away what class will be returned at the end of read process. Since I want a Date instead of an Integer, I naturally return the Date class.

public Class returnedClass() {

  return Date.class;
}

The next method returns what types (in the Types constants) the column(s) that will be read fromhave. It is interesting to note that Hibernate let you map more than one column, thus having the same feature as the JPA @Embedded annotation. In my case, I read from a single numeric column, so I should return a single object array filled with Types.INTEGER.

public int[] sqlTypes() {

  return new int[] {Types.INTEGER};

}

This method will check whether returned class instances are immutable (like any normal Java types save primitive types and Strings) or mutable (like the rest). This is very important because if false is returned, the field using this custom type won’t be checked to see whether an update should be performed or not. It will be of course if the field is replaced, in all cases (mutable or immutable). Though there’s is a big controversy in the Java API, the Date is mutable, so the method should return true.

public boolean isMutable() {

  return true;

}

I can’t guess how the following method is used but the API states:

Return a deep copy of the persistent state, stopping at entities and at collections. It is not necessary to copy immutable objects, or null values, in which case it is safe to simply return the argument.

Since we just said Date instances were mutable, we cannot just return the object but we have to return a clone instead: that’s made possible because Date‘s clone() method is public.

public Object deepCopy(Object value) throws HibernateException {

  return ((Date) value).clone();
}

The next two methods do the real work to respectively read from and to the database. Notice how the API exposes ResultSet object to read from and PreparedStatement object to write to.

public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {

  Date result = null;

  if (!rs.wasNull()) {

    Integer integer = rs.getInt(names[0]);

    if (integer != null) {

      try {

        result = new SimpleDateFormat("yyyyMMdd").parse(String.valueOf(integer));

      } catch (ParseException e) {

        throw new HibernateException(e);
      }
    }
  }

  return result;
}

public void nullSafeSet(PreparedStatement statement, Object value, int index) throws HibernateException, SQLException {

  if (value == null) {

    statement.setNull(index, Types.INTEGER);

  } else {

    Integer integer = Integer.valueOf(new SimpleDateFormat("yyyyMMdd").format((String) value));

    statement.setInt(index, integer);
  }
}

The next two methods are implementations of equals() and hasCode() from a persistence point-of-view.

public int hashCode(Object x) throws HibernateException {

  return x == null ? 0 : x.hashCode();
}

public boolean equals(Object x, Object y) throws HibernateException {

  if (x == null) {

    return y == null;
  }

  return x.equals(y);
}

For equals(), since Date is mutable, we couldn’t just check for object equality since the same object could have been changed.

The replace() method is used for merging purpose. It couldn’t be simpler.

public Object replace(Object original, Object target, Object owner) throws HibernateException {

  Owner o = (Owner) owner;

  o.setDate(target);

  return ((Date) original).clone();
}

My implementation of the replace() method is not reusable: both the owning type and the name of the setter method should be known, making reusing the custom type a bit hard. If I wished to reuse it, the method’s body would need to use the lang.reflect package and to make guesses about the method names used. Thus, the algorithm for creating a reusable user type would be along the lines of:

  1. list all the methods that are setter and take the target class as an argument
    1. if no method matches, throw an error
    2. if a single method matches, call it with the target argument
    3. if more than one method matches, call the associated getter to check which one returns the original object

The next two methods are used in the caching process, respectively in serialization and deserialization. Since Date instances are serializable, it is easy to implement them.

public Serializable disassemble(Object value) throws HibernateException

  return (Date) ((Date) value).clone();
}

public Object assemble(Serializable cached, Object owner) throws HibernateException {

  return ((Date) cached).clone();
}

Declare the type on entity

Once the custom UserType is implemented, you need to make it accessible it for the entity.

@TypeDef(name="dateInt", typeClass = DateIntegerType.class)
public class Owner {

  ...
}

Use the type

The last step is to annotate the field.

@TypeDef(name="dateInt", typeClass = DateIntegerType.class)

public class Owner {

  private Date date;

  @Type(type="dateInt")
  public Date getDate() {

    return date;
  }

  public void setDate(Date date) {

    this.date = date;
  }
}

You can download the sources for this article here.

To go further:

Shark! Shark! in the IT business

August 12th, 2009 Nicolas Frankel 2 comments

Shark! Shark! screenshotDo you remember the classic Atari ST game where you, as a fish, eat other fishes while getting bigger and avoiding bigger fishes to eat you? It seems the last 4 years has seen its share of fishes eat and being eaten in the IT business.

Oh, it began innocently enough. JBoss just hired the Hibernate team. It was in November 2005. Less than 6 months later, JBoss was bought by Red Hat. I thought: “Wow, now Red Hat can provide a whole stack from Operating System to Middleware!”

January 2008: Oracle finally buys BEA Systems, the only serious commercial concurrent of IBM in the application server market. It already tried the buyout in October 2007. I then thought: “Oracle can provide the last 2 tier of any JEE application, Middleware and Database (please don’t raise the issue of Oracle Application Server). That’s interesting!”

About the same time, Sun has got the same idea the other way around when it buys MySQL. I thought: “They have both invested in OpenSource, that’s good strategy!”

When SpringSource bought Hyperion, my sense of wonder began to dry.

Now that Oracle has bought Sun and VMWare has bought SpringSource, I’m finally more concerned than ecstatic. Concurrent products that competed against one another are now in the same provider’s portfolio. No business has interest in having the same redundant softwares in its catalog. And lacking competition means no evolution, like Darwin theorized.

I always complained about Microsoft’s choices being more marketing oriented than technically sound. It could do that until it was the major player in its field. Java and Google put an end to that (ok, not entirely, this is open to discussion but let me make my point). In turn, and although Java was meant to stay a loooong time in version 1.4, Sun made it evolve because of the progress made by the .Net framework. From my humble point of view, that’s a vertuous circle in IT darwinism.

One may rightfully think the circle is now broken, when one looks at the following points:

  • Oracle Application Server and WebLogic are now owned by Oracle. Whereas stopping the development of OC4J may not be a bad thing in itself, I can’t be so sure about the whole stack surrounding both.
  • Even worse, why would Oracle need to put money in Glassfish development, now that it has WebLogic? I’m not an ardent Glassfish defender but it plays its role in the JEE ecosystem.
  • I can’t even think about Oracle database and MySQL, now that Oracle distributes Oracle Lite for free. That goes without saying but it is for development purposes only and without an OpenSource license of course.
  • What about JDeveloper and NetBeans? I fear only very bad things since if NetBeans development is stopped, it will mean IBM will do as it pleases with Eclipse (yes, I know about the Eclipse Foundation, but it still smells).
  • And poor JRockit?
  • And so on, ad nauseam.

The present concentration trend raises concerns, at least from me, because it may well end when there’s only one single player left standing. Remember the Atari game I talked about at the beginning? It was aptly named “Shark! Shark!” because regardless of the size you were, you could always be eaten by the shark. Whoever will end up being the shark, I can only guess, but if this doesn’t stop soon, we are all about to get eaten!

Hibernate hard facts part 2

June 27th, 2009 Nicolas Frankel 3 comments

Hibernate LogoHibernate is a widely-used ORM framework. Many organizations use it across their projects in order to manage their data access tier. Yet, many developers working on Hibernate don’t fully understand the full measure of its features. In this serie of articles, I will try to dispel some common misunderstandings regarding Hibernate.

Part 1 : Updating a persistent object

Directional associations

Association is a relationship between two classes that denotes a connection between the two. Navigability is the way by which an instance of one class can access the instance of the second one. UML describes the following navigabilities:

  • undirectional navigability, from class A to class B
  • bidirectional navigability, from class A to class B and from the latter to the former
  • unknown navigability (early in the design)

When talking about persistence, associations are designed from (or to, depending on what comes first) foreign key constraints. If I want to describe that a customer can have multiple orders, chances are the Order table has a foreign key constraint on the Customer table. On the other hand, there’s no such thing as directionality in the relational world. This means that the designed directionality is a feature brought to you by the object world, and the mapping tool used.

In the relational world, we speak of a relationship’s ownership to identify the where the data used by the join resides. In the previous example, the Order table is the owner since it has the foreign key constraint on the Customer table. This ownership has no relation to navigability whatsoever.

In the case of a bidirectional association, one would think that creating the association from A to B would be enough. For example, in a one-to-many association, having a customer, if I create an account, I just have to add this account to my customer’s, haven’t I? Unfortunately, this is not the case. If I forget to associate both ends, I end up catching very nasty exceptions. Interestingly enough, they are different depending on which association you miss.

It is thus a good practice to create an addOrder() method on the Customer class to manage such subtleties:

/**
 * Adds an order to this customer's. Manage bidirectional associations.
 *
 * @param order
 */
public void addOrder(Order order) {

    getOrders().add(order);
    order.setCustomer(this);
}

Whether you use this tip or not, remember to document its use (or not) in the Javadoc, since if you don’t, client code will need to.

Now if one wants to remove an order from the database, one should normally call the session.delete() method. Like above, this will throw an exception if one didn’t previously remove this order from this customer’s. This will be slightly more hindering since it cannot be factorized in the domain class.

// We got the session somehow and the snippet is running in a transaction
Order order = (Order) session.load(Order.class, 1L);

Customer customer = order.getCustomer();

customer.getOrders().remove(order);

session.delete(order);

session.getTransaction().commit();

We’ve seen previously a simple many-to-one association creation. This gets even worse in the case of a many-to-many association update, since updating means removing and creating.

You can do it in a method, provided getters return the real collection and not an unmodifiable (a usually good practice).

// In the Customer class
public void removeOrder(Order order) {

    getOrders().remove(order);

    order.getCustomers().remove(this);
}
// In the Order class
public void removeCustomer(Customer customer) {

    getCustomers().remove(customer);

    customer.getOrders().remove(this);
}

You will find the test cases here.

Categories: Java Tags: , ,

Hibernate hard facts part 1

June 14th, 2009 Nicolas Frankel 5 comments

Hibernate LogoHibernate is a widely-used ORM framework. Many organizations use it across their projects in order to manage their data access tier. Yet, many developers working on Hibernate don’t fully understand the full measure of its features. In this serie of articles, I will try to dispel some common misunderstandings regarding Hibernate.

Updating a persistent object

A widely made mistake using Hibernate is to call the update() method on an already persistent object :

session.getTransaction().begin();

Person person = (Person) session.load(Person.class, 1L);

person.setLastName("FooBar");

session.update(person);

session.getTransaction().commit();

This will get you the following Hibernate outputs :

Hibernate: select person0_.id as id0_0_,
    person0_.birthDate as birthDate0_0_,
    person0_.FIRST_NAME as FIRST3_0_0_,
    person0_.LAST_NAME as LAST4_0_0_ from Person person0_ where person0_.id=?
Hibernate: update Person set birthDate=?, FIRST_NAME=?, LAST_NAME=? where id=?

Now remove the line numbered 7. You get exactly the same output! If you check the database, the result will be the same: calling update() does nothing since the object is already persistent. If you are in debug mode, you can even check that the output’s update line is called when commiting the transaction in both cases.

You will find proof of this assertion here.

Framework agnostic JPA

March 10th, 2009 Nicolas Frankel No comments

With new JEE 5 standard has come the EJB3 specifications. From an historical point of view, EJBs come into 3 different flavors: (i) Entity for persistence, (ii) Session for business logic and (iii) Message-Driven for listeners. Entity EJB are the most time-consuming to develop in their 2.1 version. Apart from the inherent complexity of EJB (local and remote interfaces, homes), developing an EJB 2 is error-prone because of the mapping mechanism. All in all, EJB 2 development really needs a very specialized IDE and expert developers. That’s the main reason why EJB 2 didn’t achieve a significant market share, and had to compete with JDO, Hibernate and other third-party frameworks.

Sun eventually realized this and did come with a much simpler solution with EJB 3. Using Java 5 annotations, developing Entity EJB 3 is a breeze. The part of EJB 3 specifications that deal with Entity is called Java Persistence API (JPA). It is a specification in its own right, and in the next specifications, it will have its own. Developing JPA applications is a two-step process. First, you have to create you model classes. Such classes will be the foundation of your persistence layer: it would be a good idea to use this layer throughout your entire organization, since these classes should closely map your database model. A simple JPA enhanced class would look like this: Read more…

Categories: Java Tags: , ,