Reputation: 1759
Im writing a Web application using Hibernate 3.
So, after a while i noticed that something was slow. So i tested hibernate profiler and found that hibernate will make unreasonably many db-calls for simple operation. The reason is ofcourse that i load an Object (this object has several "parents") and these "parents" have other "parents". So basicly hibernate loads them all, even though i just need the basic object. Ok, so i looked into lazy-loading. Which lead me into the Lazyloading-exception, because i have a MVC webapp.
So now i'm a bit confused as to what is my best approach to this. Basicly all I need is to update a single field on an object. I already have the object-key.
Should I: 1. Dig into Lazy-loading. And then rewrite my app for a open-session-view? 2. Dig into lazy-loading. And then rewrite my dao's to be more specific. E.g. writing DAO-methods that will return objects instanciated with only whats necessary for each use-case? Could be a lot of extra methods... 3. Scratch hibernate and do it myself? 4. Cant really think of other solutions right now. Any suggestions?
What is the best practice?
Upvotes: 21
Views: 17339
Reputation: 153690
There are many things you can do to speed-up Hibernate performance, like:
@OneToMany
instead of unidirectional one, using @MapsId
for @OneToOne
, using Set
for @ManyToMany
Upvotes: 7
Reputation: 15308
Use load() method if it's possible since it doesn't issue a select query until it's required. E.g. if you have a Book and an Author and you want to associate them together, this will won't issue any selects, only single insert:
Book b = (Book) session.load(Book.class, bookId); Author a = (Author) session.load(Author.class, authorId); b.setAuthor(a); session.save(b);
Use named queries (in your hbm files or in @NamedQuery) so that they are not parsed during each query. Don't use Criteria API until it's required (it makes impossible to use PreparedStatement cache in this case)
session.setReadOnly(object, true)
. This will make Hibernate not to keep an original snapshot of the selected entity in the persistent context for further dirty checks.c3p0.max_statements
in order to enable PreparedStatment cache in the pool and enable the statement cache of your DB if it's switched off by default.setMaxResults()
, setFirstResult()
) along with queries that contain joins to collections, this will result in all the records pulled from database and pagination will happen in memory by Hibernate. If you want pagination, ideally you shouldn't use joins. If you can't escape it, again - use batch fetching.Actually there are a lot of tricks, but I can't recall more at the moment.
Upvotes: 32
Reputation: 6901
I believe you want to review this section in the Hibernate manual.
I expect that your original problem of "...unreasonably many db-calls..." is an instance of what they call the "N+1 selects problem". If so, they've got options on how to deal with it.
The first two can be specified at the association level, and fetch type can be overridden at the query level. You should be able to get your query to do only what you need, no more, and do it with a 'good' SQL query with these tools.
Upvotes: 1