Hibernate Mappings for Performance and Serialization

What

An example of how to do Hibernate Mapping/JPA in a manner most conducive to well-performing database queries and minimally-painful serialization.

Why

Because I seem to have this discussion way too often and this stuff is too abstract to talk about without something concrete.

Because I’ve been down this road too many times and wanted to share those learnings generally.

Because I believe in domain-driven design and development and often people shoot themselves in the foot when mapping things.

Where

https://github.com/revelfire/mappingexample

How

Basic Mapping Goals

  • Minimize the object “graph” to owned-relationships
  • Prevent stack overflow errors on serialization
  • Prevent massive descent into the object graph on serialization
  • Model the data closely to how it gets accessed
  • Keep it simple

Guiding Principles

  • No, or minimal, bidirectional relationships
  • Minimize entity relationships, maximize use of foreign keys
  • Allow services to store relationships rather than automating with instance references
  • Allow HQL/Repository loads and services to load relationships WHEN they matter

So much of this stuff is use-case based and should be considered in the context of access vs ownership, both in services and over the wire.  Please keep this in mind for the example, I will endeavor to explain the modeling choices in this light.

Ownership

OK lets talk about the example. (In case you didn’t read above: https://github.com/revelfire/mappingexample) We have here a very basic Account->User->Address set of domain/service/repository/test classes. One of the most common use cases you’re likely to find.

Notice that the Account object doesn’t actually contain a User object. User does contain an account_id.  Why?

It is generally the case that when we are interacting with a User, we don’t care about the Account (e.g. profile view/edit, access rights, password updates).  On the other hand, when we interact with an Account, we sometimes want to know a list of User (admin screens).

@Entity
@Table(name="account")
public class Account extends Identifiable {

    @Column(length = 50, nullable = false)
    private String name;
...
}
@Entity
@Table(name="user")
public class User extends Identifiable {

    @Column(length = 100, nullable = false)
    private String name;
// note that this is not a reference to Account
    @Column(name = "account_id", nullable = false)
    private Long accountId;

    /**
     * This COULD be @OneToOne as an "owned" relationship if we felt strongly
     * about having a separate table.
     *
     * This COULD be a one-many scenario in which case it would not be modeled on this
     * end, rather a repository.loadAddressForUser with address.user_id being the join point
     * via the foreign key reference.
     */
    @Embedded
    private Address address;
...
}

So – Account is an “owner” of users in the sense that without it, the users probably don’t make sense by themselves, and would go away if the account went away. So of course Account should have access to users, BUT it is one to many, so I really don’t want to cascade those changes, or even load the list of users in the general case – only when I really mean to (e.g. not when serializing). So I model it this way to create an avenue to access, but limit the ownership (delegating to the service tier).

Often times I will hear “but Chris we want to be able to easily get the list of USERS from the ACCOUNT by simply typing user.account!  Yes. Maybe you do. You are trying to be lazy but failing because you are actually causing more work for yourself down the line. You now will have to set up OpenSessionInViewFilter most likely, and that sucks. Or worse, you make it EAGER, and shoot yourself every freakin time you load it. (The ignorant developers way of solving LazyInitializationException)

How about instead you create a nice repository method for that one-off use case?

@Repository
public interface AccountRepository extends CrudRepository<Account, Long> {
@Query(“select u from User u where u.accountId = ?”)
List<User> getUsersForAccount(long accountId);
}

That wasn’t so bad, was it? Access granted.

Sometimes also there is concern about managing parent/child key relationships. To that, I make this case: You WANT to manage those. You don’t often set them, except for on create, and you are already doing that, just as an entity, not as an id explicitly. So you an id. You’ll live longer.

Also on the topic of ownership, note that Address is @Embedded into User.  You can read the comments there now because you skipped them before.  Basically, I only ever turn on cascade with @OneToOne and really the only reason to use that is to make your DBA happy or to prevent severely wide tables (which seems somewhat rare). This is more true ownership in the sense that with one loads the other, always.

What’s Wrong With Bidirectional?

Oftentimes in the documentation you will read things about mapping a bidirectional relationships. While possible, I assert that this is the wrong thing to do in 99% of the cases.  It is very rare that you need to ask about User from Address, or about Account from User, and in the cases you do, go ahead and load that entity by the id. Your code will be cleaner and you will have fewer errors.

Also, entity<->entity mapping and bidirectional mapping will often cause serialization to go bonkers and StackOverflowError. This is bad. Of course, you could @JsonIgnore that relationship or @JsonBackreference or whatever – but now you are most likely hacking in the solution. The (unnecessary) mapping itself is the problem.

What About Many to Many?

In many to many there is almost always no ownership. Just access, and we have different methods for creating availability.

I don’t have this use case in this example (yet). I may add it. Simple answer is, with many to many you are probably better off still letting JPA implementation manage this relationship.  However, you should be careful to disable cascading behaviors,

e.g.

@JsonIgnore
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
 @JoinTable(
      name = "country_states", 
      joinColumns = { @JoinColumn(name = "STATE_ID", nullable = false, updatable = false) }, 
      inverseJoinColumns = { @JoinColumn(name = "COUNTRY_ID", nullable = false, updatable = false) })
public Set<States> getStates() {
  return this.categories;
}

I find I don’t run into this use case too often “in the wild” and typically wind up doing things in the services, or using (again) repository queries for these types of many-many loads. There is, however, much value of @ManyToMany in managing the join table when the case does arise.

And Finally

If you take these approaches you will find your database performs better (far fewer automated joins, access to data when you need it, not just because hibernate is a dumb animal), your REST calls are smoother (serialization doesn’t wreak havoc), you don’t need OpenSessionInViewFilter (slowing things down and locking up connections in the pool), and ultimately you start to model your API endpoints a little differently. They really ought to be resource based, and granular, unless performing some larger non-CRUD unit of work which, lets face it, is service backed anyway (not automated via JPA). Right?

 

 

Why I’m Walking and Working

Some fads are fads. Some fads are causes. This one is, I believe, a cause. Eight years ago I built my first walk-n-work desk for health reasons. As a software engineer, I sit for a living…or maybe I sit to my death. In any case I had back problems early on which were identified by doctors, chiropractors, and massage therapists alike as “sitting injuries”.

So – I bought a treadmill and built a desk around it. I walked 3-4 hours a day while working. As a telecommuter I was fortunate to be able to do this. Combined with a reasonable diet and absolutely no other exercise, I lost around 35 pounds. Much less expensive that what I spent on doctors, chiropractors, and massage therapists, and with better results.  I thought I might start a business making things like this for companies who cared about ergonomics and health!

Well…the thing broke down, I got lazy. I didn’t start a company. I moved and didn’t bring it with me…etc. Gained a bunch of weight back. Developed worsening back problems, neck problems, shoulder and wrist problems, gout, high blood pressure…

The worst of it was, a friend of mine responding to my gout, said “ah, rich mans disease.” I realize it’s an old saying, but I was still offended. By american standards I’m perhaps upper middle class but not rich, and even at upper middle class wages I have a very middle class lifestyle and a reasonable diet. But – he was right. Historically it was a rich mans disease. High fat foods, sedentary lifestyle…gout happens. My doctor said the best cure he had for gout was me losing weight.

It isn’t that I’m a big fat gluttonous slug (mostly…I do like some cake now and then); it’s that watching my calories, cutting out soda and most sweets, stopping when I’m full, all of it doesn’t much help. Even eating mostly home cooked, organic, veggie-centric, reasonable meals – sitting for a living leaves me heavy, and getting heavier.

I noticed the stand up desk explosion happening at several companies. It seemed like the up/down desk and my old friend the treadmill desk were taking off. I really should look into what is out there.

I told a friend I was ordering one and he laughed loudly. Ridiculous! He is also a software developer. I told him there was real danger in sitting for a living.

“Bah. Pseudoscience at best I’m sure!”

So I went a-looking, and I came across the initiative for this “fad”. Apparently some clever scientists actually studied the problem, and, shockingly, learned that sitting is bad for our health. Of course in some way we knew that, but HOW bad, well – here’s the Mayo Clinic on the matter…

http://www.mayoclinic.com/health/sitting-disease/MY02177

On Sitting:

50 to 70 percent of people spend six or more hours sitting a day
20 to 35 percent spend four or more hours a day watching TV

On Living:

If Americans would cut their sitting time in half, their life expectancy would increase by roughly:

2 years (by reducing sitting to less than 3 hours a day)
1.4 years (by reducing TV time to less than 2 hours a day)

And I think software developers sit 8-14 hours a day!

Some typical media-ified content on the matter -

http://www.theatlantic.com/health/archive/2012/04/confirmed-he-who-sits-the-most-dies-the-soonest/256101/#

and here is the actual science it references: http://archinte.jamanetwork.com/article.aspx?articleid=1108810

Here’s a punch line – exercise doesn’t really help -

“…demonstrates that inactive participants with high levels of sitting had the highest mortality rate, and the strong relationship of increased sitting time to mortality persisted, even among participants with relatively high levels of physical activity. ”

So – you can’t just do the gym thing an hour here or there. You actually have to GET UP out of the damn chair, and stand or walk. Since sitting burns 5/cal/hr, and standing only burns 15/cal/hr, I figure walking is the best option. That gets you >100/cal/hr – so in an 8 hour day you can burn 40, 120, or 1000+ calories, your choice. Obviously it isn’t just about calories, but that is where it starts. Get rid of the fat, get the body working naturally again, and the health will follow.

I find that I can’t REALLY walk 8 hours a day, at least not yet. But I can walk a lot. Anything is better than what I used to do. And the real kicker is this: I have better focus, concentration, and interest in what I am doing. Probably more blood to the brain or something, but, yay walk-n-work.

Some other articles if you are interested:

http://www.thelancet.com/journals/lancet/article/PIIS0140-6736(12)61031-9/abstract

http://www.bbc.co.uk/news/uk-wales-politics-18876880

http://www.americashealthrankings.org/all/sedentary

http://www.lifespanfitness.com/workplacesolutions-treadmill-desk-and-bike-desk-research.html  ..

I’ll report back on this blog if I actually manage to lose weight, and what type of steps/miles I burn.

Light The Match

Welcome to Revel Fire dot com. It has been a couple of years since I have run a consultancy, opting instead to live the startup life awhile.  Startup life is awesome.  The constant challenge, multiple hats, greenfield work, evolution of process and product – so much to do, so many pieces.  I love it.  I thrive.

There has come a time, however, (that time being now), that I wish to be able to offer the skills and services to a wider audience, to scale out the best practices evolved from years of startup life to more companies.  I’ve seen where consultants have failed me as a VP and CTO.  I’ve seen where processes break down.  I’ve seen how direction, architecture, and leadership are needed in all companies, but so often not on a fulltime basis.  To leverage a military analogy, every army needs a general, but not every platoon.  Many startups are closer to a platoon in nature, at the beginning.

Thus, Revel Fire.  Our goal is to provide orthogonal services to startups and enterprises alike, in the capacity they need.  We are like quick set cement.  We can flow easily into the most needed areas and provide immediate improvement.  Very often a company needs overall architectural guidance, but only for a few weeks every quarter.  Assistance with hiring the right development staff but only for a few hours or days here and there.  A parallel development team to crank out an extra feature or two that an overloaded dev team doesn’t have time to get in. A slipping project that needs to be put back on the rails.

We seek to be transparent to the client, integrated and involved with the stake holders, accepted and respected by the developers, and most of all, useful, not wasteful. Real consulting should be about what you need, not what we need. In fact I’d rather you think of us as a partner, not as a consultancy.

Give us a call and tell us where it hurts. We can help.

© Copyright Revel Fire - site by ps3 design