Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException

개발환경

  • hibernate : 4.2.0.Final
    • hibernate dialect : org.hibernate.dialect.MySQLDialect
  • MariaDB : 5.5.29-MariaDB

문제 로그

java.lang.reflect.InvocationTargetException

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

    at java.lang.reflect.Method.invoke(Method.java:601)

    at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)

    at java.lang.Thread.run(Thread.java:722)

Caused by: org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [insert into department(id, name, description, parent_id, createdDate) values(?, ?, ?, ?, ?)]; nested exception is java.sql.BatchUpdateException: Table 'database.department' doesn't exist

    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:237)

    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)

    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605)

    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)

    at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:890)

    at org.springframework.jdbc.core.namedparam.NamedParameterBatchUpdateUtils.executeBatchUpdateWithNamedParameters(NamedParameterBatchUpdateUtils.java:40)

    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.batchUpdate(NamedParameterJdbcTemplate.java:324)

    ... 6 more

Caused by: java.sql.BatchUpdateException: Table 'database.department' doesn't exist

    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2054)

    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1467)

    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)

    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:905)

    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:890)

    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:589)

    ... 12 more

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'database.department' doesn't exist

    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)

    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)

    at com.mysql.jdbc.Util.getInstance(Util.java:386)

    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1054)

    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4120)

    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4052)

    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2503)

    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2664)

    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815)

    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)

    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)

    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2006)

    ... 17 more

[INFO] ------------------------------------------------------------------------

[INFO] BUILD FAILURE

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 10.762s

[INFO] Finished at: Wed Apr 24 22:06:17 KST 2013

[INFO] Final Memory: 43M/365M

[INFO] ------------------------------------------------------------------------

[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.2.1:java (default-cli) on project docs-flow-data-manager: An exception occured while executing the Java class. null: InvocationTargetException: PreparedStatementCallback; bad SQL grammar [insert into department(id, name, description, parent_id, createdDate) values(?, ?, ?, ?, ?)]; nested exception is java.sql.BatchUpdateException: Table 'database.department' doesn't exist -> [Help 1]

[ERROR]

[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.

[ERROR] Re-run Maven using the -X switch to enable full debug logging.

[ERROR]

[ERROR] For more information about the errors and possible solutions, please read the following articles:

[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

해결책

  • 하이버네이트가 자동으로 @Entity를 이용하여 테이블을 생성할 때 기본은 클래스명을 따른다.
    • 대소문자를 구분하는 Database 에서는 이 부분이 문제를 일으키는 요인으로 추측된다.
  • @Entity 아래에 @Table(name=“TABLE_NAME”) 으로 테이블명을 대문자로 하여 강제적으로 선언했다.
  • 참조관계가 생성되는 부분들에 대해서도 @JoinTable(name=“JOIN_TABLE”)으로 지정해주는 것이 적절해보인다.

### 개발환경

* Spring MVC 3.2.0

* Hibernate 4.2.0.Final


### 문제발생

MVC 패턴에서 Controller 단에서 @PathVariable로 객체를 받아서 처리하려는 시도를 하면서 문제가 발생했다.


### 로그


HTTP Status 500 - No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.HashMap["result"]->com.sil.docsflow.web.common.Result["data"]->com.sil.docsflow.domain.company.User_$$_javassist_15["handler"])


type Exception report


message No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.HashMap["result"]->com.sil.docsflow.web.common.Result["data"]->com.sil.docsflow.domain.company.User_$$_javassist_15["handler"])


description The server encountered an internal error that prevented it from fulfilling this request.


exception


org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.HashMap["result"]->com.sil.docsflow.web.common.Result["data"]->com.sil.docsflow.domain.company.User_$$_javassist_15["handler"])

org.codehaus.jackson.map.ser.StdSerializerProvider$1.failForEmpty(StdSerializerProvider.java:89)

org.codehaus.jackson.map.ser.StdSerializerProvider$1.serialize(StdSerializerProvider.java:62)

org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:430)

org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:175)

org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:142)

org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:430)

org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:175)

org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:142)

org.codehaus.jackson.map.ser.MapSerializer.serializeFields(MapSerializer.java:287)

org.codehaus.jackson.map.ser.MapSerializer.serialize(MapSerializer.java:212)

org.codehaus.jackson.map.ser.MapSerializer.serialize(MapSerializer.java:23)

org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:600)

org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:280)

org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1345)

org.springframework.web.servlet.view.json.MappingJacksonJsonView.writeContent(MappingJacksonJsonView.java:292)

org.springframework.web.servlet.view.json.MappingJacksonJsonView.renderMergedOutputModel(MappingJacksonJsonView.java:247)

org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:264)

org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1208)

org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:992)

org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:939)

org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)

org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)

org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)

javax.servlet.http.HttpServlet.service(HttpServlet.java:621)

org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)

javax.servlet.http.HttpServlet.service(HttpServlet.java:728)

org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

note The full stack trace of the root cause is available in the Apache Tomcat/7.0.34 logs.


Apache Tomcat/7.0.34


### 해결방법

* 참조페이지 : [Strange Jackson exception being thrown when serializing Hibernate object](http://stackoverflow.com/questions/4362104/strange-jackson-exception-being-thrown-when-serializing-hibernate-object)


### 나름 분석

하이버네이트에 의해 영속화된 객체에 hadler 와 hibernateLazyInitializer 의 필드가 생성되는 것으로 보인다. 이렇게 영속화된 객체를 JSON으로 직렬화 하는 과정에서 hadler 가 lazy로 처리되어 있어서 발생하는 문제가 아닌가 추측해본다.


### 문제 발생

org.hibernate.MappingException: org.hibernate.dialect.MySQLDialect does not support sequences


### 문제원인 

도메인의 @ID @GeneratedValue(strategy = GenerationType.SEQUENCE) 으로 선언해둔 부분에서 GenerationType.SEQUENCE 생성방식을 MySQL에서 지원하지 않는 것으로 보인다.


### 해결방법

GenerationType.AUTO 으로 변경


Hibernate 3.6.0.Final 을 사용하다가 4.2.Final 으로 변경하면서

MultipleBagFetchException: cannot simultaneously fetch multiple bags

이 발생하면서 entityManager가 정상적으로 밀드되지 않는 문제가 생겨남


* 관련 문제 해결 확인 :  MultipleBagFetchException: cannot simultaneously fetch multiple bags is there a workaround


@OneToMany(fetch=FetchType.EAGER)

private List<Department> departments;


형태로 선언된 부분들과 관련된 문제였다.

List 클래스와 관련된 문제가 아닐까 추측이 된다.


* 해결방법

    * 첫번째 방법

    @OneToMany(fetch=FetchType.EAGER)

    @LazyCollection(LazyCollectionOption.FALSE)  



    * 두번째 방법 

    @OneToMany(fetch=FetchType.LAZY)



* 개인적 의견 

    * 두번째 방법이 문제가 없다면, 걍 두번째 방법을 사용

    * @OneToOne의 경우에는 FetchType.EAGER 선언해도 오류없이 동작한다.

회사에서 MyBatis로 구현되어 있던 프로젝트를 새로 구축하면서 ORM을 써보기로 했다.

  리팩토링한다고 일정을 잡았는데, 내가 아는 리팩토링(기능에 크게 변형을 가하지 않으면서 코드 구조를 개선하는 작업이랑 정돈되지 않은 URL을 REST 형태로 잘 정돈)이랑 회사에서 이야기되는 리팩토링(기능개선하고 기능추가하고 구조를 바꾸고... 리모델링이잖아!!)이 서로 차이가 있었다.

  회사에서 4개월 정도 진행된 프로젝트를 새로이 구축하며 진행하기로 했다.

  설계당시에는 고려하지 못했던 변경사항들이 적용된 DB model 구조의 누더기같은 모습에

'ORM'으로 하면 이런 거 신경쓰는 일이 줄어들텐데...

DDD에 대한 환상을 가지고 있는지도 모른다. @_@) 

빠른 시간안에 결과물을 내놓는 개발방식으로 채용해도 나쁘지 않다는 경험을 가지고 있다.

  MyBatis로 Mapping Class와 DB 테이블들의 구성을 맞추는 작업이 귀찮아졌다... Orz... 내가 한 것도 아닌데...

  예전에(2년 전?) 몇달 정도 사용해봤던게 전부인지라, 쿼리쪽은 건드릴 엄두가 나질 않는 무서운 상황을 피하려고 무리수를 둔 것인지도 모르겠지만... 나로서는 기존에 해왔던 것들에 대한 속성심화과정을 하는 것이라 좋은 기회일지도 모른다.


회사에서 기본구조로 잡을 프로젝트 구성과 유사한 형태로 틀을 잡아봤다.

  Hibernate를 Spring Data JPA로 감싸서 사용할 예정이다. 

  프로젝트 기본구조는 잡아놨으니, 이제 도메인 클래스들에 대한 설계작업을 진행하려고 한다.

각 도메인들간의 관계를 잡아두고, 클래스로 만들어내고, 클래스 다이어그램으로 추출하면 간단하겠지!!

4개월 개발한 프로젝트를 한달만에 부지런히 만들어내야 하는 상황에 놓였다.

잘 할 수 있으려나 모르겠네. 다른 사람이 잡아주던 환경위에서 개발하는 것에만 익숙하다가 내가 환경설정을 하고 개발을 진행한다는 게 쉬운 일은 아닌데 말이지...

이번 기회에 jenkins를 통한 배포도 정착화시킬 수 있으면 좋겠는데...


내 자신에게 Good luck for me!

+ Recent posts