In this application we are developing, we noticed that a view was particularly slow. I profiled the view and noticed that there was one query executed by hibernate which too
Here's something that has been working for me (without instrumentation):
Instead of using @OneToOne
on both sides, I use @OneToMany
in the inverse part of the relationship (the one with mappedBy
). That makes the property a collection (List
in the example below), but I translate it into an item in the getter, making it transparent to the clients.
This setup works lazily, that is, the selects are only made when getPrevious()
or getNext()
are called - and only one select for each call.
CREATE TABLE `TB_ISSUE` (
`ID` INT(9) NOT NULL AUTO_INCREMENT,
`NAME` VARCHAR(255) NULL,
`PREVIOUS` DECIMAL(9,2) NULL
CONSTRAINT `PK_ISSUE` PRIMARY KEY (`ID`)
);
ALTER TABLE `TB_ISSUE` ADD CONSTRAINT `FK_ISSUE_ISSUE_PREVIOUS`
FOREIGN KEY (`PREVIOUS`) REFERENCES `TB_ISSUE` (`ID`);
@Entity
@Table(name = "TB_ISSUE")
public class Issue {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
@Column
private String name;
@OneToOne(fetch=FetchType.LAZY) // one to one, as expected
@JoinColumn(name="previous")
private Issue previous;
// use @OneToMany instead of @OneToOne to "fake" the lazy loading
@OneToMany(mappedBy="previous", fetch=FetchType.LAZY)
// notice the type isnt Issue, but a collection (that will have 0 or 1 items)
private List next;
public Integer getId() { return id; }
public String getName() { return name; }
public Issue getPrevious() { return previous; }
// in the getter, transform the collection into an Issue for the clients
public Issue getNext() { return next.isEmpty() ? null : next.get(0); }
}