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
Getting "could not initialize proxy - no Session" despite the fact I'm using a @Transactional annotation
提问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 尝试基于类的代理:
##代码##
