반응형

git에서 프로젝트를 클론 후 STS로 프로젝트를 열었다.

 

그런데 첫줄에 에러 표시가 있었다!!!...

 

뭐지.. 그냥 가져왔을 뿐인데 에러가 나길래 당황 ㅜ ㅜ

 

하지만 갓글링을 통해 여러가지 방법을 찾아보고 시도했다.

 

먼저 이런 오류가 발생하는 원인은 Eclipse에서 나타나는 버그로 maven이 jar 들을 다운 받으면서 도중에 멈추거나 꼬인 것이라고 한다.

 

1. 해당프로젝트 우클릭 -> Maven -> Update Project

이렇게 하면 해결 된다는 글을 보았지만 내 경우에는 에러가 그대로 남아있었다.

 

2. porm.xml 에서 spring-boot-stater-parent의 version을 변경 (이 방법으로 해결!)

 

처음엔 아래 코드로 되어 있었다.

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.5.RELEASE</version>
</parent>

아래 코드로 변경 후, 저장을 해서 다시 빌드! 하니 오류가 해결됐다.

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.4.RELEASE</version>
</parent>

 

3. 해당 프로젝트 우클릭 -> Maven -> Update project 로 들어가서

일부만 캡쳐

해당 프로젝트 체크 후 아래 부분은 위 사진과 같이 체크 후 OK.

 

4. porm.xml에서 

<properties>
	<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
    <java.version>1.8</java.version>
</properties>

위와같은 properties를 찾고 메이븐 플러그인을 다운그레이드 한 후 

다시 프로젝트 우클릭 -> Maven ->Update 해주면 해결 된다고 한다.

나는 1,3,4 번을 먼저 시도했지만 안됐고, 2번을 통해 해결했다!

반응형
반응형

Spring boot 를 학습하던 도중

 

AWS에 올리려다 git에 노출되면 안되는 값이 있어 외부 yml 파일을 만들고

 

application.yml 파일에 include 해서 data를 사용하려 했다.

 

그런데 데이터 주입이 되지 않았다.

 

myval:
	value: hi

이렇게 yml 파일이 설정 되어 있다고 가정 한다.

 

1. static 변수에 주입해서 사용했다

@Value("${myval.value}")
private static String val;

이런 식으로 사용 하였는데 데이터가 주입되지 않았다.

 

기존에 구현했던 클래스는 상수에 값을 때려 박고 그 값을 static 메소드에서 사용하도록 했었다.

 

그 점을 인지 못하고 그냥 변수 부분만 바꾸면 되겠지 하고 사용했지만, 실패!

 

2. static 키워드를 제거하고 new MyClass();와 같이 인스턴스 생성해서 사용했다.

 

@Component
@ConfigurationProperties(prefix="myval")
@Getter
@Setter
public class MyClass{
	private String value;
}

 

new MyClass(); 로 생성해서 value값을 출력하는 메소드를 만들고 호출해 봤지만

 

null 값이 나온다. 실패!

 

3. (2)번 처럼 만든 클래스를 @Autowired로 주입 시켜 사용했다.

public class TestMain{
	
    @Autowired
    private MyClass myclass;
    
    public void test(){
    	myclass.출력메소드();
    }
}

 

yml 파일의 데이터를 사용하는 클래스를 호출하는 곳에서 출력 메소드를 호출해 봤고 성공했다!

 

@Autowired, @Inject, @Resource, @Value 어노테이션들은 스프링의 BeanPostProcessor 구현체가 처리한다. 이는 (무엇이든간에) 자신만의 BeanPostProcessor나 BeanFactoryPostProcessor 타입내에서는 이러한 어노테이션들을 적용할 수 없다는 의미이다. 이러한 타입들은 반드시 명시적으로 XML이나 스프링의 @Bean 메서드를 사용해서 '연결해야' 한다.

 

구글링을 해서 찾아봤지만 위와같은 글만 있고 정확한 원인은 찾을 수 없었다..

 

혹시 왜 그런지 알고 계시면 답변 부탁드립니다~~!

 

그리고 yml 또는 properties 파일에서 값을 읽어오는 Class에는 setter 메소드가 꼭 있어야 한다.!!!!!!

 

--------------------------------------추가--------------------------------

좀 더 알아본 결과 Property 값 주입은 Bean 컨테이너 즉 ApplicationConetxt가 하는데, 서버가 올라가고 ServletContext가 Initialize 되면 onRefresh 메서드에 의해 Bean이 초기화 된다. 이 때 Bean을 스캐닝해서 의존이 있다면 의존을 주입한다. 이 과정에서 플레이스 홀더에 값을 채워주는 것이다!..

그렇기 때문에 임의로 new를 이용해 인스턴스를 생성하게 되면 값 주입이 이루어 지지 않는 것이다.

 

중요한 것은 @Autowired가 아니라 플레이스 홀더가 있는 클래스가 Bean이면서 동시에 context refresh에 의해 처리 되는가 아닌가의 차이이다.

자세한 것은 Spring.io에 Properties 관련 항목을 보면 나와있다.

반응형
반응형

RestController 에서 Josn 형식으로 값을 잘 받아오던게 갑자기 안된다.

No serializer found for class org.hibernate

이런 에러가 나온다.

 

@ManyToOne에서 fetch=FetchType.LAZY 전략을 써서 

Hibernate에서 LAZY 로딩으로 인한 JSON Serialization에러가 발생한 것이라고 한다.

 

그런데 나는 fetch 설정을 한적이 없다..

심지어 @ManyToOne에서 fetch의 default 값은 EAGER 이다

 

default값

OneToMany: LAZY

ManyToOne: EAGER

ManyToMany: LAZY

OneToOne: EAGER

 

해결은

해당 Object를 JSON으로 변환하지 않는다면, @JsonIgnore 어노테이션을 nested 객체에 붙인다

@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})

 

이 방법으로 해결했다..

 

다른 방법으로는 application.properties 에 spring.jackson.serialization.fail-on-empty-beans=false

이 설정을 추가 하면 된다.

 

그런데 에러를 보이지 않게만 하는 방식이라 어떤 위험이 있을지는 모르겠다..

 

반응형
반응형

1. JPA(Java Persistence API)?

RDBMS 와 OOP 객체 사이의 불일치에서 오는 패러다임을 해결하기 위해

자바는 ORM(Object-Relational Mapping) 기술을 만들어 냈다.

문자 그대로 ORM 은 객체와 RDBMS 를 매핑하는 역할을 한다.

ORM 기술을 구현하기 위해 만들어져 사용되어 온 프레임워크가 Hibernate 이고,

시간이 지나면서 Hibernate 이외에도 ORM 기술을 구현하는 프레임워크(TopLink, CoCobase) 가 등장하였다.

그리고 이런 ORM 기술을 구현한 프레임워크에 대한 표준화가 이루어 졌는데,

그 결과로 만들어진 것이 JPA 인 것이다.

 

JDBC API 가 어플리케이션과 DMBS 사이에서 인터페이스 역할을 해 주기 때문에,

개발자는 사용할 DB 의 드라이버만 변경해 주면 되는 것처럼,

(DB 드라이버는 JDBC 표준에 맞추어 DB 관련 처리가 구현되어 있고, DB 드라이버는 각 DB 회사가 알아서 만들어 놓았다)

개발자는 ORM 을 기술을 사용할 때, JPA 인터페이스에 맞추어 구현되어 있는 

Hibernate, TopLink, CoCoBase 프레임워크 중 골라서 사용하면 된다.

만약, JPA 같은 표준 인터페이스가 없다면, 

ORM 기술을 사용하기 위한 Hibernate, TopLink, CoCoBase 의 필드와 메소드가 다를 것이다.

같은 기능을 가지는 메소드인데 Hibernate 에서는 냥냥고고( ), TopLink 에서는 멍멍고고( )로 정의되어 있다면,

사용하는 개발자가 ORM 프레임워크를 변경해야 할 때 난감할 것이다.

그래서 JPA API 가 이 기능은 통일해서 냥이최고( ) 로 구현하라고 강제하는 것이다(인터페이스의 중요 기능).

 

ORM 프레임워크를 사용하면 개발자가 객체를 데이터베이스에 저장할 때 SQL을 직접 작성할 필요 없이,

자바 컬렉션에 저장하는 것처럼 ORM 프레임워크에 저장하면 된다.

객체를 받은 ORM 프레임워크는 저장된 자바 객체를 분석해서 적절한 SQL을 생성하고 데이터베이스에 저장시킨다.  

 

2. 영속성(Persistence)

(1) Entity Class

엔티티 클래스는 자바 클래스에 @Entity 어노테이션을 붙여, 테이블과 매핑한다고 JPA 에게 알려주는 클래스다.

그리고 엔티티 클래스에서 만들어진 객체를 엔티티라고 한다.

 

(2) 영속성 컨텍스트(Persistence Context)

영속성 컨텍스트는 엔티티 클래스에서 만들어지는 엔티티를 영구 저장하고 관리하는 환경이다.

 

영속성 컨텍스트 와 관련한 엔티티의 4가지 상태

 ① 비영속(new/transient) - 엔티티 객체가 만들어져서 아직 저장되지 않은 상태로, 영속성 컨텍스트와 전혀 관계가 없는 상태

 ② 영속(managed) - 엔티티가 영속성 컨텍스트에 저장되어, 영속성 컨텍스트가 관리할 수 있는 상태

 ③ 준영속(detached) - 엔티티가 영속성 컨텍스트에 저장되어 있다가 분리된 상태로, 영속성 컨텍스트가 더 이상 관리하지 않는 상태

 ④ 삭제(removed) - 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제

 

영속성 컨텍스트의 특징

 ① 영속성 컨텍스트는 엔티티를 식별자 값(@Id로 테이블의 기본키와 매핑한 필드 값)으로 구분한다. 

     그렇기 때문에 영속 상태는 식별자 값이 반드시 있어야 한다.

 ② 영속성 컨텍스트에 엔티티를 저장하면 바로 데이터베이스에 저장되는 것이 아니라, 1차 캐시에 엔티티를 생성하고,

     쓰기 지연 SQL 저장소에 쿼리문을 생성해서 저장한다. 이렇게 쌓인 쿼리문은 flush( )가 실행될 때 데이터베이스에 반영된다.

 

(3) 엔티티 생성

1. 자바 어플리케이션에서 어떤 엔티티가 만들어져서 JPA에게 데이터베이스 저장을 부탁하면,

2. 만들어진 엔티티는 1차적으로 영속성 컨텍스트에 저장된다. 1차 캐시 정도라고 생각하면 된다.

   그리고, 저장한 엔티티를 데이터베이스에 저장하기 위한 쿼리문을 생성시켜 쓰기 지연 SQL 저장소에  저장한다.

   계속해서 엔티티를 넘기면 엔티티들과 쿼리문들은 차곡차곡 영속성 컨텍스트에 저장된다.

3. 그러다가 자바 어플리케이션에서 커밋 명령이 내려지면 영속 컨텍스트에는 자동으로 flush( )가 호출되고,

4. 영속성 컨텍스트의 변경내용을 데이터베이스와 동기(flush)화 한다(SQL 저장소의 쿼리를 실행시킨다).

5. 마지막으로 데이터베이스에게 commit 쿼리문을 명령한다.

 

 

(4) 엔티티 조회 

1. 자바 어플리케이션에서 JPA에게 데이터베이스 조회를 부탁하면,

   1차적으로 영속성 컨텍스트에서 엔티티를 찾는다. 

2. 있으면 자바 어플리케이션에 엔티티를 넘긴다.

3. 영속성 컨텍스트에 없는 엔티티 조회를 부탁하면

4. 쿼리문을 사용해 데이터베이스에서 찾아와 

5. 영속성 컨텍스트에 엔티티로 저장하고

6. 자바 어플리케이션에 그 엔티티를 넘긴다.

 

 

 

(5) 엔티티 변경

JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초의 상태를 복사해서 저장해 두는데,

이것을 스냅샷이라 한다.

 

1. 자바 어플리케이션에서 커밋 명령이 들어오면, 영속 컨텍스트에는 자동으로 flush( )가 호출되고,

2. 엔티티와 스냅샷을 비교해서 변경된 엔티티를 찾는다.

3. 변경된 엔티티가 있으면 데이터베이스에 변경사항을 저장하기 위해 쿼리를 생성하고,

4. 영속성 컨텍스트의 변경내용을 데이터베이스와 동기(flush)화 한다(SQL 저장소의 쿼리를 실행시킨다).

5. 마지막으로 데이터베이스에게 commit 쿼리문을 명령한다.

이렇게 엔티티의 변경사항을 데이터베이스에 자동으로 반영하는 기능을 변경감지(Dirty Checking)이라 한다.

 

 

(6) 엔티티 삭제

앞의 과정과 마찬가지로, 자바 어플리케이션에서 엔티티 삭제 명령이 들어오면,

엔티티를 찾고 쓰기 지연 SQL 저장소에 delete 쿼리를 생성한다.

그리고 자바 어플리케이션에서 커밋 명령이 들어오면, 자동으로 flush( )가 호출되고,

영속성 컨텍스트의 변경내용을 데이터베이스와 동기(flush)화 한다(SQL 저장소의 쿼리를 실행시킨다).

마지막으로 데이터베이스에게 commit 쿼리문을 명령한다. 

 

3. JPA 메소드

(1) flush( )

영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다.

 

실행되었을 때 일어나는 일

  ① 변경 감지가 동작해서 영속성 컨텍스트에 있는 모든 엔티티를 스냅샵과 비교해서 수정된 엔티티를 찾고,

      수정된 엔티티를 데이터베이스에 반영하기 위해 수정 쿼리를 생성하여 지연 SQL 저장소에 등록

  ② 쓰기 지연 SQL 저장소의 쿼리를 데이터 베이스에 전송(등록, 수정, 삭제 쿼리)

  

보통 직접 사용하지 않고, 자바 어플리케이션에서 커밋 명령이 들어왔을 때, 자동으로 실행된다.

 

(2) detach( )

특정 엔티티를 준영속 상태로 만든다. 

준영속 상태가 된 엔티티는 더이상 영속 컨텍스트의 관리를 받지 않으며,

영속 컨텍스트가 지원하는 어떤 기능도 동작하지 않게 된다.

영속 상태가 영속성 컨텍스트로에게 관리(managed)되는 상태라고 하면,

준영속 상태는 영속성 컨텍스트로부터 분리(detached)된 상태이다.

 

(3) clear( )

영속성 컨텍스트를 초기화 한다.

영속성 컨텍스트의 모든 엔티티를 준영속 상태로 만든다.

 

(4) close( )

영속성 컨텍스트를 종료한다.

영속성 컨텍스트가 관리하던 영속 상태의 엔티티가 모둔 준영속 상태가 된다.

 

영속 상태의 엔티티는 주로 영속성 컨텍스트가 종료되면서 준영속 상태가 된다.

개발자가 직접 준영속 상태로 만드는 일은 거의 없다.

 

(5) merge( )

준영속 상태의 엔티티의 특징

 ① 거의 비영속 상태에 가깝다. 영속성 컨텍스트가 관리하지 않으므로 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다.

 ② 식별자 값을 가지고 있다. 비영속 상태의 엔티티는 식별자(엔티티를 구분하기 위한 유일한 값, ID)를 가지지 않고 있을 수도 있지만,

     준영속 상태는 이미 한 번 영속 상태였기 때문에, 식별자 값을 가지고 있다.

 

merge( )는 준영속 상태의 엔티티를 이용해서 새로운 영속 상태의 엔티티를 반환한다.

 

실행되었을 때 일어나는 일

 ① 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티를 조회

     (1차 캐시에 엔티티가 없으면 데이터베이스에서 엔티티를 조회하고 1차 캐시에 저장)

 ② 조회한 영속 엔티티에 준영속 엔티티의 값을 채워 넣는다.

 ③ 생성된 새로운 영속 엔티티를 반환한다.

새롭게 생성된 영속 상태의 엔티티를 가지고 이제 영속성 컨텍스트가 지원하는 기능을 사용할 수 있다.

 

준영속 상태의 엔티티를 영속 상태로 변경하는 것이 아니라, 새로운 영속 상태의 엔티티를 만들어서,

준영속 상태의 엔티티 값을 영속 상태의 엔티티에 채워 넣어서 반환하는 점에 주의해야 한다.

그리고, 준영속 뿐만 아니라, 비영속 상태의 엔티티도 병합하여 새로운 영속 상태의 엔티티를 만들어 반환한다.

 

자세한 내용은 위의 엔티티 변경 참조.

 

(6) find( )

식별자 값을 가지고 엔티티를 찾아서 반환한다.

자세한 내용은 위의 엔티티 조회 참조

 

(7) persist( )

자바 어플리케이션에서 생성된 엔티티를 영속성 컨텍스트와 데이터베이스에 저장한다.

자세한 내용은 위의 엔티티 생성 참조

 

(8) remove( )

식별자 값을 가지고 엔티티를 찾아서 삭제한다.

자세한 내용은 위의 엔티티 삭제 참조



출처: https://tinkerbellbass.tistory.com/24 [Welcome to NeverLand]

반응형

'Spring Framework' 카테고리의 다른 글

[Spring JPA 에러] QuerySyntaxException is not mapped  (0) 2019.07.23
JPA 기본 사용법  (0) 2019.06.24
(STS) Spring Framework-Lombok 설치  (0) 2019.06.23
Spring MVC 라이프 사이클  (0) 2019.06.20

+ Recent posts