spring 尽管我使用的是 @Transactional 注释,但仍然“无法初始化代理 - 没有会话”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16109170/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 05:53:19  来源:igfitidea点击:

Getting "could not initialize proxy - no Session" despite the fact I'm using a @Transactional annotation

springhibernatetransactionslazy-initialization

提问by Dave

I'm using Spring 3.1.1.RELEASE and Hibernate 4.1.0.Final. I'm getting a "could not initialize proxy - no Session" exception, despite the fact I'm wrapping the relevant method call in a @Transactional annotation. Here's my method …

我正在使用 Spring 3.1.1.RELEASE 和 Hibernate 4.1.0.Final。我收到“无法初始化代理 - 没有会话”异常,尽管我将相关方法调用包装在 @Transactional 注释中。这是我的方法……

@Service("teacherImportService")
public class TeacherImportServiceImpl extends AbstractmyprojectService 
{
    …
    @Transactional
    @Override
    public void saveUserObject(final JsonObject jsonData)  
    {
        …
        final myprojectOrganization myprojectOrg = myprojectOrgDao.findBymyprojectOrgId(myprojectSchoolId);
        final Organization school = myprojectOrg != null ? myprojectOrg.getOrg() : null;
            …
        final Address address = new Address();
        address.setState(school.getState());    // error occurs here

What else do I have to do to guarantee a transaction takes place? I have included the "<tx:annotation-driven />" in my application context, which I include below

我还需要做什么来保证交易发生?我在我的应用程序上下文中包含了“<tx:annotation-driven />”,我将其包含在下面

<context:component-scan base-package="org.mainco.subco" />
...
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${test.mysql.dataSource.driverClassName}" />
    <property name="url" value="${test.mysql.dataSource.url}" />
    <property name="username" value="${test.mysql.db.user}" />
    <property name="password" value="${test.mysql.db.password}" />
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="packagesToScan" value="org.mainco.subco" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaPropertyMap" ref="jpaPropertyMap" />
</bean>

<util:map id="jpaPropertyMap">
    <entry key="hibernate.show_sql" value="true" />
    <entry key="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> 
    <entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
    <entry key="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/>
    <entry key="hibernate.cache.use_second_level_cache" value="true" />
    <entry key="hibernate.cache.use_query_cache" value="false" />
    <entry key="hibernate.generate_statistics" value="true" />
</util:map>

<bean id="sharedEntityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
   <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven />

<jdbc:initialize-database data-source="dataSource">
    <jdbc:script location="classpath:truncate_tables.sql" />
    <jdbc:script location="classpath:db-test-data.sql" />
</jdbc:initialize-database>

Here is full stack trace of the exception ...

这是异常的完整堆栈跟踪...

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:149)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:195)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
    at org.mainco.subco.organization.domain.Organization_$$_javassist_30.getState(Organization_$$_javassist_30.java)
    at org.mainco.subco.myproject.service.TeacherImportServiceImpl.saveUserObject(TeacherImportServiceImpl.java:101)
    at org.mainco.subco.myproject.service.AbstractmyprojectService.saveUsers(AbstractmyprojectService.java:226)
    at org.mainco.subco.myproject.service.AbstractmyprojectService$$FastClassByCGLIB$$d080e416.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:618)
    at org.mainco.subco.myproject.service.TeacherImportServiceImpl$$EnhancerByCGLIB$$a06c7e9f.saveUsers(<generated>)
    at org.mainco.subco.myproject.service.TeacherImportServiceTest.testSaveTeachers(TeacherImportServiceTest.java:46)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access
 TeacherImportServiceTest.testSaveTeachers() -> 
 AbstractmyprojectService.saveUsers() -> 
 TeacherImportServiceImpl.saveUserObject()
0(ParentRunner.java:42) at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:184) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

采纳答案by Jose Luis Martin

Maybe you forgot to add the transactional annotation to AbstractmyprojectService.saveUsers()

也许你忘记添加事务注释 AbstractmyprojectService.saveUsers()

Note that inner calls are never proxied, so the flow:

请注意,内部调用永远不会被代理,因此流程:

public void saveUserObject() {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = txManager.getTransaction(def);
        try {
          // the code
        }
        catch (Exception ex) {
          txManager.rollback(status);
          throw ex;
        }
        txManager.commit(status);
    }

Will not be transactional if AbstractmyprojectService.saveUsers()is not transactional at all.

如果AbstractmyprojectService.saveUsers()根本不是事务性的,则不会是事务性的。

EDIT

编辑

After reading your comments, I see three options to solve it:

阅读您的评论后,我看到了三个解决方案:

  • Extract the saveUsers()method to a helper class.
  • saveUsers()方法提取到辅助类

Really simple, refactor your code to keep the Tx methods in one class and use it from another one via composition.

真的很简单,重构您的代码以将 Tx 方法保留在一个类中,并通过组合从另一个类中使用它。

  • Use programmatic transactions in saveUserObject().
  • saveUserObject().

for example, inject the txManager and

例如,注入 txManager 和

<context:component-scan base-package="some.package.where.stereotypedclassesexist"/>
  • Use AspectJ instead Spring AOP.(I think that this option is too complex only for this issue.)
  • 使用 AspectJ 代替 Spring AOP。(我认为这个选项只针对这个问题太复杂了。)

Using AspectJ you replace AOP Proxies wiht the Aspect AnnotationTransactionAspect

使用 AspectJ,您可以用 Aspect 替换 AOP 代理 AnnotationTransactionAspect

use <tx:annotation-driven mode="aspectj"/>and choose a weaving method (compile or load time).

使用<tx:annotation-driven mode="aspectj"/>并选择一种编织方法(编译或加载时间)。

for load time weaving, see http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/aop.html#aop-aj-ltw

有关加载时间编织,请参阅http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/aop.html#aop-aj-ltw

for compile time weaving with maven, see Spring / @Transactional with AspectJ is totally ignored

对于使用 maven 进行编译时编织,请参阅Spring / @Transactional with AspectJ 完全被忽略

回答by maggu

In your application context XML, I don't see the component scan configuration which would let Spring to manage the stereo type annotated bean classes [i.e., Classes annotated with either @Service, @Repositoryor @Component]

在您的应用程序上下文 XML 中,我没有看到让 Spring 管理立体类型注释的 bean 类的组件扫描配置 [即,用@Service@Repository@Component注释的]

Just add the package scan for any of such classes as in below example:

只需为任何此类添加包扫描,如下例所示:

public class TeacherImportServiceImpl extends AbstractmyprojectService implements SomeInterface {

    @Transactional
    @Override
    public void saveUserObject(final JsonObject jsonData)  {
        ...
    }

}

public interface SomeInterface {
   void saveUserObject(JsonObject jsonData);
}

Regarding classpath scanning for spring managed components, Spring Documentation Reference here.

关于 Spring 管理组件的类路径扫描,Spring 文档参考这里

HTH.

哈。

回答by Szymon Jednac

This may be related to the proxy implementation pattern. Try extracting saveUserObjectto an interface:

这可能与代理实现模式有关。尝试提取saveUserObject到接口:

<tx:annotation-driven proxy-target-class="true" />

You may also try class-based proxing using CGLIB:

您也可以使用 CGLIB 尝试基于类的代理:

##代码##