Java&Spring/Spring

JPA 영속성 컨텍스트

sung.hyun.1204 2022. 9. 1. 14:55

 

 

영속성 컨텍스트 = 엔티티를 저장 하는 환경

 

정의:  Domain 에서 정의 한다.

엔티티(Entity) =  개체 , 데이터의 집합 , 저장 관리 되는 대상.

--- JPA ----

Spring 에서는 Entity 어노테이션을 붙임으로 정의를 한다 .

1. 모든 Entity 는 pk 를 가지고 있어야한다. @GeneratedValue 를 이용하여 identifier 의 정의 방법을 설정 할 수 있다.

2.

 

ex)

package hackathon.nomadworker.domain;


import com.fasterxml.jackson.annotation.JsonIgnore;
import org.locationtech.jts.geom.Point;
import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;




@Entity
@Getter
@Setter
public class Place {

        @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "p_id")
        private long id;

        private String p_cate;

        private String p_name;

        private String p_weekt;

        private String p_weekndt;

        private float p_grade;

        private int p_count;

        @Column(name = "p_addr")
        private String p_addr;

        private String p_image;

        private String p_storeType;

        private String rent_price;

        private float p_latitude;

        private float p_longitude;

        private Point p_gpoint;

        @JsonIgnore
        @OneToMany(mappedBy = "place", cascade = CascadeType.ALL)
        private List<Feed> feedList = new ArrayList<>();

        @OneToMany(mappedBy = "place", cascade = CascadeType.ALL)
        private List<User_Place> user_placeList = new ArrayList<>();
        public void addFeed(Feed feed)
        {
                this.feedList.add(feed);
                feed.setPlace(this);
        }
}

 

 

주의 사항 : 

The name must not be a reserved literal in the Jakarta Persistence query language. 

@Entity 인터페이스의 주석을 참고하면 확인이 가능하다.( 인터페이스라 껍데기만 있다 .)

 

사용 :

주로 Repository 에서 사용한다

package hackathon.nomadworker.repository;

import hackathon.nomadworker.domain.Feed;

import hackathon.nomadworker.domain.Place;

import hackathon.nomadworker.util.Direction;
import hackathon.nomadworker.util.GeometryUtil;
import hackathon.nomadworker.util.Location;
import lombok.RequiredArgsConstructor;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;


import javax.persistence.Query;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.text.DecimalFormat;
import java.util.List;

@Repository
@RequiredArgsConstructor
public class PlaceRepository {

    @Autowired
    private final EntityManager em;

    public Place post(Place place)
    {
        em.persist(place);

        // make point
        return place;
    }

    public Place getPlacesById(Long id) {
        return em.find(Place.class, id);
    }

    public List<Place> findAll() {
        return em.createQuery("select p from Place p", Place.class)
                .getResultList();
    }

    public List<Place> findOneByNickName(String placeName) {
        String jpql = "select p from Place p where p.p_name like :placeName";
        TypedQuery<Place> query = em.createQuery(jpql, Place.class).setParameter("placeName", placeName).setMaxResults(1000);
        return query.getResultList();
    }


    public List<Place> findPlacesByCategory(String place_cat) {
        String jpql = "select p from Place p where p.p_cate like :place_cat";
        TypedQuery<Place> query = em.createQuery(jpql, Place.class).setParameter("place_cat",place_cat).setMaxResults(1000);
        return query.getResultList();
    }


    public List<Place> getNearByCoordinate(Double latitude, Double longitude, Double distance)
    {
        Location northEast = GeometryUtil
                .calculate(latitude, longitude, distance, Direction.NORTHEAST.getBearing());
        Location southWest = GeometryUtil
                .calculate(latitude, longitude, distance, Direction.SOUTHWEST.getBearing());

        double x1 = northEast.getLatitude();
        double y1 = northEast.getLongitude();
        double x2 = southWest.getLatitude();
        double y2 = southWest.getLongitude();

        String pointFormat = String.format("'LINESTRING(%f %f, %f %f)')", x1, y1, x2, y2);
        Query query = em.createNativeQuery("SELECT * \n"+
                "From place As p \n" +
                "WHERE MBRContains(ST_LINESTRINGFROMTEXT(" + pointFormat + ",p.p_gpoint)",Place.class).setMaxResults(15);

        List<Place> places = query.getResultList();
        return places;
    }

    public List<Feed> getRecommendPlace()
    {
        List<Feed> feed =  em.createQuery("select f from Feed f " +
                        "join fetch f.place p " +
                        "order by f.f_like desc ", Feed.class).setMaxResults(10).getResultList();
        return feed;
    }
/*
    public List<Place> searchPlace(String p_cate, String p_storeType, String p_name)
    {
        List<Place> place = em.createQuery("select p from Place p " +
                        "where p.p_cate =: p_cate " +
                        "and p.p_storeType =: p_storeType " +
                        "and p.p_name =: p_name ", Place.class)
                .setParameter("p_cate", p_cate)
                .setParameter("p_storeType", p_storeType)
                .setParameter("p_name", p_name)
                .getResultList();

        return place;
    }
*/

    public List<Place> searchPlace(String p_cate, String p_storeType, String p_name)
    {
        String jpql = "select p from Place p where p.p_cate =: p_cate and p.p_storeType =: p_storeType and p.p_name like :p_name";
        TypedQuery<Place> query = em.createQuery(jpql, Place.class)
                .setParameter("p_cate", p_cate)
                .setParameter("p_storeType", p_storeType)
                .setParameter("p_name", "%" + p_name + "%").setMaxResults(1000);
        return query.getResultList();
    }

    public List<Place> searchOneByName(String p_name) {
        String jpql = "select p from Place p where p.p_name like :p_name";
        TypedQuery<Place> query = em.createQuery(jpql, Place.class).setParameter("p_name", "%" + p_name +  "%").setMaxResults(1000);
        return query.getResultList();
    }

    public Place gradePlace(Long p_id){
        return em.find(Place.class, p_id);
    }

    public void setgradePlace(Long p_id, float p_grade, Integer p_count) {
        Place place  = em.find(Place.class, p_id);
        p_grade = (float)(Math.round(p_grade * 10) / 10.0);
        place.setP_grade(p_grade);
        place.setP_count(p_count);
        em.merge(place);
    }
}

 

Entity Life cycle 

 

  • 비영속(new/transient): 영속성 컨텍스트와 전혀 관계가 없는 상태
  • 영속(managed): 영속성 컨텍스트에 저장된 상태
  • 준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태

준영속 상태의 특징 

1차 캐시 쓰기지연, 변경감지 , 지연 로딩을 포함한 영속성 컨텍스트가 제공히는 어떠한 기능도 동작 x ,

식별자의 값을 가지고 있다. 

 

비영속  :  엔티티 객체를 생성했지만 아직 영속성 컨텍스트에 저장하지않은 상태  

ex ) Place place =  new Place();

 

영속  : 엔티티 매니저를 통해 엔티티를 영속성 컨텍스트에 저장한 상태 ,

ex) em.persist(place);

 

준영속  :영속성 컨텍스트가 관리하던 영속 상태의 엔티티 더이상 관리 하지 않으면 준영속 상태라 부른다.

ex)

// 엔티티를 영속성 컨텍스트에서 분리한후 준영속 상태로 만든다.
em.detach(place);
// 영속성 콘텍스트를 비워도 관리되던 엔티티는 준영속 상태가 된다.
em.claer();
// 영속성 콘텍스트를 종료해도 관리되던 엔티티는 준영속 상태가 된다.
em.close();

 

삭제 : 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제 한다. 

em.remove(place);

 

영속성 컨텍스트의 특징 .

 

영속성 컨텍스트의 식별자 값, 

 

영속성 컨텍스트는 엔티티를 식별자 값으로 구분한다.  

 

영속성 컨텍스트를 DB에 저장 . 

 

JPA는 보통 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 DB 에 반영 하는데 이를 flush 라고 한다. 

 

 

 

 

 

 

참고 : 

https://velog.io/@neptunes032/JPA-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%9E%80