- ✔배포 스크립트 작성 및 배포 완료하기
- ✔mariaDB 프로젝트 연결해보기 (rds 연결)
- 안드로이드와 springboot 프로젝트 연결하기
- 안드로이드에서 REST API로 CRUD 간단하게 출력해보기
- 외부 인스턴스에서 test 깨지는 오류
- no main manifest attribute in 에러
- Error Executing DDL "alter table user drop foriegn key"
- error: package does not exist
- AWS RDS 인코딩 UTF8 설정하기
implementation 'com.android.volley:volley:1.1.1'
: 서버 통신과 관련된 라이브러리 (전송과 다운로드) <uses-permission android:name="android.permission.INTERNET"/>
: 인터넷 권한 설정 <activity android:name=".LoginActivity" android:exported="true">
📌 <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
📌 </intent-filter>
</activity>
다음 부분을 main Activity 로 만들 Activity 사이에 넣어준다.
intent는 앱 컴포넌트가 무엇을 할 것인지를 담는 메시지 객체이다. 메시지는 의사소통을 하기 위해 보내고 받는 것이다. 메시지를 사용하는 가장 큰 목적은 다른 엑티비티, 서비스, 브로드캐스트 리시버, 컨텐트 프로바이더 등을 실행하는 것이다. 인텐트는 그들 사이에 데이터를 주고 받기 위한 목적이다.
화면 == 하나의 엑티비티
즉 화면 간의 이동하는 과정은 각각의 액티비티를 필요에 따라 띄우거나 닫는 과정과 같다.
package org.techtown.knockknock;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class LoginActivity extends AppCompatActivity implements View.OnClickListener{
Button btn_login;
Button btn_register2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
btn_login = (Button) findViewById(R.id.btn_login);
btn_register2 = (Button)findViewById(R.id.btn_register2);
btn_login.setOnClickListener(this);
btn_register2.setOnClickListener(this);
}
@Override
📌 public void onClick(View view) {
switch(view.getId()){
case R.id.btn_login:
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
finish();
break;
case R.id.btn_register2:
Intent intent2 = new Intent(getApplicationContext(), RegisterActivity.class);
startActivity(intent2);
finish();
break;
}
}
}
화면 전환 코드는 다음과 같이 Intent 객체를 새로 생성해서 안에 현재 ApplicationContext와 전환된 화면 Activity 클래스를 넣으면 된다. intent의 시작은 startActivity(intent)
혹은 startActivityforResult(intent)
로 한다.
Intent가 끝나고 현재 activity로 돌아오게 하기 위해 finish()
메서드를 넣어준다.
나는 아직도 이 때의 오류를 잡지 못해서 헤매는 중이다.
그러나 오늘은 약간의 변화가 생겨서 이걸 기록하면 좋을 것 같다. 🎈😇
나를 괴롭히던 compileQuerydsl 오류는 결국 인프런에서도 도움을 못받은 채 나의 모든 개발 의욕을 앗아갔다.....
그래도 뭐라도 해야지 하는 심정으로 프로젝트 이것 저것 뒤적거리고 있던 찰나에
?????????????????????????????????????????????????????????????????????????
띠용..
기존의 compileQuerydsl 오류는 build 돼서 패스되고 이제 그 이후의 test 오류가 발생했다.
오류 너머 오류는 이제 너무 익숙해서 그려려니 하는데 대체 compileQuerydsl 오류는 어떻게 해결된거지?
내가 쓴 방법은 다음과 같다.
1.
compileQuerydsl { // (7)
options.annotationProcessorPath = configurations.querydsl
}
// 📌compileQuerydsl.doFirst { if(file(querydslDir).exists() ) delete(file(querydslDir)) }
아래 한 줄의 코드를 주석처리한다. (코드 내용은 querydsl 폴더가 있으면 그 폴더를 지우라는 의미)
2. ./gradlew build
로 빌드한다. -> 이때는 compileQuerydsl 문제가 터지지 않는다.
3. 다시 build 하려고 하면 기존의 queryDsl이 이미 생성되었기 때문에 또 다른 오류가 발생해버린다. 그래서 build 하기 전에 항상 ./gradlew clean
을 하고 다시 빌드한다.
왜 위의 주석 단 코드때문에 프로젝트 빌드가 외부에서 안되는지는 정말 모르겠다 ㅠ (로컬에서는 잘만 되기 때문에,,,)
그렇다고 매번 이렇게 clean하고 다시 build하는게 맞지는 않지 않을까? 어떻게 해야할지 좀 더 고민하고 찾아봐야겠다..
완전히 해결된 것은 아니지만 대충 문제가 어디인지 알게 되어서 기쁘다.. 뭐라도 진행된 기분
며칠간 정말 붙잡고 있어도 아무것도 이루어진것이 없어서 우울했는데 😭
querydsl 문제를 얼레벌레 해결하고 나니 또다른 오류에 봉착했다.
바로 TEST가 깨지는 오류였다.
오류메세지는 다음과 같았다.
KnockKnockApplicationTests > contextLoads() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1804
Caused by: org.hibernate.service.spi.ServiceException at AbstractServiceRegistryImpl.java:275
Caused by: org.hibernate.HibernateException at DialectFactoryImpl.java:100
이 문제는 내가 테스트와 연결되어있는 DB를 embedded(내장) H2가 아니라 로컬에서 접근하는 로컬 H2를 사용하고 있었기 때문이였다.
몰랐지만 새로 안 사실이였는데
H2는 로컬 h2 데이터베이스와 Springboot에서 제공해주는 프로젝트 내장 h2로 나뉜다
내 프로젝트가 로컬 h2와 연결되어 있으니 당연히 외부에서 접근해서 테스트를 돌릴 때는 로컬 데이터베이스에 접근할 수 없어서 에러가 났던 것이다.
따라서 설정을 embedded h2로 다음과 같이 변경해주었다.
runtimeOnly 'com.h2database:h2:1.4.197'
를 gradle.build 의 dependency에 추가한다.spring:
h2:
console:
enabled: true
datasource:
url: jdbc:h2:mem:testdb
# username: sa
# password:
# driver-class-name: org.h2.Driver
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
format_sql: true
show_sql: true
server:
port: 8081
logging:
level:
org.hibernate.sql: debug
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/knockknock
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
format_sql: true
show_sql: true
profiles:
active: dev
logging:
level:
org.hibernate.sql: debug
드디어..!! 드디어 build가 successful하게 이루어졌다 ㅠㅠㅠㅠㅠㅠ😭😭😭
sudo amazon-linux-extras install java-openjdk11
졸업 프로젝트하다가 이거 못찾아서 또 한참을 헤맸네 ..ㅎㅎㅎㅎ
프로젝트 빌드가 잘 되는 것도 확인했겠다 이제 jojoldu님의 블로그 남은 단계를 밟아보려고 배포 스크립트를 작성하고 배포하려는 찰나에..!
또 다시 어김없이 오류가 나타났다.
nohup.out 파일에서 로그를 확인해보려고 생성된 nohup.out파일을 열람하였더니 다음과 같은 메세지가 떴다.
no main manifest attribute, in /home/ec2-user/app/git/KnockKnock-0.0.1-SNAPSHOT-plain.jar
no main manifest attribute, in /home/ec2-user/app/git/KnockKnock-0.0.1-SNAPSHOT-plain.jar
no main manifest attribute, in /home/ec2-user/app/git/KnockKnock-0.0.1-SNAPSHOT-plain.jar
no main manifest attribute, in /home/ec2-user/app/git/KnockKnock-0.0.1-SNAPSHOT-plain.jar
no main manifest attribute in 에러는 spring 애플리케이션을 빌드한 결과물로 나온 jar파일에서 처음 호출할 Main 메소드를 찾지 못했다는 에러다.
찾아보니 spring boot 2.5.0 이상 버전의 gradle로 빌드할 때 jar 파일이
앱이름.jar -> bootJar Task로 생성된것
앱이름-plain.jar -> build Task로 생성된것
이렇게 두 개 생성된다고 한다.
첫번째 jar는 해당 프로젝트에 필요한 모든 의존성이 같이 추가된것으로 MANIFEST.MF까지 모두 정상적인 형태로 나온다.
하지만 plain.jar는 의존성을 제외하고 딱 프로젝트에 있는 자원들만 jar로 만든것으로 spring 관련 의존성이 빠져 MANIFEST.MF에 Main메소드의 위치가 나오지 않는다.
에러 메세지를 보니 plain.jar 파일을 java -jar로 실행해서 에러가 난 것 같다
따라서 springboot의 공식 사이트에 나와있는 plain.jar 파일을 생성하지 않는 명령어를 build.gradle에 추가했다.
jar {
enabled = false
}
그런데 여전히 plain.jar 파일이 생성되는 것이다 😭😭 대체 왜이럴까
bootJar{
enabled(true)
archiveClassifier.set("")
}
구글링해서 다음과 같은 내용을 추가하니까 해결되었다. 후,, 대체 공식 사이트에서 제시한 방법도 안통하면 어쩌자는 건지 😣😣🔥 어쨌든 해결되어서 다행이다.
결론은 위에 jar옵션과 bootJar 옵션을 둘 다 주어야 한다는 것!!
대부분의 과정은 jojoldu님을 참고하였고 따라서 생략되는 부분도 많을 것이다.
#!/bin/bash
REPOSITORY=/home/ec2-user/app/git // git에서 가져온 프로젝트 레파지토리 위치
cd $REPOSITORY/KnockKnock/ // 프로젝트 레파지토리 명
echo "> Git Pull"
git pull
echo "> 프로젝트 Build 시작"
./gradlew build
echo "> Build 파일 복사"
cp ./build/libs/*.jar $REPOSITORY/
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -f 📌KnockKnock) // 프로젝트 레파지토리 명
echo "$CURRENT_PID"
if [ -z $CURRENT_PID ]; then
echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> kill -2 $CURRENT_PID"
kill -9 $CURRENT_PID
sleep 5
fi
echo "> 새 어플리케이션 배포"
JAR_NAME=$(ls $REPOSITORY/ |grep 📌'KnockKnock' | tail -n 1)
echo "> JAR Name: $JAR_NAME"
nohup java -jar $REPOSITORY/$JAR_NAME &
nohup은 build 후 java - jar
명령어가 실행되며 프로젝트가 구동을 시작할 때 찍히는 로그들을 기록해주는 명령어이다. 이 로그는 nohup.out
파일에 생성된다.
쉽게 말해 로컬에서 프로젝트를 실행할 때 springboot 로그부터 뜨는 그 로그가 nohup.out 파일에 저장되면 정상적으로 프로젝트가 실행되고 있다고 이해하면 된다.
chmod 755 ./deploy.sh
: ./deploy.sh 파일의 실행 권한 주기. 이후 배포는 ./deploy,sh
코드로 해결
ps -ef|grep {프로젝트(레파지토리)명}
: 프로젝트로 실행중인 프로세스(jar 파일)을 확인하는 명령어
이 때 📌핀 꽂이둔 부분은 jar 파일의 이름에서 일부를 검색하는 코드이기 떄문에 jar 파일명을 잘 확인하고 해당하는 프로젝트 명으로 입력해주어야 한다!!!
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
compile("org.mariadb.jdbc:mariadb-java-client")
spring:
datasource:
url: jdbc:mariadb://{rds엔드포인트}:3306/{데이터베이스 이름}
username: 마스터 사용자 명
password: 마스터 사용자 비밀번호
driver-class-name: org.mariadb.jdbc.Driver
이렇게 연결하고 로컬에서 프로젝트를 돌려본 결과 오류가 발생했다 😇
org.hibernate.tool.schema.spi.commandacceptanceexception: error executing ddl "alter table user drop foriegn key"
이 오류를 찾아본 결과 지정된 table을 찾아서 drop할 foriegn key를 drop해야 하는데
문제는 alter table을 찾을 수 없었던 것이다.
이 문제가 발생하는 까닭은 바로 jpa.hibernate.ddl-auto: create
옵션에 있었다.
나는 create 옵션을 두고 있었는데 프로젝트가 실행될때마다 create옵션으로 인해 모든 테이블이 drop되기 때문에 alter table에서 해당 table 찾을 수 없었던 것이다.
따라서 이 문제의 해결은 ddl-auto: update
로 옵션을 줘서 해결할 수 있었다
이 오류는 내가 rds 연결 후 만들어놓은 REST API 가 잘 동작하는지 확인하기 위해 초기 데이터를 넣어주려고 initDB 파일에 초기 데이터 내용을 작성한 뒤 프로젝트를 실행하니까 나는 오류였다.
다음과 같이 아주 멀쩡히 잘 있는 패키지 경로를 못찾겠다고 하니 아주 환장할 노릇이였다 😧
이 문제는 compileQuerydsl 문제와 같은,, 문제인데 결과적으로 Qclass generate된 부분을 clean하고 돌려주면 해결된다
그러나 또 다른 문제에 직면하고 만다,,
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'initDB': Invocation of init method failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: could not extract ResultSet; nested exception is org.hibernate.exception.JDBCConnectionException: could not extract ResultSet
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:440) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.12.jar:5.3.12]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.12.jar:5.3.12]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.6.jar:2.5.6]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.6.jar:2.5.6]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.6.jar:2.5.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.6.jar:2.5.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.6.jar:2.5.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.6.jar:2.5.6]
at jpaproject.knockknock.KnockKnockApplication.main(KnockKnockApplication.java:16) ~[main/:na]
Caused by: org.springframework.dao.DataAccessResourceFailureException: could not extract ResultSet; nested exception is org.hibernate.exception.JDBCConnectionException: could not extract ResultSet
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:255) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.12.jar:5.3.12]
at jpaproject.knockknock.repository.MemberRepository$$EnhancerBySpringCGLIB$$8d486979.findByNickName(<generated>) ~[main/:na]
at jpaproject.knockknock.service.MemberService.validateSameNickNameExsist(MemberService.java:38) ~[main/:na]
at jpaproject.knockknock.service.MemberService.signIn(MemberService.java:25) ~[main/:na]
at jpaproject.knockknock.service.MemberService$$FastClassBySpringCGLIB$$c4a35944.invoke(<generated>) ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.12.jar:5.3.12]
at jpaproject.knockknock.service.MemberService$$EnhancerBySpringCGLIB$$d024d447.signIn(<generated>) ~[main/:na]
at jpaproject.knockknock.InitService.dbInit1(InitService.java:24) ~[main/:na]
at jpaproject.knockknock.InitService$$FastClassBySpringCGLIB$$c547a807.invoke(<generated>) ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.12.jar:5.3.12]
at jpaproject.knockknock.InitService$$EnhancerBySpringCGLIB$$abab9270.dbInit1(<generated>) ~[main/:na]
at jpaproject.knockknock.InitDB.init(InitDB.java:17) ~[main/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ~[spring-beans-5.3.12.jar:5.3.12]
... 18 common frames omitted
Caused by: org.hibernate.exception.JDBCConnectionException: could not extract ResultSet
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:48) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:67) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.getResultSet(Loader.java:2297) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2050) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2012) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.doQuery(Loader.java:948) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2843) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2825) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2657) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.Loader.list(Loader.java:2652) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:506) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:400) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1414) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1636) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1604) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1652) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at jpaproject.knockknock.repository.MemberRepository.findByNickName(MemberRepository.java:34) ~[main/:na]
at jpaproject.knockknock.repository.MemberRepository$$FastClassBySpringCGLIB$$cb64a86a.invoke(<generated>) ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.12.jar:5.3.12]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.12.jar:5.3.12]
... 57 common frames omitted
Caused by: java.sql.SQLTransientConnectionException: (conn=1255) Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation '='
at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:79) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:158) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.MariaDbStatement.executeExceptionEpilogue(MariaDbStatement.java:266) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.ClientSidePreparedStatement.executeInternal(ClientSidePreparedStatement.java:229) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.ClientSidePreparedStatement.execute(ClientSidePreparedStatement.java:149) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.ClientSidePreparedStatement.executeQuery(ClientSidePreparedStatement.java:163) ~[mariadb-java-client-2.7.4.jar:na]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-4.0.3.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-4.0.3.jar:na]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
... 80 common frames omitted
Caused by: org.mariadb.jdbc.internal.util.exceptions.MariaDbSqlException: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation '='
at org.mariadb.jdbc.internal.util.exceptions.MariaDbSqlException.of(MariaDbSqlException.java:34) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.exceptionWithQuery(AbstractQueryProtocol.java:194) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.exceptionWithQuery(AbstractQueryProtocol.java:177) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:321) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.ClientSidePreparedStatement.executeInternal(ClientSidePreparedStatement.java:220) ~[mariadb-java-client-2.7.4.jar:na]
... 85 common frames omitted
Caused by: java.sql.SQLException: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation '='
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.readErrorPacket(AbstractQueryProtocol.java:1694) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.readPacket(AbstractQueryProtocol.java:1556) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.getResult(AbstractQueryProtocol.java:1519) ~[mariadb-java-client-2.7.4.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:318) ~[mariadb-java-client-2.7.4.jar:na]
... 86 common frames omitted
전체 에러는 다음과 같다.
이 에러는 인코딩 문제가 제대로 정리되지 않아서 생기는 오류였다.
이 블로그에서 나온 대로 AWS에서 파라미터 그룹을 모두 utf8mb4, utf8mb4_general_ci 로 바꾸고 character_set_database, collation_connection을 수동으로 utf8mb4로 변경했더니 해결되었다
한 가지 헤맸던 점은 수동으로 변경해줄 때
ALTER DATABASE 데이터베이스명 CHARACTER SET = 'utf8mb4'
COLLATE = 'utf8mb4_general_ci';
저기 데이터베이스명을 RDS 데이터베이스명으로 생각했는데 그것 뿐만 아니라 Innodb까지 변경해줘야한다
또한 변경하자마자 바로 반영되는 것이 아니니 DB도 재접속해보고, 당연히 기존의 table은 drop한 뒤 새로 생성해주어야 한다
짠! 이리하여 REST API를 써서 CR이 되는 것을 확인했다.
오늘은 시간이 너무 늦어서 나머지 CRUD 기능은 다음에 더 해보고 내일은 안드로이드 연결까지 할 수 있었으면 좋겠다!
오늘의 나야 수고 많았다 🥰