Spring测试对服务事务的影响

Spring测试对服务事务的影响,spring,testing,transactions,Spring,Testing,Transactions,我在JUnit测试中使用@Transactional(主要优点是在一个测试中回滚更改),但我有一个小问题,这会影响我的服务事务。例如,这是 我的服务: @Service @Transactional(propagation = Propagation.REQUIRED) public class ServiceImpl 我的单元测试: @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "/te

我在JUnit测试中使用@Transactional(主要优点是在一个测试中回滚更改),但我有一个小问题,这会影响我的服务事务。例如,这是

我的服务:

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class ServiceImpl
我的单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
@Transactional
public class TestService 

@Test
public void testNumberTransaction() {
Entity a = new Entity();
Entity b = new Entity();
service.add(a);
service.add(b);
}
我天真地希望service.add()有两个单独的事务,但除非在测试方法上使用@nontransactional,否则它将在一个事务中运行(但测试后它不会回滚)

这是预期的吗?我可以用一些配置来更改它吗


谢谢

是的,这是意料之中的事<代码>传播。必需的(默认值)表示:在现有事务中执行(如果存在)。否则,创建一个事务并在方法末尾提交它

因此,是的,如果整个测试方法是事务性的,那么两个服务调用都将在测试事务的上下文中执行

请注意,由于该服务是用
REQUIRED
注释的,因此如果事务已经存在,它应该可以工作。这使得测试有效:它在现有事务的上下文中测试您的服务。如果您希望服务在其自己的专用事务中执行,则应使用
REQUIRES\u NEW
对其进行注释。但当然,如果是这种情况,您将无法通过在事务中执行测试来回滚服务事务。

默认情况下(
要求
是默认的传播行为),如果事务已经存在,您的服务方法将不会创建新的事务,而是加入现有的事务。在您的例子中,它是由Spring测试框架(将回滚的框架)创建的事务


您可以通过将传播设置为
REQUIRES\u NEW
来更改此行为。但是,因为现在业务
add
方法在新事务中运行,所以一旦离开此方法,事务将被提交而不是回滚。默认情况下,由于所有事务都加入到JUnit测试事务中,因此对数据库所做的所有更改都会回滚。

。注释该类与注释该类的每个公共方法是等价的,划分界线仍然是该方法(在您的示例中,是
testNumberTransaction()
)。提交/回滚决策将在分界点进行,即从测试方法返回时。无论是指定
REQUIRES
还是
REQUIRES\u NEW
传播,实际的事务单位都是相同的,
testNumberTransaction()
方法,因此两个
服务.add(…)
调用将始终在同一事务中执行

如果您的目标是在测试后总是回滚事务,那么只需删除
@Transactional
注释(或者像您提到的那样放置@nontransactional)就可以了


另一方面,如果要为每个
服务.add(…)
调用强制一个新事务,可以为服务类创建一个包装器,其中有一个
add(…)
方法,该方法用@Transactional(propagation=propagation.REQUIRES\u new)注释然后从那里调用wrapped
service
instance
add(…)
方法。或者,您可以在spring测试上下文中添加一些声明性事务管理,为
服务添加事务建议。add(…)
方法。阅读中有关如何使用
标记添加声明性事务支持的详细信息。

从测试方法中删除@Transactional不会回滚事务:测试中不会有任何事务。事务将在调用服务方法时启动,并在服务方法返回时提交。对我来说,这是一个真实而笨拙的公式。删除@Transactional注释将阻止事务管理器在java层中创建事务。然而,大多数数据库总是为每个会话创建一个隐式事务,如果您将autocommit设置为off(默认为IIRC),则没有任何事务的行为方式与总是回滚的事务相同。如果我错了,请纠正我。错误,否。从测试方法中删除事务将使测试在任何事务上下文之外运行,但Spring仍将为每个服务方法调用启动一个事务,因为服务方法使用事务性注释。因此,服务完成的实际事务工作(可能会更新某些数据库)将在事务中完成并提交,除非服务本身引发运行时异常。我的观点是,很多(如果不是大多数的话)数据库总是会为您执行的每个SQL命令创建一个事务,因此始终会有一个事务上下文在起作用。您可以选择不让Spring拾取该事务上下文(即,不注释@transactional),但它仍然存在。如果您将“自动提交”设置为“false”,它将永远不会提交,您的更新也永远不会被反映。或者,您可以将自动提交设置为“true”,在这种情况下,您的更新将始终提交。该服务使用事务性注释。它写在OP的问题里。