본문 바로가기

신세계 국비과정/신세계 - Spring 공부

19주차 배운점 - JPA @Embeddable, 컬렉션 Set 매핑

728x90
반응형

 

테이블과 매핑 예

 

 

 

실제모델

 

 

 

@Embeddable


엔티티가 아닌 타입을 한 개 이상의 필드와 매핑할 때 사용
예: Address, Money 등 매핑
엔티티의 한 속성으로 @Embeddable 적용 타입 사용

 

저장

 

 

객체를 생성자에 넣어줘도 insert 잘 됨

 

 

 

조회

 

 


하나의 객체로 관리됨 인베더블 클래스를 부품처럼!!

 

 

null

 

 

 

@AttributeOverride 설정 재정의
이름 다르게 사용, 매핑을 하나씩 따로

 

 

 

Hotel

 

@Entity
@Table(name = "hotel_info")
public class Hotel {
    @Id
    @Column(name = "hotel_id")
    private String id;

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

    private int year;

    @Enumerated(EnumType.STRING)
    private Grade grade;

    @Embedded
    private Address address;

    private LocalDateTime created;

    @Column(name = "modified")
    private LocalDateTime lastModified;

    protected Hotel() {
    }
    .
    .

 

 

Address


@Embeddable 사용

 

@Embeddable // 어노테이션
public class Address {
    
    @Column(name = "addr1")
    private String address1;

    @Column(name = "addr2")
    private String address2;

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

    protected Address() {
    }

 

 

MainEmbeddable

 

public class MainEmbeddable {
    private static Logger logger = LoggerFactory.getLogger(MainEmbeddable.class);

    public static void main(String[] args) {
        EMF.init();
        saveHotel();
        printHotel();
        EMF.close();
    }

    private static void saveHotel() { // 저장
        EntityManager em = EMF.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        Address address = new Address("창원시", "의창구", "342");
        Hotel hotel = new Hotel("H00", "HN", 2022, Grade.S7, address);
        try {
            tx.begin();
            em.persist(hotel);
            tx.commit();
        } catch (Exception ex) {
            tx.rollback();
            throw ex;
        } finally {
            em.close();
        }
    }

    private static void printHotel() { // 단건 조회

        EntityManager em = EMF.createEntityManager();
        EntityTransaction tr = em.getTransaction();
        try{
            tr.begin();
            Hotel hotel = em.find(Hotel.class, "H00");

            tr.commit();
            logger.info(hotel.toString());
        }catch (Exception e){
            tr.rollback();
            throw e;
        }
        finally {
            em.close();
        }
    }
}

 

 

이거 추가해줘야함


persistance.xml

 

<persistence-unit name="jpabegin" transaction-type="RESOURCE_LOCAL">
        <class>jpabasic.employee.domain.Employee</class>
        <class>jpabasic.reserve.domain.Hotel</class>
        <class>jpabasic.reserve.domain.Member</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>

 

 

단순 값을 Set으로 보관하는 모델

 

 

 

Role에다가 @ElementCollection 어노테이션 사용
컬렉션테이블 만들어주고 role_id 연결해줌

 

@Column 어노테이션 해서 Set<String> ..

 

 

 

저장

 

 

 

조회(lazy)

 

 

 

Role

 

@Entity
// 엔티티 클래스로서 데이터베이스의 'role' 테이블에 매핑됩니다.
@Table(name = "role")
public class Role {
    @Id
    // 'id' 필드를 테이블의 기본 키로 지정합니다.
    private String id;
    
    // 'name' 필드는 역할의 이름을 저장합니다. 테이블의 'name' 컬럼과 자동 매핑됩니다.
    private String name;

    @ElementCollection
    // 'permissions'는 별도의 테이블 'role_perm'에 저장됩니다.
    // 이 컬렉션은 Role 엔티티와 1:N 관계를 형성합니다.
    @CollectionTable(
            name = "role_perm", // 컬렉션 데이터가 저장될 테이블 이름입니다.
            joinColumns = @JoinColumn(name = "role_id") // Role 엔티티와 연결될 외래 키 컬럼을 지정합니다.
    )
    @Column(name = "perm") // 컬렉션 내 각 요소가 매핑될 컬럼의 이름입니다.
    private Set<String> permissions = new HashSet<>(); // 권한 목록을 저장하는 Set 컬렉션입니다.

    // 기본 생성자를 protected로 설정하여 직접적인 인스턴스 생성을 제한하고,
    // JPA 프로바이더만이 이 클래스의 인스턴스를 생성할 수 있게 합니다.
    protected Role() {}
    
      public void revokeAll() {
        this.permissions.clear(); // SELECT -> DELETE
        // this.permissions = new HashSet<>(); // DELETE
    }
    
    ,
    ,
    

 

 

sql

 

create table jpabegin.role (
  id varchar(20) not null primary key,
  name varchar(100)
) engine innodb character set utf8mb4;

create table jpabegin.role_perm (
  role_id varchar(20),
  perm varchar(50),
  grantor varchar(50),
  primary key (role_id, perm)
) engine innodb character set utf8mb4;

 

 

RoleMain

 

public class MainRole {
    // 로거 설정. 이 클래스의 모든 중요한 동작을 로깅할 수 있습니다.
    private static Logger logger = LoggerFactory.getLogger(MainRole.class);

    public static void main(String[] args) throws Exception {
        clearAll();  // 모든 역할과 권한을 데이터베이스에서 삭제합니다.
        EMF.init();  // EntityManagerFactory 초기화
        String roleId = "R07";
        saveRole(roleId);  // 새로운 역할 저장
        readRole(roleId);  // 저장된 역할 읽기
        updateRoleByModifyingCollection(roleId);  // 역할의 권한 수정
        String roleId2 = "R19";
        saveRole(roleId2);  // 또 다른 역할 저장
        updateRoleByAssigningNewSet(roleId2);  // 새 권한 세트로 역할 수정
        revokeRole(roleId2);  // 역할의 모든 권한 회수
    }

 

 

    // 데이터베이스에서 모든 역할과 권한을 삭제하는 메소드
    private static void clearAll() throws SQLException {
        try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/jpabegin?characterEncoding=utf8",
                "jpauser",
                "jpapass");
             Statement stmt = conn.createStatement()
        ) {
            stmt.executeUpdate("delete from role_perm where role_id != ''");  // role_perm 테이블에서 모든 데이터 삭제
            stmt.executeUpdate("delete from role where id != ''");  // role 테이블에서 모든 데이터 삭제
        }
    }
    

 

 

    // 주어진 ID로 새 역할을 생성하고 저장하는 메소드
    private static void saveRole(String roleId) {
        logger.info("saveRole");
        EntityManager em = EMF.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            Role role = new Role(roleId, "관리자", Set.of("F1", "F2"));  // 새 Role 인스턴스 생성
            em.persist(role);  // 역할을 데이터베이스에 저장
            tx.commit();
        } catch (Exception ex) {
            tx.rollback();  // 오류 발생 시 롤백
            throw ex;
        } finally {
            em.close();  // EntityManager 리소스 해제
        }
    }

 

 

16:01:21.986 [main] INFO main.MainRole - saveRole
16:01:22.037 [main] DEBUG org.hibernate.SQL - insert into role (name, id) values (?, ?)
16:01:22.050 [main] DEBUG org.hibernate.SQL - insert into role_perm (role_id, perm) values (?, ?)
16:01:22.052 [main] DEBUG org.hibernate.SQL - insert into role_perm (role_id, perm) values (?, ?)

 

    // 주어진 ID의 역할을 읽어와 로그에 기록하는 메소드
    private static void readRole(String roleId) {
        logger.info("readRole");
        EntityManager em = EMF.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            Role role = em.find(Role.class, roleId);  // 역할 검색
            logger.info("role id: {}", role.getId());
            for (String perm : role.getPermissions()) {
                logger.info("perm: {}", perm);  // 권한 로깅
            }
            tx.commit();
        } catch (Exception ex) {
            tx.rollback();  // 오류 발생 시 롤백
            throw ex;
        } finally {
            em.close();  // EntityManager 리소스 해제
        }
    }

 

16:01:22.058 [main] INFO main.MainRole - readRole
16:01:22.079 [main] DEBUG org.hibernate.SQL - select r1_0.id,r1_0.name from role r1_0 where r1_0.id=?

 

    // 역할의 권한 컬렉션을 수정하는 메소드
    private static void updateRoleByModifyingCollection(String roleId) {
        logger.info("updateRoleByModifyingCollection");
        EntityManager em = EMF.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            Role role = em.find(Role.class, roleId);  // 역할 검색
            role.getPermissions().add("F3");  // 권한 추가
            role.getPermissions().remove("F1");  // 권한 제거
            tx.commit();
        } catch (Exception ex) {
            tx.rollback();  // 오류 발생 시 롤백
            throw ex;
        } finally {
            em.close();  // EntityManager 리소스 해제
        }
    }

 

 

    // 새 권한 세트를 할당하여 역할을 업데이트하는 메소드
    private static void updateRoleByAssigningNewSet(String roleId) {
        logger.info("updateRoleByAssigningNewSet");
        EntityManager em = EMF.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            Role role = em.find(Role.class, roleId);  // 역할 검색
            role.setPermissions(Set.of("F4", "F5"));  // 새 권한 세트 할당
            tx.commit();
        } catch (Exception ex) {
            tx.rollback();  // 오류 발생 시 롤백
            throw ex;
        } finally {
            em.close();  // EntityManager 리소스 해제
        }
    }

 

 

    // 주어진 역할의 모든 권한을 회수하는 메소드
    private static void revokeRole(String roleId) {
        logger.info("revokeRole");
        EntityManager em = EMF.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            Role role = em.find(Role.class, roleId);  // 역할 검색
            role.revokeAll();  // 모든 권한 회수
            tx.commit();
        } catch (Exception ex) {
            tx.rollback();  // 오류 발생 시 롤백
            throw ex;
        } finally {
            em.close();  // EntityManager 리소스 해제
        }
    }
}

 

 

Role 테이블

 

 

 

 

Roleparam 테이블
getPermissions().add("F3") 했더니 테이블에 R07에 추가됨

 

 

 
반응형