2015-09-09 100 views
1

自從我從存儲庫方法上的@QueryHints轉換爲@Cacheable後,我遇到了問題。@Cacheable殺死Hibernate會話?

我有一個控制器方法註釋春季@Transactional,它調用一個服務方法(未註釋)。 該服務首先獲得一個具有repository.getByLogin(login)的實體用戶,然後在parent.getChildren()上循環。

隨着@CacheablegetByLogin(login),我有一個org.hibernate.LazyInitializationException試圖做parent.getChildren()

控制器時(包含@Transactional這是一個不好的做法):

@Controller 
@RequestMapping(value="/users") 
public class UserController { 

    @Autowired 
    UserService userService;  

    @Transactional 
    @RequestMapping(value="/add-son", method=POST) 
    public void addSon(@RequestBody User son) { 
     userService.addSon(son); 
    } 
} 

服務:

@Service 
public class UserService { 

    @Autowired 
    UserRepo repository; 

    public void addSon(User son) { 
     User parent = repository.getByLogin(user.getParent()); // call to my repo 
     for(User child: parent.getChildren()) { // breaks here 
      System.out.println(child) 
     } 
     parent.addChild(son); 
    } 
} 

我的舊版本庫(worke d):

public interface UserRepo extends JpaRepository<User, Integer> { 
    @QueryHints({@QueryHint(name = COMMENT, value = "get user by login"), 
       @QueryHint(name = CACHEABLE, value = "true")}) 
    User findByLogin(String login); 
} 

我的新庫(似乎殺了我的Hibernate的Session):

public interface UserRepo extends JpaRepository<User, Integer> { 
    @Cacheable(value = "myapp.entities.User", cacheManager = "springCacheManager", unless="#result == null") 
    User findByLogin(String login); 
} 

堆棧跟蹤:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: myapp.entities.User.children, could not initialize proxy - no Session 
     at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566) 
     at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186) 
     at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545) 
     at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:124) 
     at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:266) 
     at myapp.services.UserService.addSon(UserService.java:19) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:497) 
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) 
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:201) 
     at com.sun.proxy.$Proxy194.addSon(Unknown Source) 
     at myapp.controllers.UserController.addSon(UserController.java:20) 
     at myapp.controllers.UserController$$FastClassBySpringCGLIB$$7053b110.invoke(<generated>) 
     at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
     at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
     at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) 
     at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) 
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
     at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) 
     at myapp.controllers.UserController$$EnhancerBySpringCGLIB$$66ec522b.addSon(<generated>) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
+0

當您退出某個事務並嘗試使用該代理執行CRUD時,會引發LazyInitializedException。因此我認爲spring沒有配置爲@Transactional搜索控制器。還要確保你已經啓用了緩存:。順便說一下:「我有一個控制器註釋@Transactional」..不要這樣做!糟糕的建築。 –

+0

這是一個糟糕的項目框架,確實如此:) 但是它與我的倉庫中的@ QueryHints協同工作,所以事務在服務中很好地傳播(@Service bean)。 – Pleymor

+0

那麼'@ Cacheable'和'@ QueryHints'(用於緩存查詢結果!)是完全不同的野獸,並且服務於不同的目的。您不能簡單地將hibernate託管對象放入緩存中,因爲這也會將其放入緩存中。在休眠級別集成第二級緩存或找出將對象重新連接到會話的方法(這可能很危險,因爲基本上可能會遇到共享單個實例的問題,並且存在多個會話!)> –

回答

1

當您使用@Cacheable爲實體的實體加入到沒有延遲收集的緩存被抓取。當您訪問它時會加載惰性集合,但是在那段時間內會話可能會結束,並且無法加載惰性集合。 我會使用服務類來調用存儲庫,並將實體轉換爲轉換對象(加載延遲集合)。 然後您將使用轉換對象,因此您可以註釋服務方法@Cacheable。