0 0

使用Spring对Service层进行测试,无法查询到刚刚插入的记录?5

如题,本人使用Spring提供的:AbstractTransactionalDataSourceSpringContextTests类对Service层进行测试。测试的方法是向数据库中插入一条用户记录,然后再重新检索出来。代码如下:

【1】DAO层代码:
public User saveUser(User newUser) {
		getHibernateTemplate().save(newUser);
		//getHibernateTemplate().flush();
		return (User) getHibernateTemplate().get(User.class,
				newUser.getUserId());
	}


【2】Service层代码:
public User saveUser(User newUser) throws NewsletterException {
		try {
			return userDao.saveUser(newUser);
		} catch (HibernateObjectRetrievalFailureException he) {
			throw new ServiceException(systemMessage.getMessage(SERVICE_FAILED)
					+ ": saveUser");
		} catch (Exception e) {
			throw new NewsletterException(e.getMessage());
		}
	}



public User getUserByName(String userName) throws NewsletterException {
		try {
			return userDao.getUserByName(userName);
		} catch (HibernateObjectRetrievalFailureException he) {
			throw new ServiceException(systemMessage.getMessage(SERVICE_FAILED)
					+ ": userName");
		} catch (Exception e) {
			throw new NewsletterException(e.getMessage());
		}
	}


【3】测试代码:
public void testSaveUser() {
		User newUser = createUser();
		try {
			userService.saveUser(newUser);
			assertTrue(true);			
			String sql = "Select USERNAME from NEWSLETTER_USER where UPPER(USERNAME)= ?";
			String userName = (String) jdbcTemplate.queryForObject(sql,
					new Object[] { "PAUL" }, java.lang.String.class);
			assertNotNull(userName);
			assertEquals(userName, newUser.getUserName());			
		} catch (NewsletterException ne) {
			fail(ne.getMessage());
	
}
}


【4】Spring配置文件:
<!-- User Service Definition -->
	<bean id="userServiceTarget"
		class="com.newsletter.service.impl.UserServiceImpl">
		<property name="userDao">
			<ref local="userDao" />
		</property>
		<property name="systemMessage">
			<ref local="systemMessage" />
		</property>
	</bean>

	<!-- Transactional proxy for the User Service -->
	<bean id="userService"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager">
			<ref local="transactionManager" />
		</property>
		<property name="target">
			<ref local="userServiceTarget" />
		</property>
		<property name="transactionAttributes">
			<props>
				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="save*">PROPAGATION_REQUIRED</prop>
				<prop key="update*">PROPAGATION_REQUIRED</prop>
				<prop key="delete*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>


【5】测试问题:

1. 使用上面的测试代码,发现jdbcTemplate.queryForObject方法获取到的结果为空,测试失败。

2. 在testSaveUser方法末尾,即便加上setComplete()方法,发现数据已经插入,但query方法同样返回NULL

3. 假如我使用上面Service层的userService.getUserByName方法进行测试,测试通过

4. 假如我在DAO层的saveUser方法里面加上getHibernateTemplate().flush();测试也通过


请问为什么即便我在测试方法中加上setComplete(),而且数据库中查到了记录,但每次都是返回NULL是什么原因?
问题补充:
谢谢llade,假如我调用了setComplete()方法,Spring确实是提交了事务的,因为我在数据库中已经查询到相应的记录。

我测试过3种情况的setComplete(),第一种是在saveUser调用之后,第二种是在queryForObject之后,第三种是分别在saveUser和queryForObject之后。

但每次都是同样的结果。
2008年6月19日 17:47

3个答案 按时间排序 按投票排序

0 0

采纳的答案

需要将hibernate的session,flush一下

SessionFactoryUtils.getSession(getSessionFactory(), false).flush()

这样你刚才做的操作才会体现在实际的数据库表中。然后通过jdbc就能查到了。

public void testSaveUser() {  
    User newUser = createUser();  
    try {  
    userService.saveUser(newUser);  
    [b]SessionFactoryUtils.getSession(getSessionFactory(), false).flush();[/b]
    assertTrue(true);             
    String sql = "Select USERNAME from NEWSLETTER_USER where UPPER(USERNAME)= ?";  
    String userName = (String) jdbcTemplate.queryForObject(sql,  
        new Object[] { "PAUL" }, java.lang.String.class);  
    assertNotNull(userName);  
    assertEquals(userName, newUser.getUserName());            
    } catch (NewsletterException ne) {  
        fail(ne.getMessage()); 
    }
} 

2008年6月24日 09:41
0 0

那是因为, Hibernate和JDBC不在一个事务内.

所以,
[1] 你把Hibernate的Session Flush后, JDBC就可以查到了.

[2] 你不用JDBC去查,继续使用Hibernate去查询,当然还可以查到.


最近一直在看Hibernate和JDBC的框架整合,就一直遇到同类的问题.

2008年6月20日 18:51
0 0

有意思的问题。在这种情况下还是先看看到底Connection有没有commit吧。
方法是,做一个代理类,看看connecton有没提交。

package llade.test.jdbc

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Map;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MyDataSource extends BasicDataSource {
	Log logger = LogFactory.getLog(MyDataSource.class);
	class ProxyConnection implements Connection{
		
		Connection innnerConnection;
		String uuid;
		
		public ProxyConnection(Connection conn,String uuid){
			this.innnerConnection=conn;
			this.uuid=uuid;
		}

		public void clearWarnings() throws SQLException {
			this.innnerConnection.clearWarnings();
		}

		public void close() throws SQLException {
			this.innnerConnection.close();
		}

		public void commit() throws SQLException {
			//正是我们想要知道是否调用了commit();
                           //如果信不过logger可以用System.out
			logger.debug("connection:"+this.uuid+" commit");
			this.innnerConnection.commit();
		}

		public Statement createStatement() throws SQLException {
			return this.innnerConnection.createStatement();
		}

		public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
			return this.innnerConnection.createStatement(resultSetType, resultSetConcurrency);
		}

		public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
			return this.innnerConnection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
		}

		public boolean getAutoCommit() throws SQLException {
			return this.innnerConnection.getAutoCommit();
		}

		public String getCatalog() throws SQLException {
			return this.innnerConnection.getCatalog();
		}

		public int getHoldability() throws SQLException {
			return this.innnerConnection.getHoldability();
		}

		public DatabaseMetaData getMetaData() throws SQLException {
			return this.innnerConnection.getMetaData();
		}

		public int getTransactionIsolation() throws SQLException {
			return this.innnerConnection.getTransactionIsolation();
		}

		public Map<String, Class<?>> getTypeMap() throws SQLException {
			return this.innnerConnection.getTypeMap();
		}

		public SQLWarning getWarnings() throws SQLException {
			return this.innnerConnection.getWarnings();
		}

		public boolean isClosed() throws SQLException {
			return this.innnerConnection.isClosed();
		}

		public boolean isReadOnly() throws SQLException {
			return this.innnerConnection.isReadOnly();
		}

		public String nativeSQL(String sql) throws SQLException {
			return this.innnerConnection.nativeSQL(sql);
		}

		public CallableStatement prepareCall(String sql) throws SQLException {
			return this.innnerConnection.prepareCall(sql);
		}

		public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
			return this.innnerConnection.prepareCall(sql, resultSetType, resultSetConcurrency);
		}

		public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
			return this.innnerConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
		}

		public PreparedStatement prepareStatement(String sql) throws SQLException {
			return this.innnerConnection.prepareStatement(sql);
		}

		public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
			return this.innnerConnection.prepareStatement(sql, autoGeneratedKeys);
		}

		public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
			return this.innnerConnection.prepareStatement(sql, columnIndexes);
		}

		public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
			return this.innnerConnection.prepareStatement(sql, columnNames);
		}

		public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
			return this.innnerConnection.prepareStatement(sql, resultSetType, resultSetConcurrency);
		}

		public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
			return this.innnerConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
		}

		public void releaseSavepoint(Savepoint savepoint) throws SQLException {
			this.innnerConnection.releaseSavepoint(savepoint);
		}

		public void rollback() throws SQLException {
			this.innnerConnection.rollback();
		}

		public void rollback(Savepoint savepoint) throws SQLException {
			this.innnerConnection.rollback(savepoint);
		}

		public void setAutoCommit(boolean autoCommit) throws SQLException {
			this.innnerConnection.setAutoCommit(autoCommit);
		}

		public void setCatalog(String catalog) throws SQLException {
			this.innnerConnection.setCatalog(catalog);
		}

		public void setHoldability(int holdability) throws SQLException {
			this.innnerConnection.setHoldability(holdability);
		}

		public void setReadOnly(boolean readOnly) throws SQLException {
			this.innnerConnection.setReadOnly(readOnly);
		}

		public Savepoint setSavepoint() throws SQLException {
			return this.innnerConnection.setSavepoint();
		}

		public Savepoint setSavepoint(String name) throws SQLException {
			return this.innnerConnection.setSavepoint(name);
		}

		public void setTransactionIsolation(int level) throws SQLException {
			this.innnerConnection.setTransactionIsolation(level);
		}

		public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
			this.innnerConnection.setTypeMap(map);
		}
		
	}

	@Override
	public Connection getConnection() throws SQLException {
		
		Connection conn=super.getConnection();
		 return new ProxyConnection(conn,java.util.UUID.randomUUID().toString());
	}

	@Override
	public Connection getConnection(String user, String password) throws SQLException {
		Connection conn=super.getConnection(user,password);
		if(conn instanceof ProxyConnection)return conn;
		return new ProxyConnection(conn,java.util.UUID.randomUUID().toString());
	}
	
	

}


2008年6月19日 23:20

相关推荐

    spring+hibernate整合实现简单数据库添加记录

    本文将深入探讨如何将Spring与Hibernate整合,以实现对数据库的简单添加记录功能,这对于初学者来说是一次宝贵的学习机会。 首先,我们需要理解Spring的核心概念。Spring提供了一个依赖注入(DI)容器,它负责管理...

    jsp、servlet进行增删改查,dao层和service层分开

    3. **DAO(Data Access Object)层**:DAO层是数据库操作的抽象层,它封装了对数据库的所有访问,包括查询、插入、更新和删除等操作。在这个项目中,使用原生的JDBC(Java Database Connectivity)编程,意味着没有...

    使用Unitils测试DAO

    测试DAO的主要目标是验证它们是否正确地执行了数据库操作,如插入、更新、删除和查询记录。 3. **使用Unitils进行数据库测试**: - **数据库准备**:Unitils支持DBUnit,可以自动加载或清理数据库状态,使得每个...

    Spring-Mybatis整合

    可以使用 Spring 自带的 Test 框架进行单元测试,或者利用Mockito等工具对Service层进行隔离测试。 7. **优势**: SSM 整合带来的优势在于松耦合、高可扩展性和易于测试。Spring 提供的 DI 和 AOP 能够让代码更...

    SSM(spring+SpringMVC+Mybatis)框架实现增删改查

    7. **测试**:在完成SSM框架的增删改查功能后,通常会编写JUnit测试用例,对Service层进行单元测试,确保每个操作都能正常工作。 通过以上详细说明,我们可以看到SSM框架如何协同工作,为Web应用程序提供强大的数据...

    使用jsp-servlet-service-dao四层结构完成用户信息的增删改查操作

    本文将深入探讨如何使用jsp-servlet-service-dao四层架构来实现这样的系统,包括用户信息的增删改查功能,以及权限控制机制。 首先,让我们理解这四层架构的每一层: 1. **JSP(JavaServer Pages)**:JSP是Java ...

    Spring Aop使用实例

    **Spring AOP 使用实例** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个重要组成部分,它提供了一种在不修改原有代码的情况下,通过代理方式添加额外功能的技术。这种技术使得我们...

    Spring系列面试题129道(附答案解析)

    - 支持测试:Spring对单元测试和集成测试都有良好的支持,特别是通过依赖注入简化了测试。 4、SpringFramework有哪些不同的功能? Spring框架的主要功能包括但不限于: - Spring Core Container:包含了Spring框架...

    spring从入门到精通

    《Spring从入门到精通》是一本全面覆盖Spring框架核心概念和技术的指南,旨在帮助读者从零基础开始,逐步掌握Spring的使用和应用开发。Spring作为Java企业级应用开发的主流框架,其强大的功能和灵活性使其在众多框架...

    Spring+Spring MVC+Spring JDBC+MySql实现简单登录注册

    在本项目中,我们主要利用Spring框架,包括其核心模块Spring、MVC模块Spring MVC以及数据访问/集成模块Spring JDBC,结合MySQL数据库来构建一个基础的登录注册系统。以下是这个项目涉及的关键技术点: 1. **Spring...

    springmvc+mysql增删改查【时间段条件查询】

    - **创建(Create)**:通过Service层调用DAO的insert方法,插入新记录到数据库。 - **读取(Read)**:使用SELECT语句获取数据,可以是单个记录或多个记录。支持分页和条件查询。 - **更新(Update)**:根据主键或...

    Spring基础:Spring AOP简单使用

    - **JDK动态代理**:当目标对象实现了至少一个接口时,Spring会使用Java的Proxy类创建一个代理对象,该代理对象在运行时动态生成,并在调用实际方法前/后插入通知代码。 - **CGLIB代理**:如果目标对象没有实现...

    spring-boot aop

    Spring Boot AOP(面向切面编程)是一种强大的设计模式,它允许我们在不修改现有代码的情况下,插入额外的功能或监控代码。在Spring框架中,AOP主要用于日志记录、事务管理、性能统计等场景。本示例是关于如何在...

    Spring与Hibernate整合实例(博客用户登录增删改查)

    4. **修改**:用户信息修改涉及到更新数据库记录,Service层处理用户提交的更新请求,更新相应的数据库记录。 5. **删除**:删除用户通常需谨慎处理,防止误操作。Service层会先验证权限,然后调用DAO删除指定用户。...

    Spring AOP完整例子

    在本教程中,我们将深入探讨Spring AOP的不同使用方法,包括定义切点、通知类型、组装切面以及使用JUnit4进行测试。 首先,我们需要理解Spring AOP的基础概念。AOP的核心是切点(Pointcut),它定义了关注点在何处...

    SSH(Struts+Spring+Hibernate)结合项目简单实例

    2. **拦截器**:Struts 2的拦截器可以插入到Action调用之前和之后,进行如日志记录、权限验证等预处理或后处理操作。 3. **配置文件**:通常使用struts.xml文件来定义Action、结果类型和拦截器配置。 **Spring** ...

    Spring基本架包

    8. **spring-aop-4.3.18.RELEASE.jar**:面向切面编程(AOP)模块允许开发者定义“切面”,这些切面可以插入到多个对象的方法调用中,实现如日志记录、性能监控、事务管理等功能,提高代码的可维护性和复用性。...

    基于Spring+Spring MVC+Mybatis的用户账号注册和密码修改.zip

    - 如果验证通过,Service层将用户信息封装成对象,使用Mybatis的SQL映射插入到用户表中。 - 注册成功后,发送确认邮件或短信,通过链接完成邮箱或手机验证,提高账户安全性。 **5. 密码修改流程** - 用户提交修改...

    springmvc+hibernate+spring学生表增删改查

    - **Bean管理**:在Spring的配置文件中声明Controller、DAO和Service等组件,使用@Autowired进行依赖注入。 - **事务配置**:使用@Transactional注解在Service层方法上,开启事务管理。 - **AOP**:可以利用...

    MyBatis+Spring整合示例

    最后,通过Spring的依赖注入,我们可以在Service层或其他业务逻辑组件中注入`UserMapper`,直接调用其方法进行数据操作,无需关心SqlSession的生命周期管理。 总的来说,MyBatis与Spring的整合简化了数据访问层的...

Global site tag (gtag.js) - Google Analytics