2013-01-13 1 views
1

나는 이상한 문제에 직면 해있다. 현재 Spring-MVC 3.2와 Hibernate 4.1.9에 기반한 웹 애플리케이션을 작성하고 있습니다. 나는 TestNG 유닛 테스트로 샘플 컨트롤러를 썼고, 편집을 제외하고는 모든 것이 괜찮습니다. 나는 새로운 객체를 저장할 때 매력처럼 작동한다는 것을 알 수 있지만, 기존 객체를 편집하려고하면 아무 이유도없이 저장되지 않는다. (나는 추가와 업데이트를 위해 같은 메소드를 호출한다) .하이버 네이트는 편집 된 엔티티를 저장하지 않고 새로운 엔티티를 저장한다.

당신이 볼 수 있듯이 편집 된 객체를 저장하는 로그가

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.springframework.http.converter.json.MappingJacksonHttpMessageConverter[email protected]] 
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 

동안 두 번째 로그에 Application을 입력

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,[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 

의 새로운 객체를 추가하는 로그, 아니 준비된 명령문 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 annotation을 추가하고 트랜잭션 관리자를 구성하면 스프링이 메소드를 성공적으로 완료 한 후에 커밋을 수행합니다. 그렇지 않으면 트랜잭션이 필요하지 않기 때문에 삽입이 성공할 수 있습니다. 명시 적으로 save 나 update를 호출 할 필요가 없으면, Hibernate는 DB로부터 먼저 객체를 첨부하여 객체를 첨부하고 변경된 객체를 자동으로 업데이트 한 다음,로드 된 객체에 대한 모든 업데이트를 자동으로 저장한다. –

관련 문제