views:

119

answers:

0

I have two database tables, User and Role. I'm trying to set up a bidirectional many-to-many mapping in my application but I'm running into performance issues when eagerly fetching. The many-to-many works using a UserRole join table. My DTOs look like this (fat has been trimmed):

UserDTO.java

@Entity
@Table(name = "[redacted].User")
public class UserDTO implements Serializable {      
    /* other field declarations snipped */
    private Set<RoleDTO> roles = new HashSet<RoleDTO>();

    public UserDTO() {}

    /* other getters/setters snipped */

    @Fetch(FetchMode.JOIN)
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "[redacted].UserRole",
               joinColumns = { @JoinColumn(name = "userId") },
               inverseJoinColumns = { @JoinColumn(name = "roleId") })
    public Set<RoleDTO> getRoles() {
        return roles;
    }

    public void setRoles(Set<RoleDTO> roles) {
        this.roles = roles;
    }
}

RoleDTO.java

@Entity
@Table(name = "[redacted].Role")
public class RoleDTO implements Serializable {  
    /* other field declarations snipped */
    private Set<UserDTO> users = new HashSet<UserDTO>();

    public RoleDTO() {}

    /* other getters/setters snipped */

    @Fetch(FetchMode.JOIN)
    @ManyToMany(mappedBy = "roles")
    public Set<UserDTO> getUsers() {
        return users;
    }

    public void setUsers(Set<UserDTO> users) {
        this.users = users;
    }
}

All is well with the world, except that things run really slowly - like, O(30 seconds) to update 5 user rows where each user has 2 roles. I think it's because of the eager fetching. I've tried looking at the SQL that Hibernate generates, but I can't tease anything meaningful out of it. I can post a link to a SQL dump if anyone's interested.

At any rate, I'd like to try to fix this by switching to lazy loading. When I change @ManyToMany(fetch = FetchType.EAGER) to @ManyToMany(fetch = FetchType.LAZY), I get the classic error

org.hibernate.LazyInitializationException: failed to lazily initialize a collection [blah blah] no session or session was closed.

I understand why this exception is thrown, but I don't know the best way to fix it.

  • Keep the session (transaction?) open for as long as I need to? How?
  • Omit the mapping from my EJB entirely, and just manually fetch a user's roles (and a role's user) in my application logic? This feels like a poor man's lazy load, and I have no idea of how I'd handle pushing changes back into the database without explicitly editing the join table (which sounds really unappealing).
  • Something else?

If it matters, my beans are @Stateless, since that's how I've seen it done on other projects.