[Trouble Shooting] - 좋아요 Repository 실행 오류
좋아요 기능을 구현하기 위한 좋아요 모델 Like를 다음과 같이 구현하였다.
@Entity
@Table(name = "LIKE")
@Data
@NoArgsConstructor
public class Like {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
long likeId;
@ManyToOne
@JoinColumn(name = "USER_IDX")
User user;
@ManyToOne
@JoinColumn(name = "PROJECT_ID")
Project project;
}
User index와 Project Id값을 각각 다대일 연관관개로 매핑하여 가지고 있는 테이블이다.
아래는 EntityManager를 이용해 DB에 직접적으로 접근하는 Repository 코드의 일부이다.
@Repository
public class LikeRepository {
@PersistenceContext
EntityManager em;
public long save(User user, Project project){
Like like = new Like();
like.setUser(user);
like.setProject(project);
em.persist(like);
return like.getLikeId();
}
//...//
}
LikeRepository의 동작을 확인하기 위한 테스트 코드를 작성 후 실행하였다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:appConfig.xml")
public class LikeRepositoryTest {
@Autowired LikeRepository likeRepository;
@Autowired UserRepository userRepository;
@Autowired ProjectRepository projectRepository;
User basicUser;
Project basicProject;
@Test
@Transactional
public void 좋아요() throws Exception{
//given
make_basic_data();
//when
long likeId = likeRepository.save(basicUser, basicProject);
//then
Assertions.assertThat(likeRepository.findById(likeId).getUser()).isEqualTo(basicUser);
Assertions.assertThat(likeRepository.findById(likeId).getProject()).isEqualTo(basicProject);
}
//...//
@Transactional
public void make_basic_data(){
basicUser = new User();
//== basicUser 값 설정 ==//
userRepository.save(basicUser);
basicProject = new Project();
//== basicProject 필드 값 설정 ==//
projectRepository.save(basicProject);
}
}
좋아요() 메서드의 실행 결과 다음의 오류 메시지를 확인할 수 있었다.
...
14:57:43.558 [main] DEBUG org.mariadb.jdbc.client.impl.StandardClient -- execute query: insert into LIKE (PROJECT_ID, USER_IDX) values (?, ?)
14:57:43.586 [main] WARN org.mariadb.jdbc.message.server.ErrorPacket -- Error: 1064-42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE (PROJECT_ID, USER_IDX) values (2, 2)' at line 1
14:57:43.587 [main] DEBUG org.hibernate.engine.jdbc.spi.SqlExceptionHelper -- could not execute statement [n/a]
java.sql.SQLSyntaxErrorException: (conn=2813) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE (PROJECT_ID, USER_IDX) values (2, 2)' at line 1
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:282)
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:370)
...
at com.example.tumblbugclone.repository.LikeRepository.save(LikeRepository.java:24)
...
at com.example.tumblbugclone.repository.LikeRepositoryTest.좋아요(LikeRepositoryTest.java:41)
...
14:57:43.595 [main] WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper -- SQL Error: 1064, SQLState: 42000
14:57:43.595 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper -- (conn=2813) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE (PROJECT_ID, USER_IDX) values (2, 2)' at line 1
14:57:43.620 [main] DEBUG org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl -- JDBC transaction marked for rollback-only (exception provided for stack trace)
java.lang.Exception: exception just for purpose of providing stack trace
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.markRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:324)
...
at com.example.tumblbugclone.repository.LikeRepository$$SpringCGLIB$$0.save(<generated>)
at com.example.tumblbugclone.repository.LikeRepositoryTest.좋아요(LikeRepositoryTest.java:41)
...
org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute statement; SQL [n/a]
...
at com.example.tumblbugclone.repository.LikeRepository$$SpringCGLIB$$0.save(<generated>)
at com.example.tumblbugclone.repository.LikeRepositoryTest.좋아요(LikeRepositoryTest.java:41)
...
Caused by: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:64)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:56)
...
at com.example.tumblbugclone.repository.LikeRepository.save(LikeRepository.java:24)
... 38 more
Caused by: java.sql.SQLSyntaxErrorException: (conn=2813) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE (PROJECT_ID, USER_IDX) values (2, 2)' at line 1
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:282)
... 73 more
얼추 살펴 보니 SQL 문법이 잘못되었거나, MariaDB의 버전을 확인 해 보라는 등의 메시지를 볼 수 있었다.
그러나, SQL 문법은 하이버네이트에서 알아서 생성 해 줄테니 문제가 없을 것 같았고, MariaDB의 버전 호환 역시 이전에 확인 하고 넘어갔기 때문에 해당 부분 이전 단계의 문제일 것이라 생각이 들었다.
LikeRepositoryTest 클래스의 빌드 과정에서의 에러 메시지에서 다음의 에러를 발견할 수 있었다.
...
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "
drop table if exists LIKE" via JDBC Statement
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
...
Caused by: java.sql.SQLSyntaxErrorException: (conn=2813) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LIKE' at line 1
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:282)
... 61 common frames omitted
LIKE 테이블을 생성하는 과정에서 에러가 발생했기 때문에 LIKE 테이블을 사용하는 로직에서 전부 에러가 발생하는 것이었다.
CommandAcceptanceException 으로 검색을 해 본 결과, Like Entity에 사용했던 테이블 명 LIKE가 MariaDB의 예약어 이기 때문에 발생한 오류였다.
Like Entity를 다음과 같이 수정하여 문제를 해결하였다.
@Entity
@Table(name = "LIKES")
@Data
@NoArgsConstructor
public class Like {...}
초기 개발 단계에서 spring.jpa.hibernate.ddl-auto=create로 설정 후 서버에서는 테이블을 별도로 생성하지 않아서 뒤늦게 비즈니스 로직 개발 단계에서 발견하게 되었다.
프로젝트 진행을 위해 SQL을 완벽히 공부하지 못한 상태에서 JPA를 사용하니 이런 문제를 겪게 되는 것 같다. 프로젝트가 종료되면 DB 공부를 진행하자는 다짐이 조금 더 강해졌다.
아래는 트러블 슈팅에 참고한 블로그이다.