文档章节

TransactionalTestExecutionListener使用报异常

liuhuics10
 liuhuics10
发布于 2015/12/09 13:40
字数 680
阅读 1.2K
收藏 0

行业解决方案、产品招募中!想赚钱就来传!>>>

使用spring自带框架测试,代码如下:

package TestContext;

import java.util.List;

import javax.annotation.Resource;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;

import entity.User;
import service.UserService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:beans.xml")
@TestExecutionListeners(TransactionalTestExecutionListener.class)
@Transactional
public class ListActionTest extends AbstractTransactionalJUnit4SpringContextTests{
	
	
	private UserService userService;
	

	public UserService getUserService() {
		return userService;
	}

	@Resource
	public void setUserService(UserService userService) {
		this.userService = userService;
	}


	//	@Rollback(false)默认true 
	@Test
	public void test(){
		/*User user = userService.getUser(50);
		System.out.println(user.getUname());
		
		List<User> users = userService.getUsers();
		System.out.println(users.size());*/
		
		User user2 = new User();
		user2.setUname("b");
		user2.setPwd("b");
		userService.add(user2);
		
	}
	
}

运行时报错:

警告: Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@15975490] to process 'before' execution of test method [public void TestContext.ListActionTest.test()] for test instance [TestContext.ListActionTest@40dd3977]
java.lang.IllegalStateException: Cannot start a new transaction without ending the existing transaction.
	at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:169)
	at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:265)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

注释掉下面一行注解

//@TestExecutionListeners(TransactionalTestExecutionListener.class)

运行成功。

ListActionTest的父类AbstractTransactionalJUnit4SpringContextTests已经使用的注解

@TestExecutionListeners({TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class})

AbstractTransactionalJUnit4SpringContextTests的父类AbstractJUnit4SpringContextTests又使用了注解

@TestExecutionListeners({ ServletTestExecutionListener.class, DirtiesContextBeforeModesTestExecutionListener.class,
	DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class })

所以这6个注解都会自动继承,不需要添加。

而至于为什么一添加

TransactionalTestExecutionListener.class

就报异常,我查了下:

http://stackoverflow.com/questions/19537775/transaction-with-transactional-and-transactionaltestexecutionlistener-what-is-th

一人回答的是:

TransactionalTestExecutionListener is the only guy who creates transactions. It checks @Transactional annotation presence and then opens transaction. In case on test execution listeners are specified spring uses some default test execution listeners one of which is TransactionalTestExecutionListener, that is why it seems that listener and annotation works separately.

他提到TransactionalTestExecutionListener 检测到@Transactional会开启一个transaction。后半段我根据自己理解断了下句如下:

 In case of test execution,  listeners are specified spring, uses some default test execution listeners, one of which is TransactionalTestExecutionListener, that is why it seems that listener and annotation works separately.

简单翻译下就是:当你执行测试时,如果指定了使用spring的监听器,那么会使用一些默认的监听器,而这些默认监听器中的其中一个便是TransactionalTestExecutionListener,这也就是为什么监听器和注解会分开使用的原因。


但是以上解释还是听得云里雾里的,所以我自己总结如下:

加上TransactionalTestExecutionListener 时就报异常java.lang.IllegalStateException: Cannot start a new transaction without ending the existing transaction.。原因是:

我们继承AbstractTransactionalJUnit4SpringContextTests时,已经继承了注解TransactionalTestExecutionListener ,这时再重复使用此注解,即是在原来已经开了一个transaction的基础上又重复开了个transaction.所以会报这个异常。

这一原因只是我个人的猜想,有看到此博客的兄弟,如有更好的解释和evidence,还望不吝赐教。多谢!

liuhuics10
粉丝 4
博文 97
码字总数 39010
作品 0
烟台
私信 提问
加载中
请先登录后再评论。
访问安全控制解决方案

本文是《轻量级 Java Web 框架架构设计》的系列博文。 今天想和大家简单的分享一下,在 Smart 中是如何做到访问安全控制的。也就是说,当没有登录或 Session 过期时所做的操作,会自动退回到...

黄勇
2013/11/03
3.4K
6
CDH5: 使用parcels配置lzo

一、Parcel 部署步骤 1 下载: 首先需要下载 Parcel。下载完成后,Parcel 将驻留在 Cloudera Manager 主机的本地目录中。 2 分配: Parcel 下载后,将分配到群集中的所有主机上并解压缩。 3 激...

cloud-coder
2014/07/01
6.8K
1
使用IBPP在C++中操作FireBird/Interbase数据库

FireBird是一种小巧的关系型数据库,它有多种版本,包括服务器版(象MySQL),单机版(象Access)以及嵌入式(象SQLite)。而且不管是服务器版还是嵌入式版它都完整支持视图、触发器、存储过程等...

Waiting4you
2009/07/26
3.8K
2
Pulse 安装失败

刚刚下载 安装!!按照instanlling.txt指示做 build.xml 生成一个war包 放到tomcat下运行结果就是报异常失败

jiguansheng
2010/04/12
732
2
使用CImg处理三维图像

http://www.cppprog.com/2009/0429/110.html

Waiting4you
2009/05/05
1.6K
0

没有更多内容

加载失败,请刷新页面

加载更多

用flutter_staggered_grid_view实现分页瀑布流效果【flutter20个实例之四】

一、老套路,先看样式 二、讲解 1.前言的话 GridView是一个可滚动的,2D数组控件可以用这个组件实现滚动效果,但是它渲染的高度是一样的。 如果要实现不同高度的滚动瀑布流,就要使用这个插件...

一代码农码一代
1分钟前
0
0
C语言中结构体直接赋值?

在C语言中结构体变量之间可以进行赋值操作吗? 简单结构体的赋值 先说结论:一般来说,C语言中的结构体变量可以用另一个变量对其进行赋值或初始化。简单结构体(不包含指针成员)直接赋值没有...

高奕
6分钟前
0
0
python表白神器你值得拥有

上一期云舔狗的效果好像反响不错,大家纷纷摆脱双手的束缚python云舔狗自动给微信好友发送早安晚安和播报天气预报,然后纷纷获得她(们)的芳心,就此一行君建议大家应该乘胜追击,吹响最后的号...

行哥玩Python
05/11
0
0
在SQL表中查找重复值 - Finding duplicate values in a SQL table

问题: It's easy to find duplicates with one field: 使用一个字段很容易找到duplicates : SELECT name, COUNT(email) FROM usersGROUP BY emailHAVING COUNT(email) > 1 So if we h......

fyin1314
13分钟前
0
0
Rust和为n的连续正数序列

题目:输入一个正数n,输出所有和为n 连续正数序列。 例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3 个连续序列1-5、4-6 和7-8。 fn main() { sum_is_n_continuous(15isize); ...

捍卫机密
21分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部