简体   繁体   中英

Hibernate One To Many Mapping using Spring Error

I am using Hibernate with Spring and i run into this problem failed to lazily initialize a collection : , no session or session was closed using one-to-many relationship I have two tables one is Users & Roles from Users i am trying to get the roles using lazy fetch. The StackTrace

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.rep.users.KZ_Users.roleList, no session or session was closed
    org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
    org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
    org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
    org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    org.hibernate.collection.PersistentList.iterator(PersistentList.java:115)
    com.rep.users.KZ_Users.getAuthorities(KZ_Users.java:137)
    org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.createSuccessAuthentication(AbstractUserDetailsAuthenticationProvider.java:186)
    org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:165)
    org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:120)
    org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:48)
    org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:138)
    org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:48)
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:97)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:109)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)

i have implemented UserDetails, Serializable in my KZ_Users pojo class and the method that causing the error is

@Override
    public Collection<GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();

        for (Roles roles : roleList) { //<-- ERROR 
            list.add(new GrantedAuthorityImpl(roles.getRole()));
        }

        return list;
    }

the rolelist is define in KZUser Class. Can any one tell me what was the problem Error is

 16:15:01,317 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/ReportingPortalV3].[default]] (http-/192.168.1.124:8080-2) JBWEB000236: Servlet.service() for servlet default threw exception: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.rep.users.KZ_Users.roleList, no session or session was closed

Thanks in advance.

Keep Spring specific API separate from your entities. Instead of directly implementing UserDetails interface in your @Entity class, extend it (or compose), ie:

public class CurrentUser extends User implements UserDetails {

    private final Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();

    public CurrentUser(User user) {
        super(user);
        initAuthorities(user);
    }

    private void initAuthorities(User user) {
        if (user.getRoles() == null) {
            return;
        }
        for (Authority role : user.getRoles()) {
            authorities.add(new SimpleGrantedAuthority(role.getAuthority()));
        }
    }

    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        return authorities;
    }

    // implement the rest of UserDetails interface accordingly
}

Also keep initialization of authorities collection in the constructor. And then:

public class UserDetailsServiceImpl extends UserDetailsService {

    @Override
    @Transactional(propagation = SUPPORTS, readOnly = true)
    public CurrentUser loadUserByUsername(String username) 
            throws AuthenticationException ,DataAccessException {
        ensureNotEmpty(username);
        User user = userRepository.findUserWithAuthorities(username);
        if (user == null) {
            throw new UsernameNotFoundException("Invalid credentials!");
        }
        return new CurrentUser(user);
    }
}

Notice that this way you'll be accessing the roles collection still within the transaction marked my @Transactional . Now Spring can call getAuthorities() wherewer it needs, and it will work fine, bacuse it's already initialized and connection to database is no longer required.

Always know where your transaction starts and ends .

Depending on your use case, you migh also think about using OpenEntityManagerInViewFilter or OpenEntityManagerInViewInterceptor (or equivalents for native Hibernate API OpenSessionInViewFilter/Intercetor ), but read about consequences first .

And please tell me that KZ in the name of the class are not your initiials? If they are, please, please, please don't do that...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM