2017-01-16 13 views
1

私はSpringブートアプリケーションで遅延初期化に問題があります。私は遅延フィールドがRoleのエンティティを持っていますが、私は彼らがLazyInitializationExceptionをMy Spring Security(UserDetailsService)メソッドに持っていますが、コントローラではOKです。 スプリングブートがfetch = FetchType.LAZYでどのように動作するか説明できますか?なぜ、Spring Security UserDetailsServiceが動作せず、コントローラメソッドで動作しますか? これについてのガイドは見つかりませんでした。ありがとう!春のブートとfetchType =怠惰

春ブーツ:

@SpringBootApplication 
public class App { 

    public static void main(String[] args) throws Exception { 
     SpringApplication.run(App.class, args); 
    } 
} 

アンエンティティ:

@Entity 
@Table(name = "users") 
@Getter 
@Setter 
@NoArgsConstructor 
public class Users { 
    @ManyToMany(fetch = FetchType.LAZY) 
    @JoinTable(name = "Users_Role", joinColumns = @JoinColumn(name = "User_id", referencedColumnName = "id"), 
      inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")) 
    private Set<Role> roles = new HashSet<Role>(); 
} 

マイサービス:

@Transactional(readOnly = true)//does not matter 
public Users getUserByLogin(String login) { 
     return usersRepository.findOneByLogin(login); 
    } 

    @Transactional(readOnly = true) 
    public Users getUserByLoginWithRoles(String login) { 
     Users oneByLogin = usersRepository.findOneByLogin(login); 
     logger.debug("User was initialize with Roles: " + oneByLogin.getRoles().size()); // force initialize of roles and it works! 
     return oneByLogin; 
    } 

    @Transactional(readOnly = true)//does not matter 
    public Users testGetUser() { 
     Users oneByLogin = usersRepository.getOne(1L); 
     return oneByLogin; 
    } 

    @Transactional(readOnly = true)//does not matter 
    public Users testFindUser() { 
     Users oneByLogin = usersRepository.findOne(1L); 
     return oneByLogin; 
    } 

そして、私が持っている春のセキュリティUserDetailsS​​ervice:

@Service 
    public class UserDetailsServiceImpl implements UserDetailsService { 

    @Autowired 
    private Services services; 

    @Override 
    public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException { 
     Users user; 
     Users userFetchedViaGet = services.testGetUser(); 
     Users userFetchedViaCustomMethod = services.getUserByLogin(login); 
     Users userFetchedViaFind = services.testFindUser(); 
     Users userFetchedWithRoles = services.getUserByLoginWithRoles(login); 
     try { 
      userFetchedViaGet.getRoles().add(new Role("test")); 
     } catch (Exception e) { 
      e.printStackTrace();//LazyInitializationException: failed to lazily initialize a collection of role: , could not initialize proxy - no Session 
     } 
     try { 
      userFetchedViaCustomMethod.getRoles().add(new Role("test")); 
     } catch (Exception e) { 
      e.printStackTrace();//LazyInitializationException: failed to lazily initialize a collection of role: , could not initialize proxy - no Session 
     } 
     try { 
      userFetchedViaFind.getRoles().add(new Role("test")); //LazyInitializationException: failed to lazily initialize a collection of role: , could not initialize proxy - no Session 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     //some code 
     } 
    } 

と私のコントローラ(すべての方法が機能します!これが機能するためのテスト()メソッドを、しかし - - あなたのファサード上

@RequestMapping(value = "/test", method = RequestMethod.GET) 
    public String test() {  
     Users userFetchedViaGet = services.testGetUser(); 
     Users userFetchedViaCustomMethod = services.getUserByLogin("ADMIN"); 
     Users userFetchedViaFind = services.testFindUser(); 
     Users userFetchedWithRoles = services.getUserByLoginWithRoles("ADMIN"); 
     try { 
      userFetchedViaGet.getRoles().add(new Role("test")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     try { 
      userFetchedViaCustomMethod.getRoles().add(new Role("test")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     try { 
      userFetchedViaFind.getRoles().add(new Role("test")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     //some code 
    } 
+1

あなたはこれを試してみましたか?http://stackoverflow.com/questions/11746499/solve-failed-to-lazily-initialize-a-collection-of-role-exception –

+0

こんにちは!その投稿は私の質問と共通するものはありません。 –

+0

これを解決できますか?私は実際に同じ問題を抱えています –

答えて

0

あなたは全体の事をラップするトランザクションが必要になります。そこにはセッションがなく、遅延が)タイプをフェッチので、しかし、起こるexcpetionする必要がありますこれは本当に良い習慣ではありません。

あなたのサービスはトランザクションでapiメソッドをラップし、完全にロードされたオブジェクトをすべての子ノードとともに返します。このオブジェクトはUsersクラス、 オブジェクトから構築されたハッシュマップ、または残りの呼び出しから戻ってくるような文字列から構築された単純なBeanにすることができます。

+0

こんにちは! Spring DataトランザクションのreadOnly = trueのデフォルトでは、testGetUser()のようなメソッドのラッピングが行われます。そして私はgetUserByLoginWithRolesメソッドでそれを行いました。 "testGetUser"のような同じメソッドがSecurityクラスで動作せず、コントローラで動作するのはなぜですか?コントローラでなぜSpring BootでLazy例外を受け取らないのですか?なぜSpringブートは私の遅延コレクションを初期化したのですか?どのように春のブートそれを行うのですか? –

+0

hi。バネデータメソッドを使用した直後にトランザクションが終了するのは、ユーザーエンティティとロールエンティティの間で遅延フェッチを使用しているため、バネデータメソッドはロールなしでユーザーをフェッチするだけです。より大きいトランザクションコンテキストでラップされている場合は、ユーザーロールグラフをトラバースし、データベースからすべてのロールをフェッチする必要があります。可能であれば、レイジーフェッチを可能な限り簡単に変更することができます。また、単純なhqlクエリーを記述することで、このようにしたくない場合にこの結合をフェッチすることもできます。 –

関連する問題