2

我尝试在我的 Spring (v 3.1) Web 应用程序中使用一些在 scala 中编程的 bean,并且在事务方面遇到了奇怪的问题。

我在 Roo 中设置了一个小而完整的 Spring 应用程序来显示我的问题。老实说,我不知道为什么它不起作用......

project --topLevelPackage com.app
jpa setup --provider ECLIPSELINK --database DERBY_EMBEDDED
entity jpa --class com.app.MyEntity
field string --fieldName title

然后我在java中创建了接口

package com.app;
public interface IScalaMainClass {
 void doSomething();
}

package com.app;
public interface IScala1 {
 void someMethod();
}

package com.app;
public interface IScala2 {
 void someMethod();
}

这些实现是在 Scala 中创建的,其中 Scala1 持久化 MyEntity 并且 Scala2 进行 DELETE 查询:

package com.app

import org.springframework.transaction.annotation.Transactional
import org.springframework.stereotype.Repository
import org.springframework.beans.factory.annotation.Autowired

@Repository class ScalaMainClass extends com.app.IScalaMainClass {
 @Autowired var bean1: IScala1 = null
 @Autowired var bean2: IScala2 = null

 @Transactional def doSomething() = {
  bean1.someMethod()
  bean2.someMethod()
 }
}


package com.app

import org.springframework.stereotype.Repository
import javax.persistence.{EntityManager, PersistenceContext}

@Repository class Scala1 extends com.app.IScala1 {
 @PersistenceContext var em: EntityManager = null

 def someMethod = {
  val e = new MyEntity
  em persist e
 }
}


package com.app

import org.springframework.transaction.annotation.Transactional
import org.springframework.stereotype.Repository
import javax.persistence.{EntityManager, PersistenceContext}

@Repository class Scala2 extends com.app.IScala2 {
 @PersistenceContext var em: EntityManager = null

 @Transactional def someMethod = {
  val q = em createQuery "DELETE FROM MyEntity"
  q executeUpdate
 }

}

最后创建执行 IScalaMainClass 的 Java 测试:

import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.annotation.Rollback;
import org.springframework.beans.factory.annotation.Autowired;

import org.junit.runner.RunWith;
import org.junit.Test;
import org.junit.Assert;

import com.app.IScalaMainClass;

@ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration(defaultRollback = false)
public class AppTest {
 @Autowired private IScalaMainClass smc;

 @Test public void testIt() {
  smc.doSomething();
 }
}

如果您现在将 scala 依赖项添加到 pom.xml 并执行“mvn test”,您将收到

javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active
...
4

2 回答 2

2

当您查看 Spring 对 Transaction 和其他面向方面的特性的支持时,您需要非常小心。

  • 无法自动装配不可变字段:自动装配是在初始化后建立依赖关系的模式,val 是在初始化后无法更改的不可变属性

  • 正如您在文档中看到的那样,Spring AOP 支持不是基于字节码编织,而是纯粹用 Java 实现的: http: //static.springsource.org/spring/docs/3.0.x/reference/aop.html

这意味着只有通过 Spring IoC 创建的 bean 才能受益于 Spring AOP 支持。

如果您查看本章的介绍,您可以阅读:

AOP 在 Spring 框架中用于...

... 提供声明性企业服务,尤其是作为 EJB 声明性服务的替代品。最重要的此类服务是声明式事务管理。

因此,如果您的 bean 不是通过 Spring 创建的,那么您将无法获得 Spring 事务支持。

于 2012-07-10T12:22:43.433 回答
1

虽然我主要同意@Edmondo1984 的回答,但我认为上面的 Rainerh 代码已将所有 bean 放在 Spring 上下文中,因此它可以与 Spring Transaction 一起使用。

从上面的代码,我认为你应该改变测试如下

@ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml")
public class AppTest extends AbstractTransactionalJUnit4SpringContextTests {
 @Autowired private IScalaMainClass smc;

 @Test public void testIt() {
  smc.doSomething();
 }
}

不要忘记导入org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests

于 2014-01-15T07:50:02.040 回答