add 취소

git reset HEAD [file]

commit 취소

git reset HEAD^

commit message 변경

git commit --amend

https://gmlwjd9405.github.io/2018/05/25/git-add-cancle.html

 

반응형

 

ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

 

SET GLOBAL log_bin_trust_function_creators = 1;

위와 같이 설정을 변경 후 function create 다시 시도

반응형

[현상 및 에러로그]

bad SQL grammar [SELECT E.JOB_EXECUTION_ID, E.START_TIME, E.END_TIME, E.STATUS, E.EXIT_CODE, E.EXIT_MESSAGE, E.CREATE_TIME, E.LAST_UPDATED, E.VERSION, E.JOB_INSTANCE_ID, E.JOB_CONFIGURATION_LOCATION from bomdb.BATCH_JOB_EXECUTION E, bomdb.BATCH_JOB_INSTANCE I where E.JOB_INSTANCE_ID=I.JOB_INSTANCE_ID and I.JOB_NAME=? and E.START_TIME is not NULL and E.END_TIME is NULL order by E.JOB_EXECUTION_ID desc]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'E.JOB_CONFIGURATION_LOCATION' in 'field list'

 

[원인 및 해결]

spring batch 버전이 올라가면서 메타데이터 스키마가 변경되었음.

BATCH_JOB_EXECUTION_PARAMS 테이블 추가.

BATCH_JOB_EXECUTION 테이블에 JOB_CONFIGURATION_LOCATION 칼럼 추가.

 

[참고]

https://docs.spring.io/spring-batch/docs/current/reference/html/schema-appendix.html

https://stackoverflow.com/questions/25882740/unknown-column-job-configuration-location-in-field-list-while-using-spring-b

반응형

영속성 컨텍스트

- 엔티티를 영구 저장하는 환경

- 영속성 컨텍스트는 논리적인 개념으로 눈에 보이지 않음

- 엔티티 매니저를 통해 영속성 컨텍스트에 접근

 

 

생명주기

비영속(new)

영속성 컨텍스트와 관계 없는 상태

Member member = new Member();
member.setId("m1");
member.setUsername("");

영속(managed)

영속성 컨텍스트에 저장된 상태

Member member = new Member();
member.setId("m1");
member.setUsername("");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(member);

준영속(detached)

영속성 컨텍스트에 저장되었다가 분리된 상태

em.detach(member);

삭제(delete)

영속성 컨텍스트와 DB에서 삭제된 상태

em.remove(member);

 

영속성 컨텍스트가 제공하는 이점

1. JPA 의 조회시 캐시 기능

em.find(Member.class, "m1");

영속 컨텍스트(entityManager)(1차 캐시) 에서 먼저 조회

(영속 컨텍스트에 존재하지 않을시 DB에서 조회 후 영속 컨텍스트에 저장, 그리고 반환)

 

2. 영속 엔티티의 동일성 보장

Member a = em.find(Member.class, "m1");

Member b = em.find(Member.class, "m1");

System.out.println(a==b); //true

1차 캐시로 반복 가능한 읽기(REPEATABLE READ)등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공

 

 

3. 트랜잭션을 지원하는 쓰기 지원

em.persist(member); //쓰기지연 SQL 저장소, 1차 캐시에 저장

flush / commit 시 DB에 insert 쿼리를 보낸다.

 

4. 엔티티 수정시 변경 감지

Member memberA = em.find(Member.class, "m1");
memberA.setUserName("pyo");
memberA.setAge(10);

em.update(memberA); 와 같은 코드가 필요없다.

transaction.commit;

flush/commit 시점에 스냅샷을 확인하여 바뀐 값이 존재시 update 쿼리를 DB에 보낸다.

collection framework list 에서 값을 변경 후 list 에 값을 다시 넣어주지 않아도 list 값이 바뀌는 것과 마찬가지로

update 를 직접 해줄 필요가 없다.

 

JPQL 쿼리 실행시 flush가 자동으로 호출된다.

아래와 같이 flush 및 commit을 직접적으로 해주지 않을 경우 query 로 조회된 결과가 나오지 않으므로

이같은 실수를 방지하기 위해  JPQL 쿼리 실행시 flush 자동으로 호출.

em.persist(memberA);
em.persist(memberB);

query = em.createQuery("select m from Member m", member.class);
List<Member> members = query.getResultList();

flush 는 영속성 컨텍스트를 비우는게 아닌, 영속성 컨텍스트의 변경내용을 DB에 동기화

트랜잭션 작업단위가 중요. 커밋 직전에만 동기화 하면 된다.

 

준영속 상태로 만드는 방법

em.detach(memberA) 특정 엔티티만 준영속 상태로 전환

em.clear() 영속성 컨텍스트 초기화

em.close() 영속성 컨텍스트 종료

 

 

반응형

JPA에서의 연관관계 매핑

 

1. 단방향 매핑

Team 1 : User N 인 경우

User entity가 참조할 Team entity 매핑키(tid)를 넣어준다.

* 1:N 관계에서 N 테이블에 1테이블의 fk 를 가지고 있다.

  관계의 주인은 N 테이블이 된다.

 

[Sample Code]

[Team entity]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.jpp.webservice.web.domain.team;
 
import java.util.ArrayList;
import java.util.List;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
 
import com.jpp.webservice.web.domain.user.User;
 
@Entity
public class Team {
    
   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   private Long tid;
    
   private String teamNm;
 
   public Long getTid() {
      return tid;
   }
 
   public void setTid(Long tid) {
      this.tid = tid;
   }
 
   public String getTeamNm() {
      return teamNm;
   }
 
   public void setTeamNm(String teamNm) {
      this.teamNm = teamNm;
   }
}
cs

 

[User entity]

User 엔티티가 참조할 Team 의 tid 칼럼을 필드로 갖게한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.jpp.webservice.web.domain.user;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
 
@Entity
public class User {
    
   @Id
   @GeneratedValue
   private Long id;
    
   private String name;
    
   private String mobileNum;
 
   private Long tid;
    
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getMobileNum() {
      return mobileNum;
   }
   public void setMobileNum(String mobileNum) {
      this.mobileNum = mobileNum;
   }
   public Long getTid() {
      return tid;
   }
   public void setTid(Long tid) {
      this.tid = tid;
   }
    
}
cs

 

[테스트]

User 를 저장할때 tid를 넣어주어 Team과 User를 매핑해준다.

실제로 참조관계를 설정해준건 아니기 때문에 연관관계가 있다고 하긴 모호하다.

일단 tid를 기준으로 User를 조회해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.jpp.webservice.web.domain.team;
 
import java.util.List;
 
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
 
import com.jpp.webservice.web.domain.user.User;
import com.jpp.webservice.web.domain.user.UserRepository;
 
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class TeamRepositoryTest {
   
   protected static final Logger LOGGER = LoggerFactory.getLogger(TeamRepositoryTest.class);
   
   @Autowired
   TeamRepository teamRepository;
   
   @Autowired
   UserRepository userRepository;
   
   @Test
   public void test() {
      Team team = new Team();
      team.setTeamNm("vip");
      LOGGER.info("tid before save >>> " + team.getTid());    //save 를 하기 전엔 entity의 id(pk)가 생성되지 않는다
      teamRepository.save(team);
      
      Long tid = team.getTid();
      LOGGER.info("tid after save >>> " + tid); //save 를 하고 난 후 entity의 id(pk)가 생성되어 있다
      
      List<Team> teams = teamRepository.findAll();
      for(Team t : teams) {
         LOGGER.info("t nm:"+t.getTeamNm());
         LOGGER.info("id:"+t.getTid());
      }
      
      User user = new User();
      user.setMobileNum("01012345678");
      user.setName("pyo");
      user.setTid(tid);    //team entity를 save 할 때 사용한 tid를 user entity 의 fk칼럼인 tid에 넣어준다
      
      userRepository.save(user);
      List<User> users = userRepository.findByName("pyo");
      for(User u : users) {
         LOGGER.info("u nm:"+u.getName());
         LOGGER.info("u tid:"+u.getTid());
         List<User> users2 = userRepository.findByTid(u.getTid());
         for(User us : users2) {
            LOGGER.info("us : " + us.getName());
         }
      }
   }
}
cs

 

[결과]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Hibernate: 
    drop table posts if exists
Hibernate: 
    drop table team if exists
Hibernate: 
    drop table user if exists
Hibernate: 
    create table posts (
        id bigint generated by default as identity,
        author varchar(255),
        content TEXT not null,
        title varchar(500not null,
        primary key (id)
    )
Hibernate: 
    create table team (
        tid bigint generated by default as identity,
        team_nm varchar(255),
        primary key (tid)
    )
Hibernate: 
    create table user (
        id bigint generated by default as identity,
        mobile_num varchar(255),
        name varchar(255),
        tid bigint,
        primary key (id)
    )
09:53:57.773 [main] INFO  o.h.tool.hbm2ddl.SchemaExport - HHH000230: Schema export complete
 
 
 
09:54:00.266 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - tid before save >>> null
Hibernate: 
    insert 
    into
        team
        (tid, team_nm) 
    values
        (null, ?)
09:54:00.324 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - tid after save >>> 1
09:54:00.344 [main] INFO  o.h.h.i.QueryTranslatorFactoryInitiator - HHH000397: Using ASTQueryTranslatorFactory
Hibernate: 
    select
        team0_.tid as tid1_1_,
        team0_.team_nm as team_nm2_1_ 
    from
        team team0_
09:54:00.485 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - t nm:vip
09:54:00.485 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - id:1
Hibernate: 
    insert 
    into
        user
        (id, mobile_num, name, tid) 
    values
        (null, ?, ?, ?)
Hibernate: 
    select
        user0_.id as id1_2_,
        user0_.mobile_num as mobile_n2_2_,
        user0_.name as name3_2_,
        user0_.tid as tid4_2_ 
    from
        user user0_ 
    where
        user0_.name=?
09:54:00.525 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - u nm:pyo
09:54:00.525 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - u tid:1
Hibernate: 
    select
        user0_.id as id1_2_,
        user0_.mobile_num as mobile_n2_2_,
        user0_.name as name3_2_,
        user0_.tid as tid4_2_ 
    from
        user user0_ 
    where
        user0_.tid=?
09:54:00.530 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - us : pyo
 
cs

위와같이 Team 에 넣은 tid 값을 기준으로 User를 조회할 수 있다.

중요한건 DDL 부분인데, pk만 지정되었을 뿐 참조관계, 즉 fk가 설정되지 않았다. (~28 Line 까지가 DDL 이며, 참조관계가 설정되는 구문이 보이지 않는다)

참조관계를 설정해줬다기 보단 User 테이블에 Team 테이블의 pk 칼럼을 포함시켰을 뿐이다.

(코드는 마치 fk 가 잡혀있듯이 개발하고, 실제 테이블엔 fk를 설정하지 않는 것 처럼)

 

그렇다면 진짜 참조관계(fk)를 설정해보자.

 

2. 양방향 매핑

1) 테이블에서의 양방향 매핑

- 외래 키 하나로 두 테이블 연관관계 관리

- MEMBER.TEAM_ID FK키 하나로 양방향 연관관계를 가지며 양쪽으로 조인이 가능하다 

SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID

SELECT * 
FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID M.TEAM_ID

2) 객체에서의 양방향 매핑

- 객체의 양방향 관계는 Table의 양방향 관계와 달리 서로 다른 단방향 관계 2개(순환참조)로 만든다.

  (위에서 살펴본 단방향 매핑 두개가 양쪽에 있는 개념)

Class A {
  B b;
}
Class B {
  A a;
}

 

[Sample Code]

[Team entity]

List<User> users 를 넣어주었다.

mappedBy는 말 그대로 매핑이 ?에 의해 이루어 진다는 의미로 참조를 당한다는 의미다.

@OneToMany는 1:N을 의미(앞쪽의 One 은 현재 엔티티 뒷쪽의 Many는 매핑된 다른 엔티티)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.jpp.webservice.web.domain.team;
 
import java.util.ArrayList;
import java.util.List;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
 
import com.jpp.webservice.web.domain.user.User;
 
@Entity
public class Team {
    
   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   private Long tid;
    
   private String teamNm;
 
   @OneToMany(mappedBy = "team")
   private List<User> users = new ArrayList<User>();
    
   public Long getTid() {
      return tid;
   }
 
   public void setTid(Long tid) {
      this.tid = tid;
   }
 
   public String getTeamNm() {
      return teamNm;
   }
 
   public void setTeamNm(String teamNm) {
      this.teamNm = teamNm;
   }
 
   public List<User> getUsers() {
      return users;
   }
 
   public void setUsers(List<User> users) {
      this.users = users;
   }
}
 
cs

 

[User entity]

Team team을 넣어주었다.

@JoinColumn 어노테이션을 달아 주었으며 이는 외부 엔티티의 필드를 참조함을 의미한다.

@ManyToOne은 N:1을 의미 (앞쪽의 Many가 현재 entity)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.jpp.webservice.web.domain.user;
 
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
 
import com.jpp.webservice.web.domain.team.Team;
 
@Entity
public class User {
    
  @Id
  @GeneratedValue
  private Long id;
    
  private String name;
    
  private String mobileNum;
    
  @ManyToOne
  @JoinColumn
  private Team team;
    
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getMobileNum() {
      return mobileNum;
   }
   public void setMobileNum(String mobileNum) {
      this.mobileNum = mobileNum;
   }
   public Team getTeam() {
      return team;
   }
   public void setTeam(Team team) {
      this.team = team;
   }
    
}
 
cs

JPA Entity 매핑에선

1 Entity엔 @OneToMany(mappedBy= 1의 Table명)

N Entity엔 @ManyToOne @JoinColumn(id = 1의 Key)

ex) Member 1 : Order N 관계에서의 Entity 설정은 아래와 같다

@Entity

class Member {

  @OneToMany(mappedBy = "member")

   private List<Order> orders = new ArrayList<>();

}

@Entity

class Order {

  @ManyToOne @JoinColumn(name = "member_id")

  private Member member;

}

 

 

[테스트]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.jpp.webservice.web.domain.team;
 
import java.util.List;
 
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
 
import com.jpp.webservice.web.domain.user.User;
import com.jpp.webservice.web.domain.user.UserRepository;
 
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class TeamRepositoryTest {
   
   protected static final Logger LOGGER = LoggerFactory.getLogger(TeamRepositoryTest.class);
   
   @Autowired
   TeamRepository teamRepository;
   
   @Autowired
   UserRepository userRepository;
   
   @Test
   public void test1() {
      Team team = new Team();
      team.setTeamNm("vip");
      teamRepository.save(team);
      
      User user = new User();
      user.setMobileNum("01012345678");
      user.setName("pyo");
      
      team.getUsers().add(user);
      user.setTeam(team);
      
      userRepository.save(user);
   }
   
   @Test
   public void test2() {
      List<Team> teamList = teamRepository.findAll();
      for(Team t : teamList) {
         for(User u : t.getUsers()) {
            LOGGER.info("?!!");
            LOGGER.info("user name : "+u.getName());
            LOGGER.info("user team : "+u.getTeam());
         }
      }
   }
   
}
 
cs

[결과]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
16:15:34.405 [main] INFO  o.h.tool.hbm2ddl.SchemaExport - HHH000227: Running hbm2ddl schema export
Hibernate: 
    drop table posts if exists
Hibernate: 
    drop table team if exists
Hibernate: 
    drop table user if exists
Hibernate: 
    create table posts (
        id bigint generated by default as identity,
        author varchar(255),
        content TEXT not null,
        title varchar(500not null,
        primary key (id)
    )
Hibernate: 
    create table team (
        team_id bigint generated by default as identity,
        team_nm varchar(255),
        primary key (team_id)
    )
Hibernate: 
    create table user (
        id bigint generated by default as identity,
        mobile_num varchar(255),
        name varchar(255),
        team_id bigint,
        primary key (id)
    )
Hibernate: 
    alter table user 
        add constraint FKbmqm8c8m2aw1vgrij7h0od0ok 
        foreign key (team_id) 
        references team
16:15:34.431 [main] INFO  o.h.tool.hbm2ddl.SchemaExport - HHH000230: Schema export complete
 
Hibernate: 
    insert 
    into
        team
        (team_id, team_nm) 
    values
        (null, ?)
Hibernate: 
    insert 
    into
        user
        (id, mobile_num, name, team_id) 
    values
        (null, ?, ?, ?)
16:15:37.128 [main] INFO  o.h.h.i.QueryTranslatorFactoryInitiator - HHH000397: Using ASTQueryTranslatorFactory
Hibernate: 
    select
        team0_.team_id as team_id1_1_,
        team0_.team_nm as team_nm2_1_ 
    from
        team team0_
Hibernate: 
    select
        users0_.team_id as team_id4_2_0_,
        users0_.id as id1_2_0_,
        users0_.id as id1_2_1_,
        users0_.mobile_num as mobile_n2_2_1_,
        users0_.name as name3_2_1_,
        users0_.team_id as team_id4_2_1_ 
    from
        user users0_ 
    where
        users0_.team_id=?
16:15:37.264 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - ?!!
16:15:37.264 [main] INFO  c.j.w.w.d.team.TeamRepositoryTest - user name : pyo
cs

참조 조건이 설정됨을 확인할 수 있다. (31~34 line)

Team 에서 User를 조회할 수 있다.  (반대의 경우도 가능하다)

 

 

Owner : 연관관계의 주인

객체의 두 관계 중 하나를 연관관계의 주인으로 지정

연관관계의 주인만이 외래키를 관리(등록, 수정)

주인이 아닌 쪽은 읽기만 가능

주인은 mappeedBy 속성 사용하지 않음

주인이 아니면 mappedBy 속성으로 주인 지정

 

※ 일반적인 설계

위 예에서 User가 연관관계의 주인, 반대편인 Team은 가짜매핑(조회를 편하게 하기위한)

설계시 User의 Team을 주인으로 정한다. fk 키를 가지고 있는 칼럼을 주인으로 정해야 혼란을 방지할 수 있다.

 

※ 기타

양방향 매핑은 사실 필요가 없다.

조회를 편하게 하기 위함일 뿐, 일반적으론 단방향 매핑 관계만 적용하여 설계한다.

반대방향으로 조회가 필요한 경우, 그 때 양방향 관계(mappedBy)를 추가한다.

그리고 설계시 연관관계의 주인(JoinColumn)은 fk 키를 가지고 있는 entity의 필드를 주인으로 삼는다.

 

참고 :

Tacademy 김영한 개발자님의 강의

김영한 개발자님의 JPA 저서

https://www.baeldung.com/jpa-join-column

반응형

'back > JPA' 카테고리의 다른 글

[JPA] equals , hashcode  (0) 2022.11.08
[JPA] JPQL, QueryDSL  (0) 2020.03.21
[JPA] JPA 영속성 컨텍스트  (0) 2020.03.08
[JPA] JPA 기초 설정 및 entity 필드 매핑  (0) 2020.02.27
[JPA] JPA란? : 등장배경, ORM, 하이버네이트  (0) 2020.02.23

@Autowired

Type --> 이름 --> Qualifier --> fail

@Resource

이름 --> Type --> Qualifier --> fail

@Inject

Type --> Qualifier --> 이름 --> fail

 

https://engkimbs.tistory.com/682

반응형

- JPA 는 특정 데이터베이스에 종속적이지 않음

- dialect interface 를 구현하는 MySQLDialect, OracleDialect H2Dialect 등이 존재

(dialect : SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능(ROWNUM(ORACLE) vs LIMIT(Mysql)))

- h2 : 크기가 작은 메모리 DB, 테스트용으로 사용

 

[pom.xml (dependency)]

org.hibernate.hibernate-entitymanager dependency필요(해당 dependency가 jpa.persistence-api, hibernate-core 땡겨옴)

 

[persistence.xml]

jpa 설정을 위한 persistence.xml가 필요(spring fw기준)(boot는 yml 혹은 property에 작성)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version=“2.2">
     <persistence-unit name="hello">
         <properties>
             <!-- 필수 속성 -->
             <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
             <property name="javax.persistence.jdbc.user" value="sa"/>
             <property name="javax.persistence.jdbc.password" value=""/>
             <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
             <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
             <!-- 옵션 -->
             <property name="hibernate.show_sql" value="true" />
             <property name="hibernate.format_sql" value="true" />
             <property name="hibernate.use_sql_comments" value="true" />
             <property name="hibernate.id.new_generator_mappings" value="true" />
             <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
         </properties>
     </persistence-unit>
</persistence>
cs

* hibernate.hbm2ddl.auto (hibernate.ddl-auto) 옵션

create : 기존테이블 삭제 후 다시 생성

create-drop : create와 같으나 종료 시점에 테이블 drop

update : 변경분만 반영

validate : 엔티티와 테이블 정상 매핑인지만 확인

none : 사용하지않음

* 환경별 옵션 사용

개발 초기(create, update)

테스트서버 (update, validate)

운영서버 (validate, none)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Entity
public class Member {
    @Id
    private Long id;
    
    @Column(name = "USERNAME")
    private String name;
    
    private int age;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date regDate;
    
    @Enumerated(EnumType.STRING)
    private MemberType memberType;
}
cs

@Entity (javax.persistence)

: JPA로 관리할 객체

@Id

: DB PK와 매핑 할 필드 ( * 보통 auto_increment 로 설계)

@Column

- name : 필드와 실제로 매핑할 테이블의 칼럼명(테이블 칼럼명이 필드와 다를 경우 사용)

- nullable : null허용

- unique : 유니크제약

- length 등..

@Temporal(TemporalType.DATE)

: 날짜타입매핑

@Enumerated

: 열거형 매핑

- EnumType.ORDINAL : 순서 저장(default)

- EnumType.STRING : 열거형 이름 그대로 저장 (ordinal 대신 string 사용할 것)

@Lob

: CLOB, BLOB 알아서 매핑

CLOB : char[]

BLOB : byte[]

@Transient

: DB에 저장하지 않는 Column(앱단에서만 사용)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String args[]) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");    //factory는 하나만 생성하여 애플리케이션 전체에서 공유
    EntityManager em = emf.createEntityManager();    //요청마다 manager 생성하여 사용
    EntityTransaction tx = em.getTransaction();    //transcation
    tx.begin();
    try {
         Member member = new Member();
         member.setId(1L);
         member.setName("hello");
         em.persist(member);
         tx.commit();
    } catch (Exception e) {
        tx.rollback();
    } finally {
        em.close();
    }
    emf.close();
}
cs

 

 

반응형

'back > JPA' 카테고리의 다른 글

[JPA] equals , hashcode  (0) 2022.11.08
[JPA] JPQL, QueryDSL  (0) 2020.03.21
[JPA] JPA 영속성 컨텍스트  (0) 2020.03.08
[JPA] 연관관계 매핑 : 단방향, 양방향 매핑  (0) 2020.03.01
[JPA] JPA란? : 등장배경, ORM, 하이버네이트  (0) 2020.02.23

 

 

객체지향의 사실과 오해

1. 객체엔 property가 존재, property는 단순값인 attribute와 타 객체를 참조하는 link로 나누니다

2. 엔티티는 참조객체를 의미한다

3. 객체를 설계할 땐 상태(필드) 보다 행동을 중심으로 설계해야 한다

4. 추상화 지형 그대로 그려놓은 지하철 노선도 vs 역과 환승을 추상화한 지하철 노선도

- 공통점을 취하고 차이점을 버린다

- 복잡성을 줄이고 단순화

- 동일한 행동은 동일한 책임 수행, 동일한 타입에 속하며 내부 표현 방식은 다를 수 있다.

- 동일한 책임은 동일한 메시지(파라미터)를 수신하며 내부 처리방식(메소드 내부 내용)은 다를 수 있다

- 책임주도설계(responsibility driven design)

  : 제공할 행동을 머저 생각 및 결정 후 행동(책임) 수행에 필요한 데이터를 생각하고

    그 데이터는 인터페이스 뒤로 캡슐화 한다

- 객체를 분류하는 기준은 타입이며 타입을 나누는 기준은 객체가 수행하는 행동이다

 

 

개발언어나 기술에 대해 깊이 다루기 보단 객체지향이라는 개념을 추상적으로 다룬 책. 

객체지향에 대해 최대한 쉬운 예로 설명하는 책.

2020.02.23

반응형

'etc. > books' 카테고리의 다른 글

[Book] HTTP 완벽 가이드  (0) 2020.03.17
[Book] 소프트웨어 장인  (0) 2020.01.16
[Book] Clean Code (클린 코드)  (0) 2019.12.28
[Book] 프로그래머의 길, 멘토에게 묻다  (0) 2019.11.22
[Book] Head First : Design Patterns  (2) 2019.06.04

기존 개발방식(mybatis)의 문제

- 물리적으로 코드가 분리되어있지만 논리적인 분리는 이루어 지지 않음

- sql 에 의존적인 개발

- 유지보수의 문제(칼럼 추가 수정 삭제시 sql, 코드 수정 양이 큼)

- 패러다임 불일치 문제

   : a 테이블을 참조하고 있는 b 테이블,

    b 테이블에 데이터를 넣을 때 a 테이블에도 데이터를 넣어줘야 참조관계가 깨지지 않음

 

 

JPA 

: Java Persistence API

- 자바 진영의 ORM 기술 표준

 

ORM

: Object-relational mapping(객체 관계 매핑)

- 객체는 객체대로 설계, 관계형 데이터베이스는 관계형 데이터베이스대로 설계

- ORM 프레임워크가 이 둘을 중간에서 매핑

 

JPA는 애플리케이션과 DB 사이에 있다

JAVA APP <> JPA <> JDBC API <> DB

 

JPA는 인터페이스, 하이버네이트는 JPA의 구현체

 

동작순서(저장)

1. MemberDAO

2. PERSIST(entity)

3. JPA : Entity 분석, Insert ql 생성, JDBC API 사용, 패러다임 불일치 문제 해결

4. DB insert

* 패러다임 불일치 문제 : a 테이블을 참조하고 있는 b 테이블, b 테이블에 데이터 넣을 때 a 테이블에도 데이터를 넣어줘야 참조관계가 깨지지 않음

 

동작순서(조회)

MemberDAO

find(id)

JPA : SELECT SQL 생성, JDBC API 사용, ResultSet매핑, 패러다임 불일치 문제 해결

4. DB select

5. Entity Object 반환

 

JPA의 CRUD

저장 : jpa.persist(member)

조회 : Member member = jpa.find(memberId)

수정: member.setName("~")

삭제: jpa.remove(member)

 

 

반응형

'back > JPA' 카테고리의 다른 글

[JPA] equals , hashcode  (0) 2022.11.08
[JPA] JPQL, QueryDSL  (0) 2020.03.21
[JPA] JPA 영속성 컨텍스트  (0) 2020.03.08
[JPA] 연관관계 매핑 : 단방향, 양방향 매핑  (0) 2020.03.01
[JPA] JPA 기초 설정 및 entity 필드 매핑  (0) 2020.02.27

File

named collection (메모리는 주소를 통한 접근)

비휘발성의 보조기억장치에 저장

운영체제는 다양한 저장 장치를 file 이라는 동일한 논리적 단위로 볼 수 있게 해 줌

Operation 종류 : create, read, write, reposition, delete, open, close

File attribute (metadata)

파일 이름, 유형, 저장위치, 파일사이즈, 접근권한, 시간(생성/변경/사용), 소유자과 같은

파일 자체의 내용이 아니라 파일을 관리하기 위한 각종 정보들

File system

운영체제에서 파일을 관리하는 부분

파일 및 파일의 메타데이터, 디렉토리 정보

파일의 저장 방법 결정

파일 보호

Directory

파일의 메타데이터 중 일부를 보관하고 있는 일종의 특별한 파일

그 디렉토리에 속한 파일 이름 및 파일 attribute들

Operation 종류 : search for a file, create a file, delete a file, list a directory, rename a file, traverse the file system

Partition(=Logical Disk)

하나의 물리적 디스크 안에 여러 파티션을 두는게 일반적

여러 개의 물리적인 디스크를 하나의 파티션으로 구성하기도 함

물리적 디스크를 파티션으로 구성한 뒤 각각의 파티션에 file system을 깔거나 swapping 등 다른 용도로 사용 가능

 

open()

파일의 메타데이터를 메모리로 올린다.

1) fd = open("/a/b") : 프로그램이 b 메타데이터 정보를 요청

2) 시스템콜을 하여 CPU를 운영체제에 넘긴다.

3) CPU가 root 메타데이터를 먼저 메모리에 올린다(root 메타데이터의 디렉토리는 이미 알고 있음)

4) root 메타데이터를 연다

5) root 메타데이터에 존재하는 a 메타데이터의 파일시스템상 위치정보로 디스크에서 a의 메타데이터를 가져와 메모리에 올린다

6) a의 메타데이터를 연다

7) a의 메타데이터에 존재하는 a content의 파일시스템상 위치정보로 디스크에서 a의 content 안에 존재하는 b의 메타정보를 가져와 메모리에 올린다

8) b의 메타정보를 가리키는 포인터의 인덱스(파일 디스크립터) 값을 리턴

9) read(fd...) : 프로그램이 b content 정보 요청(읽기)

10) 읽은 내용을 사용자 프로그램(Process A)에 직접 주는게 아닌, 커널 메모리 영역(buffer cache)으로 가져온다

11) 사용자 메모리영역(Process A)엔 그 내용을 카피해서 준다.

※ 만약 다른 프로그램(Process B)에서 b의 content 를 요청한다면 운영체제가 buffer cache에서 전달해준다 

※ File System 의 Buffer cache 환경에선 운영체제가 모든 정보를 알고 있으므로(파일 시스템 접근시 시스템 콜을 통해 제어권이 CPU로 넘어오므로) LRU, LFU 알고리즘을 사용할 수 있다. 

※ per-process file descriptor table : 파일 디스크립터 테이블은 프로세스마다 따로 존재

system-wide open file table : system wide 로 전체 시스템에 한개로 관리되지만 각각의 프로그램들이 파일의 offset을 프로그램 별로 관리하기 위한 공간(table)은 따로 존재

 

File Protection

1. Access control matrix : linked list 형태로 권한 관리 (overhead가 큼)

Access control list : 파일별로 누구에게 어떤 접근 권한이 있는지 표시

Capability list: 사용자별 자신이 접근 권한을 가진 파일 및 해당 권한 표시

2. Grouping

전체 user를 owner, group, public의 세그룹으로 구분

각 파일에 대해 세그룹의 접근 권한(rwx)을 3비트씩 표시

UNIX를 포함한 대부분의 OS에서 사용

3. Password

파일마다 password를 두는 방법

rwx 마다 password를 하나씩 부여해야하므로 관리가 어려움

 

File System의 Mounting

파티션을 통해 여러개의 논리적 디스크로 분리된 하나의 물리적 디스크

각각의 논리적 디스크에 file system 존재

다른 파일시스템에 접근할 경우 mount 사용

disk3의 루트를 disk1의 usr 경로에 연결(mount)하여 타 파일시스템 접근이 가능

 

 

※ 이화여대 반효경 교수님의 운영체제 강의 정리

반응형

+ Recent posts