2013-01-13 106 views
1

我正面临一个奇怪的问题。我目前正在编写基于Spring-MVC 3.2和Hibernate 4.1.9的Web应用程序。我用TestNG单元测试编写了一个示例控制器,除编辑外,一切都很好。我可以看到,当保存一个新对象时,它就像一个魅力,但如果我尝试编辑一个现有的对象,它不会保存没有任何理由(我调用相同的方法添加和更新) 。休眠不保存编辑的实体,同时保存新的实体

添加型应用

14:26:36.636 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/app/add.json] 
14:26:36.637 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /app/add.json 
14:26:36.650 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.Long com.wstars.kinzhunt.platform.apps.web.AppController.createApp(com.wstars.kinzhunt.platform.model.apps.Application)] 
14:26:36.651 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appController' 
14:26:36.821 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class com.wstars.kinzhunt.platform.model.apps.Application] as "application/json" using [org.springf[email protected]5dc6bb75] 
14:26:36.890 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session 
14:26:36.890 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580799968 
14:26:36.892 [main] DEBUG c.w.c.dao.hibernate.BaseDaoHibernate - Saving or Updating Object: [email protected][id=<null>,name=KinzHunt,compan[email protected][id=1,name=KinzHunt],callbackUrl=http://www.kinzhunt.com/callback/,website=http://www.kinzhunt.com,[email protected],logoUrl=<null>] 
14:26:36.892 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session 
14:26:36.893 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580799968 
14:26:36.893 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session 
14:26:36.894 [main] DEBUG o.h.e.def.AbstractSaveEventListener - executing identity-insert immediately 
14:26:36.898 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 
14:26:36.899 [main] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection 
14:26:36.899 [main] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:h2:mem:platform_test;DB_CLOSE_DELAY=-1] 
14:26:36.901 [main] DEBUG org.hibernate.SQL - /* insert com.wstars.kinzhunt.platform.model.apps.Application */ insert into applications (id, callback_url, company_id, logo_url, name, sender_email, website) values (null, ?, ?, ?, ?, ?, ?) 
14:26:36.904 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 2 
14:26:36.904 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1) 
14:26:36.905 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session 
14:26:36.905 [main] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)] 
14:26:36.905 [main] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources! 
14:26:36.926 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [2] as "application/json;charset=UTF-8" using [org.springf[email protected]5dc6bb75] 
14:26:36.927 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling 
14:26:36.928 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request 

的新对象虽然日志保存编辑后的目标是

14:27:03.398 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/app/1/edit.json] 
14:27:03.398 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /app/1/edit.json 
14:27:03.401 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.Long com.wstars.kinzhunt.platform.apps.web.AppController.editApp(com.wstars.kinzhunt.platform.model.apps.Application,java.lang.Long)] 
14:27:03.401 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appController' 
14:27:03.404 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class com.wstars.kinzhunt.platform.model.apps.Application] as "application/json" using [org.springf[email protected]5dc6bb75] 
14:27:03.409 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session 
14:27:03.410 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580800234 
14:27:03.411 [main] DEBUG c.w.c.dao.hibernate.BaseDaoHibernate - Saving or Updating Object: [email protected][id=1,name=KinzHunt,[email protected][id=1,name=KinzHunt],callbackUrl=http://www.kinzhunt.com/callback/,website=http://www.wstars.com/KinzHunt/,[email protected],logoUrl=<null>] 
14:27:03.412 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session 
14:27:03.412 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580800234 
14:27:03.413 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session 
14:27:03.422 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session 
14:27:03.424 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [1] as "application/json;charset=UTF-8" using [org.springf[email protected]5dc6bb75] 
14:27:03.424 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling 
14:27:03.425 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request 

正如你所看到的,在第二日志的记录,没有准备好的声明被创建,并且没有JDBC连接被打开。数据库我的测试配置是这样的:

<bean id="targetDataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="org.h2.Driver" /> 
    <property name="url" value="jdbc:h2:mem:platform_test;DB_CLOSE_DELAY=-1" /> 
</bean> 

<bean id="sessionFactory" 
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="dataSource" ref="targetDataSource" /> 
    <property name="packagesToScan"> 
     <list> 
      <value>com.mypackage.model.*</value> 
     </list> 
    </property> 
    <property name="namingStrategy"> 
     <bean class="com.example.common.config.MyOwnNamingStrategy"/> 
    </property> 
    <property name="hibernateProperties"> 
     <map> 
      <entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> 
      <entry key="hibernate.max_fetch_depth" value="1" /> 
      <entry key="hibernate.use_sql_comments" value="true" /> 
      <entry key="hibernate.hbm2ddl.auto" value="update" /> 
     </map> 
    </property> 
    <!-- <property key="hibernate.current_session_context_class" value="thread"/> --> 
    <!-- <property key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JDBCTransactionFactory"/> --> 
</bean> 

<bean id="h2WebServer" class="org.h2.tools.Server" 
    factory-method="createWebServer" depends-on="targetDataSource" 
    init-method="start" lazy-init="false"> 
    <constructor-arg value="-web,-webPort,11111" /> 
</bean> 

我的控制器的代码是:

@Controller 
public class AppController extends BaseAnnotatedController { 

    @Autowired 
    private AppManagementService appManagementService; 

    @RequestMapping(value="/app/add", method=RequestMethod.POST, consumes={"application/json"}) 
    public @ResponseBody Long createApp(@RequestBody Application app) { 
     saveApp(app); 
     return app.getId(); 
    } 

    @RequestMapping(value="/app/{appId}/edit", method=RequestMethod.POST, consumes={"application/json"}) 
    public @ResponseBody Long editApp(@RequestBody Application app, @PathVariable Long appId) { 
     if (!appId.equals(app.getId())) { 
      WSError error = new WSError(ValidationErrorType.GENERIC, "id"); 
      throw new ValidationException(error); 
     } else { 
      saveApp(app); 
      return app.getId(); 
     } 
    } 

    @RequestMapping(value="/app/list", method=RequestMethod.GET) 
    public @ResponseBody List<Application> listApps() { 
     return appManagementService.listAllApps(); 
    } 

    @RequestMapping(value="/app/{appId}/get", method=RequestMethod.GET) 
    public @ResponseBody Application getAppDetails(@PathVariable Long appId) { 
     return appManagementService.getApplication(appId); 
    } 

    private void saveApp(Application app) { 
     if (isValid(app)) { 
      appManagementService.saveApp(app); 
     } 
    } 

    public @ResponseBody List<Application> listAllApps() { 
     return appManagementService.listAllApps(); 
    } 
} 

我的测试类是:

@Test 
public class AppControllerIntegrationTests extends AbstractContextControllerTests { 

    private MockMvc mockMvc; 

    @Autowired 
    AppController appController; 

    @Autowired 
    private AppManagementService appManagementService; 

    @Autowired 
    private BaseDao baseDao; 

    @BeforeClass 
    public void classSetup() { 
     Company comp = new Company(); 
     comp.setName("Some Company"); 
     baseDao.saveObject(comp); 
    } 

    @BeforeMethod 
    public void setup() throws Exception { 
     this.mockMvc = webAppContextSetup(this.wac).build(); 
    } 

    @Test 
    public void testAddInvalidAppWebJson() throws Exception { 
     String appJson = getInvalidApp().toJsonString(); 
     RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/add.json") 
       .contentType(MediaType.APPLICATION_JSON).content(appJson); 
     ResultActions resultAction = this.mockMvc.perform(requestBuilder); 
     resultAction.andExpect(status().isForbidden()); 
     MvcResult mvcResult = resultAction.andReturn(); 
     Exception resolvedException = mvcResult.getResolvedException(); 
     assertTrue(resolvedException instanceof ValidationException); 
     ValidationException validationException = (ValidationException) resolvedException; 
     assertEquals(validationException.getErrors().size(), 3); 
    } 

    @Test 
    public void testAddAppWebJson() throws Exception { 
     Application app = getMockApp(); 
     String appJson = app.toJsonString(); 
     RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/add.json") 
       .contentType(MediaType.APPLICATION_JSON).content(appJson); 


     this.mockMvc.perform(requestBuilder).andExpect(status().isOk()); 

    } 

    @Test 
    public void testEditAppWithWrongIdWebJson() throws Exception { 
     String appJson = getMockAppWithId().toJsonString(); 
     RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/2/edit.json") 
       .contentType(MediaType.APPLICATION_JSON).content(appJson); 
     this.mockMvc 
       .perform(requestBuilder) 
       .andExpect(status().isForbidden()) 
       .andExpect(
         content() 
           .string("{\"errors\":[{\"errorType\":\"-100\",\"field\":\"id\",\"constraint\":null}],\"objects\":null}")); 
    } 

    @Test(dependsOnMethods={"testAddApp", "testAddAppWebJson"}) 
    public void testEditAppWebJson() throws Exception { 
     Application app = getMockAppWithId(); 
     setAppWebsiteToDifferentOne(app); 
     String appJson = app.toJsonString(); 

     RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/1/edit.json") 
       .contentType(MediaType.APPLICATION_JSON).content(appJson); 

     this.mockMvc.perform(requestBuilder).andExpect(status().isOk()); 
    } 

    @Test 
    public void testEditInvalidAppWebJson() throws Exception { 
     Application app = getMockAppWithId(); 
     app.setWebsite("Saba7o 3asal"); 
     String appJson = app.toJsonString(); 
     RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/1/edit.json") 
       .contentType(MediaType.APPLICATION_JSON).content(appJson); 
     this.mockMvc 
       .perform(requestBuilder) 
       .andExpect(status().isForbidden()) 
       .andExpect(
         content() 
           .string("{\"errors\":[{\"errorType\":\"-114\",\"field\":\"website\",\"constraint\":null}],\"objects\":null}")); 
    } 

    @Test(dependsOnMethods="testEditAppWebJson") 
    public void testGetAppDetails() throws Exception { 
     RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/app/1/get.json"); 
     Application app = getMockAppWithId(); 
     setAppWebsiteToDifferentOne(app); 

     this.mockMvc.perform(requestBuilder).andExpect(status().isOk()) 
       .andExpect(content().string(app.toJsonString())); 
    } 
} 

我的服务的方法是:

@Override 
@Transactional(readOnly=false) 
public void saveApp(Application app) { 
    baseDao.saveObject(app); 
} 

所有测试方法都通过,除了f或最后一个,因为它预计应用程序的网站将被编辑。我哪里错了?

回答

1

需要知道在saveApp()中调用哪个hibernate方法时,还要确保您的服务使用@Transactional注释。

+0

我注明了服务方法,但还是没有区别。另外,我没有任何事务管理器在运行,所以默认情况下,所有事务都应该是读/写事务(特别是添加对象工作正常) –

+0

你说得对。我配置了事务管理器,并且一切正常。我不明白数据库是如何工作的。 –

+0

当您添加@Transactional注释并配置事务管理器时,spring将在该方法成功完成后执行提交,否则会进行回滚,可能是插入成功,因为它不需要事务,另一方面,不需要显式地调用save或update,hibernate会自动提交你的修改,只要你先从DB加载对象,然后更新加载对象的数据,然后所有对加载对象的更新都会自动保存。 –

相关问题