테이블과 매핑 예
실제모델
@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에 추가됨
'신세계 - Spring 공부' 카테고리의 다른 글
19주차 배운점 - JPA 매핑, 식별자 (0) | 2024.09.24 |
---|---|
19주차 배운점 - JPA 설정, CRUD (0) | 2024.09.24 |
16주차 배운점 - 스프링 부트, ORM, 하이버네이트 (1) | 2024.09.24 |
15주차 배운점 - Spring mybatis Todo 프로그램 (테이블 페이징) (0) | 2024.09.24 |
15주차 배운점 - Spring mybatis Todo 프로그램 (CRUD) (0) | 2024.09.24 |