당니의 개발자 스토리
JPA 소개 본문
JPA 소개
이번 시간에는 이제 JPA에 대해서 본격적으로 소개를 해드리겠습니다.

JPA는 뭐냐면 Java Persistence API 라는 것의 줄임말인데요. 이게 Java 진영의 ORM 기술 표준입니다. 그러면 '어? ORM은 뭐지?'

ORM은 Object Relational Mapping 입니다. 그러니까 객체 관계 맵핑 이라는 건데, R은 우리가 RDB 할 때, 그러니까 관계형 DB 할 때의 그 R입니다. 그러니까 이게 객체랑 관계형 데이터베이스랑 맵핑을 해준다는 뜻이에요. 그래서 이 맵핑이라는 건 중간에서 뭔가를 해준다는 거거든요. 그래서 우리가 ORM 이라는 걸 쓰게 되면 객체는 객체대로 설계를 해요. 그리고 관계형 데이터베이스 테이블은 또 관계형 데이터베이스로 쫙 설계를 해요. 그럼 중간에서 이 ORM 프레임워크가 객체와 관계형 데이터베이스 간의 다른 부분들을 맵핑을 해서 해결을 해준다는 거예요.
그래서 패러다임의 불일치나 이런 걸 해결을 해준다는 거고요. 대중적인 언어에는 대부분 ORM 기술이 존재합니다. Java 뿐만 아니라 .NET이나 등등 나머지 다른 언어들에도 대중적인 데는 대부분 ORM이 있습니다.
자 여러분 JPA는 뭐냐면,

애플리케이션과 JDBC 사이에서 동작을 해요. 그러니까 막 JPA라는 게 뭔가 완전 새로운 기술이 아니고, 새롭긴 하지만 완전 처음부터 뭔가 쌓아올린다기보다는 결국 우리가 java 애플리케이션에서 db랑 통신 할려면 jdbc api를 써야 되죠. 그래서 원래는 개발자가 직접 jdbc api를 썼다면 이제는 그거를 jpa가 대신 쓴다고 생각하시면 됩니다. 마치 여기까지만 보면 뭔가 JdbcTemplate이나 MyBatis 같은 것들이랑 비슷하죠. 근데 그런 프레임 워크랑 큰 차이가 뭐냐면,

이겁니다. 여러분 jpa는 예를 들어서 우리가 Member 객체를 저장한다고 생각해 볼게요. 그러면 Member 객체를 memberDAO에 넘기고 memberDAO가 JPA에게 Member 엔티티를 던집니다. JPA에서는 이런 것을 엔티티라고 하거든요. 그러니까 'JPA야 Member 회원 객체를 저장해줘!' 라고 JPA에 던지기만 하면 JPA가 알아서 이 회원 객체를 분석을 합니다. 그래서 insert SQL을 다 만들어줘요. 그리고 JDBC API를 사용해서 DB Insert Query까지 다 날려줍니다. 그리고 사실은 더 중요한 게 있는데 바로 패러다임의 불일치를 해결해줍니다. 이거는 조금 있다 뒤에서 설명드릴게요.
암튼 마치 Java Collection을 저장하듯이 한 줄 코드만 넣으면 됩니다.

그 다음 조회할 때도 이렇게 하면 됩니다.
jpa에게 그냥 id만 던지면 돼요. '회원 id 10번 찾아주세요' 라고 하면 jpa가 어떻게 하냐면 select 쿼리를 다 만듭니다. 그러니까 그 회원 객체를 분석을 해서 select 쿼리를 다 만들고, JDBC API를 사용하고 ResultSet 다 맵핑해주고, 그리고 패러다임의 불일치까지 해결합니. 뒤에 말씀드릴 건데 상속이나 이런 것들에서 어떤 문제점들을 다 해결해 주고요 그렇게 해가지고 조회니까 JPA가 entity object를 다 만들어서 우리에게 딱 반환을 해줍니다. 굉장히 깔끔하죠.
일단 JPA에 대해서 좀 소개를 먼저 해드릴게요.

여러분 옛날에 EJB라는 게 있었어요. 자바 진영에서 EJB라는 게 있었는데 이게 이제 크게 두 가지 기능이 있었어요. 우리가 지금 스프링에서 사용하는 컨테이너 기술 같은 EJB 영역이 있었고, 그 다음에 지금의 JPA라고 볼 수 있는데, 엔티티 빈이라는 게 있었어요. 그래서 JPA는 이 엔티티 빈으로부터 출발을 한 거고요.
근데 재미난 히스토리가 있는데, 이 EJB의 엔티비 빈은 거의 모든 개발자들이 쓰지 않았어요. 왜냐하면 이 기술이 너무 복잡하고 성능도 너무 안 나오는 거예요. 그래서 실용성은 떨어지는 거예요.
그래서 나중에 어떤 개발자 한 분이 엔티티 빈을 써보니까 너무 기술이 어렵고 성능도 안나오고 그냥 직접 SQL 짜고 하는거보다 더 못한거에요. 그래서 내가 만들어도 이거보다 낫겠다 해서 저녁에 퇴근하고 집에 가셔서 만든 게 바로 Hibernate 라는 오픈소스 입니다.
EJB 엔티티 빈도 뭐냐면, 아까 말씀드렸듯이 객체를 그냥 저장하고 조회해줘 라고 하면, 조회를 해야 하는데 사실 Join 부터 시작해서 막 여러가지들을 다 고민해야 되잖아요.
그래서 그 분이 고민하다가 저녁에 퇴근하고 와서 만들었는데 그걸 오픈소스로 딱 했죠. 이제 그랬더니 주변에서 많은 개발자들이 열광을 한거죠. 많은 개발자들이 같이 참여하고 도우면서 해서 나온게 바로 Hibernate 입니다. 그리고 이 Hibernate 를 만든 개발자가 바로 개빈 킹이죠.
그런데 원래 EJB가 Java 진영에서 표준으로 쓰는 거란 말이에요. 그래서 잘 돼야 되는데 기술이 너무 어렵고 그리고 성능도 제대로 안 나오고 그러다 보니까 실질적으로 쓰는 효율이 별로 없어서 망했습니다. 그래서 Java 진영에서 반성을 합니다. '아 이거 우리가 잘못했구나' 라고 해서 EJB도 ORM이고 Hibernate도 ORM인데 Hibernate가 너무 득세를 하니까, 결국 Java 진영에서 Hibernate를 만든 개빈 킹을 잡아옵니다.

그래서 '우리가 Java 표준 ORM 명세를 새로 만들 건데 네가 좀 해줘' 라고 해서 이제 Hibernate를 거의 복사 붙이기 하는 것처럼 그렇게 만들고 표준으로 만든 거죠.
사실은 표준이라고 하면 좋은 게 있어요. 오픈소스는 장점도 있는데 막 만든 게 있죠. 좀 빠르게 만들잖아요. 근데 표준은 굉장히 여러 사람의 의견을 모으는 시간들이 있단 말이에요. 그래서 용어나 이런 것들이 좀 더 명확하게 정제된 효과들이 있어요.
그래서 JPA는 아무튼 오픈소스에서 출발한 표준이에요. 그렇기 때문에 굉장히 실용적이예요. 그리고 용어를 포함해서 정제할 수 있는 프로세스 같은 것들을 많이 정제했죠. 그래서 아무튼 JPA라는 Java 표준이 탄생을 하게 됩니다.
JPA가 많이 쓰이는 이유가 되게 실용적인 데서 출발한 Java 표준이기 때문에 굉장히 오랫동안 사랑받고 살아남은 표준이 되는 거죠.
그러면 이제 JPA는 표준 명세라고 하는데, 표준 명세가 무슨 뜻이지?

표준 명세라는 거는 그냥 인터페이스의 모음이라고 보시면 돼요. 이런 인터페이스를 쫙 깔아놓는 거예요.
지금 현재 JPA 표준 명세를 구현한 대표적인 구현체는 한 3가지 정도가 있어요. 근데 우리는 거의 Hibernate 를 쓰신다고 보면 됩니다. Hibernate, EclipseLink 등 3가지가 주로 쓰이는데 거의 한 90% 이상은 구현체로 Hibernate를 씁니다. 사실 그럴 수밖에 없겠죠. JPA 표준 명세 전에 Hibernate를 거의 다 구현해 놓은 거기 때문에.

그래서 JPA는 표준 인터페이스고, 그 인터페이스를 구현한 Hibernate가 있어야 됩니다. Hibernate도 원래 오픈소스로 시작을 했지만 나중에는 개빈 킹도 JPA에 참여하면서 Hibernate도 JPA 표준에 맞춰서 다 컨버팅해서 개발을 하게 됩니다.

그래서 우리는 그냥 JPA 표준 인터페이스로 Hibernate를 쓰시면 됩니다.

그래서 버전을 대략 말씀드리면 1.0은 굉장히 오래됐죠. 이건 초기 버전이고 약간 기능이 부족했는데 2.0이 나오면서 이제 거의 대부분의 ORM 기능을 포함을 하게 됩니다. 2.0 이후로는 실질적으로 크게 많이 바뀔게 많지 않아요. 이미 2.0에서 굉장히 많은 부분들이 커버가 되었기 때문에 여러분 JPA를 한번 잘 배워두시면 쭉 계속 잘 쓰실 수 있을 거에요.
자 그러면 우리가 JPA를 왜 사용해야 되는가에 대해서 말씀드릴게요.

첫 번째로 SQL 중심적인 개발에서 객체 중심으로 개발할 수 있습니다. 왜냐? 이 JPA ORM 표준 명세, 그냥 저는 ORM 프레임워크라고 할게요. 이제 jpa가 이런 거를 중간에서 다 문제를 해결해줍니다. 우리는 마치 Java 컬렉션에다가 객체를 저장하듯이 던지면 돼요. 조회할 때도 마찬가지고요. 그럼 당연히 생산성과 유지보수가 훨씬 늘어나게 되겠죠. 그리고 패러다임 불일치도 해결되고 성능 관련해서도 더 이점들이 있는 부분들도 있습니다. 그래서 뭐 여러가지가 있는데 이건 이제 뒤에 쭉 설명드릴게요.

제일 먼저 생산성 관련해서는 여러분 그냥 코드를 이렇게 짜는 거예요. Member 객체를 저장해야 된다고 하면, jpa.persist() 하면 돼요. persist 라는 뜻이 뭐냐면 뭐 영구 보관하다, 이런 뜻이거든요. 그래서 jpa.persist(member)를 하면 마치 Java Collection에다가 저장하듯이 저장이 됩니다.
그리고 조회는 jpa.find() 해서 id를 주면 Member 객체가 팍 튀어나옵니다.
그리고 수정할 때는 member.setName() 해서 이름만 바꿔주면 돼요.
그러니까 여러분 생각해보세요. 내가 Java Collection 에서 데이터를 조회했죠. 그런 다음 만약에 데이터를 변경하고 싶으면 어떻게 하면 되나요? 그냥 조회한 Collection 에서 Member 객체를 꺼내요. 그럼 거기에 이름만 바꿔주면 되죠. 그럼 그냥 그 Member 객체가 바뀌는 거죠.
JPA도 똑같아요. 이렇게 해서 그냥 member.setName()만 하면 돼요. 뭐 보통 생각할 땐 'jpa.update() 이런 게 있지 않나요?' 하실 수 있는데 그냥 setName()으로 됩니다. 물론 조건이 있어요. 트랜잭션 안에서 이 데이터를 조회한 다음에 데이터를 변경해주면 트랜잭션이 끝난 시점에 자동으로 Update 쿼리가 DB에 나가게 됩니다. 그게 나간 다음 데이터베이스를 커밋하게 되죠.
삭제는 jpa.remove 이렇게 됩니다.
그리고 이제 유지보수 관점에서도

과거에는 만약 연락처 필드가 추가돼요. 그러면 모든 insert, select, update 다 찾아다니면서 SQL을 다 내가 직접 수정해야 돼요. 그래서 insert 문에 연락처, select 문에 연락처, 그러다가 또 update 문은 깜빡하면 고객의 연락처 변경이 안돼서 또 회사 돌아와가지고 또 이제 작업하고 해야 되겠죠.

근데 JPA는 여러분 필드만 추가하면 됩니다.
이런 SQL은 어차피 JPA가 해결해주기 때문에 개발자가 유지 보수해야 되는 영역이 굉장히 줄어들게 되죠.

자 그리고 사실은 이게 더 중요한데요. jpa가 paradigm의 불일치를 해결을 해줍니다. 상속, 연관관계, 객체 그래프 탐색, 비교하기, 앞에서 제가 설명드렸던 그 4가지를 다 해결을 해줍니다.
첫번째 상속.

이 그림이 있을 때 개발자는

jpa.persist 라고 해서 이 Album 객체를 넣어주기만 하면 돼요.

원래는 Item이랑 Album에서 insert 쿼리 두 번 나가야 되죠? 지금 슈퍼타입, 서브타입으로 테이블을 설계하게 되면 Item 객체 인스턴스를 데이터베이스에 보관하려면 insert 쿼리를 item 테이블에도 넣고, Album 테이블에도 넣어야 돼요.

자 그런데 여러분 jpa와 상속은 저장하면 이렇게 해줍니다.
jpa.persist 해서 Album을 딱 넣으면 jpa가 insert into 해서 Item 테이블에도 넣고 Album 테이블에도 넣습니다. 개발자가 직접 해주던 그 많은 맵핑 과정을 jpa가 다 해주게 됩니다.
그 다음 조회.

jpa.find() 해서 Album 타입을 주고 조회를 하잖아요? 그럼 Album을 꺼내줘요. 마치 Java Collection에서 가져가는 것처럼 가져와져요. 그러면 여러분 조회할 때 이게 단순히 쿼리 하나로 되는 게 아니잖아요. 원래 이거는 Album 조회하려면 Item이랑 Album을 Join한 다음에 가져가야 된단 말이에요. 놀랍게도 JPA가 다 Join해가지고 '아 이거는 상속관계니까 이거랑 이거가 필요하겠다' 하고 두 개 테이블를 Join해 가지고 다 만들어서 Album 객체에 반환해줍니다.
이것이 끝이 아니겠죠.
Album, Movie, Book 전부 다 그냥 자기가 알아서 싹 해줍니다.
자 그 다음 이제 연관관계와 객체 그래프 탐색인데요.

자 여러분 jpa 에서는 이 연관관계를 진짜로 참조를 쓸 수가 있어요. 원래는 외래 키 값을 넣고 그래야 되잖아요. jpa 에서는 member.setTeam() 해서 세팅 해놓고 Member를 persist로 딱 저장을 해요. 그러면 나중에 jpa.find() 해서 Member를 꺼내잖아요? 그럼 member.getTeam() 하면 Team을 조회할 수가 있습니다.
그러면 개발 많이 하셨던 분들은 '어? 이렇게 하면 저 밑에서 jpa.find() 할 때 도대체 query가 다 Join이 되는 건가?' 궁금하실텐데요, 이런 것도 jpa가 성능 최적화까지 다 고려해서 고민을 해줍니다.

자 그리고 엔티티 계층을 신뢰할 수가 있어요. 이전에 SQL을 직접 다룰 때는 신뢰하기 어렵다 했죠. jpa는 memberDAO가 내부에서 jpa를 쓴다고 가정을 할게요. 그러면 여기서 Member 객체를 딱 반환을 받아요. 그러면 JPA에서는 JPA가 관리하는 이 객체를 엔티티라고 하거든요. 그 다음에 어떻게 하느냐? member.getTeam(), member.getOrder().getDelivery() 할 수 있습니다. 물론 데이터가 다 그 안에 데이터가 있다는 전제하에 데이터가 다 존재하게 됩니다.
'어 이게 어떻게 가능하지? 이따만한 복잡한 SQL을 날리나?' 그렇지 않고 지연 로딩이라는 마법 같은 기술로 그런 것들이 다 가능하게 해줍니다.
자 그리고 JPA와 비교하기라는 건데요,

여러분 JPA를 통해서 우리가 Member id 100번으로 2개를 조회해요. 그래서 member1, member2를 조회 하는데 둘 다 Member id가 같은 애예요. 그러면 놀랍게도 JPA는 == 비교하면 같다 라고 우리가 Java Collection이랑 비교했던 것처럼 둘 다 당연히 같은 인스턴스가 나오죠.

자 그런 것처럼 JPA를 통해서 꺼내게 되면 == 비교해서 같습니다. 대신 전제가 있어요. 동일한 트랜잭션 안에서 조회해야되는 거죠.
그래서 동일한 트랜잭션 안에서 조회한 엔티티는 같다는 것을 JPA가 보장을 해줍니다.

자 그리고 이제 JPA를 사용하면 또 이런 성능 최적화도 제공이 되는데요. 1차 캐시와 동일성 보장이라는 것과 트랜잭션을 지원하는 쓰기 지연, 그리고 지연 로딩이라는 것을 제공을 해줍니다.
JPA는 같은 트랜잭션 안에서는 항상 같은 엔티티를 반환해줘요. 이게 상황에 따라 좀 다르긴 한데 약간의 조회 성능에 향상이 있습니다. 그래서 뭐냐면

이런거에요.
아 그걸 먼저 말씀드려야 되겠네요.

여러분 뭔가 중간에 끼잖아요. 중간에 기술이 하나 끼게 되면 보통 두 가지 성능상 이점을 얻을 수 있는 찬스를 가지게 돼요. 하나는 모아서 보내는게 가능해져요. 중간에 뭐가 있으면 그게 버퍼로 라이팅이 가능하고 또 하나는 캐싱, 조회할 때 이미 조회된 거는 멀리 안 가고 중간에서 있는 거를 다시 반환해 줄 수 있는 기능들을 제공할 수 있죠.
jpa가 중간에 끼기 때문에 그런 것들을 제공해 줄 수가 있거든요.

그래서 이거는 약간 캐싱과 관련된 건데 이전에 말씀드렸듯이 jpa에서는 같은 Member를 조회하게 되면, 첫 번째에서는 로직에서 jpa.find 에서 100번을 넘겨요. 그럼 첫 번째는 SQL query가 나갑니다. 그래서 가지고 와요. jpa가 중간에 그걸 들고 있어요. 그 다음에 jpa.find 하면 이제는 jpa가 sql을 날리지 않고 jpa가 메모리 상에서 들고 와서 반환을 해줍니다. 그래서 == 비교하면 같다고 나오고, 두 번 같은 회원을 조회했지만 sql은 한번만 실행이 됩니다.
물론 조건은 있어요. 같은 데이터베이스 트랜잭션 안에서만 이게 성립을 합니다. 다른 트랜잭션 안에서는 안됩니다. 그러니까 막 고객 요청이 여러개 오잖아요. 그럼 다 다른 트랜잭션 쓰기 때문에 안되는 거예요.
자 그리고 트랜잭션을 지원하는 쓰기 지연,

이건 뭐냐면 데이터를 버퍼로 촤악 모으는 거예요. 그래서 여러분, 이게 jpa 옵션을 켜야 되긴 하는데 트랜잭션을 커밋 할 때까지 insert SQL을 쫙 모을 수 있어요. 그 다음에 JDBC의 배치 SQL이라는 기능을 사용해서 이 쿼리들을 모아놨다가 한 번에 네트워크로 보내요.
예를 들어서 지금 이 코드를 보면 트랜잭션을 시작하고 Member A, B, C 세 개를 다 저장을 해요. 그러면 insert 쿼리가 한 번, 두 번, 세 번 따로 나가는 게 아니라, 모아놨다가 여태까지는 SQL을 안 보내요. 모아놨다가 트랜잭션을 커밋하면 딱 보내고 이 3개의 insert 쿼리를 한 번에 네트워크로 보내고 트랜잭션을 딱 커밋칠 수 있는 거예요. 그러면 네트워크 통신 비용이 굉장히 줄어들죠.
왔다 갔다 왔다 갔다 할 필요 없이 그냥 딱 모았다가 한 번에 딱 보내고 커밋. 이게 왜 성립할 수 있냐면 어쨌든 트랜잭션이 중요하기 때문에 트랜잭션을 커밋하기 전까지만 데이터를 보내면 되는 거거든요.
자 그래서 이런 것들도 가능하는데 이게 바로 버퍼 라이팅이 가능한 거죠. 이런 것들로 뭐 배치를 작성하거나 이럴 때는 성능을 또 많이 끌어올릴 수 있겠죠. 실무 많이 하신 분들은 알텐데 jdbc 배치 SQL을 직접 짤려면 이 코드가 여러분 엄청 지저분합니다. 근데 이걸 그냥 엄청 깔끔하게 JPA는 할 수 있는 거죠.

자 업데이트도 좀 비슷한 걸 가지고 성능이 좀 얻을 수 있는 게 있다라고 보시면 되는데, 내용이 어려워서 나중에 설명할게요.

자 그 다음에 지연 로딩과 즉시 로딩이라는 굉장히 재밌는 기능을 제공합니다. 여러분 지연 로딩이란 뭐냐면 예를 들어서 Member랑 Team이 있어요. 자 그런데 어떨 때는 내가 Member만 쓰고 어떨 때는 Member랑 Team이 연관관계가 있단 말이에요. 근데 로직을 짜다 보니까 Member를 조회할 때 항상 Team이 같이 사용돼요. 그러면 어떻게 하는 게 좋나요? Member를 조회할 때 Team도 한 방에 쿼리로 같이 Join으로 조회해서 가지고 오는 게 낫죠. 그래야 네트워크 통신도 줄이고 좋잖아요. db도 여러번 갈 필요 없고.
반면 Member를 조회할 때 Team을 거의 같이 안 쓰고 진짜 어쩌다가만 Team을 쓰면, Member만 조회하는 게 성능상 낫겠죠. 왜냐면 Team을 거의 안 쓰고 Member만 쓰고 싶은 거니까. 이렇게 되면, 연관된 거를 같이 미리 땡겨올 필요가 없다는 거죠.
자, 여러분. 이게 상황마다 다르단 말이에요. 그래서 JPA는 지연 로딩과 즉시 로딩이라는 두 가지를 다 지원합니다.
지연 로딩은 뭐냐면 객체가 실제 사용될 때 로딩하는 거예요. 예를 들어서 이런 거죠.

여기 지연 로딩 로직을 볼게요. memberDAO에서 Member를 딱 조회했습니다. 그 다음에 Member를 조회할 때는 일단 SELECT * FROM MEMBER에서 Member만 조회하는 거에요. Team은 조회 안하죠. 그러다가 db에서 Team이 실제 사용될 때 지연 로딩 제일 밑에 member.getTeam() 이 때, '어? Team이 사용되네' 라고 하면서, 이제 뭐 프록시를 초기화한다 뭐 이런 용어를 쓰는데 이때 실제 Team 데이터를 가져와서 값을 채워준다고 생각하면 됩니다.
그러면 거기서 이제 getName() 하면 query가 날아가고 데이터를 다 채운 다음에 실제 Team의 이름을 넣을 수 있는 거죠.
이렇게 지연 로딩이라는 전략도 지원을 하고, 아니면 '내가 해보니까 Member랑 Team은 거의 무조건 같이 쓰는 것 같아. 그래서 웬만한 Member를 조회할 때는 Team도 같이 조회해줘' 라고 세팅을 jpa에 해놓으면 즉시로딩이라는 전략이 동작하는데요. 이건 뭐냐면 Member를 딱 조회하는 순간 얘는 Team도 그냥 같이 딱 조회하는 거예요.

이런 게 왜 중요하냐면 우리가 애플리케이션 개발할 때 성능 최적화는 나중에 고민해도 되잖아요. 그래서 JPA 개발할 때는 보통 지연 로딩으로 쫙 세팅을 해놓다가 나중에 성능을 보고 하나의 쿼리로 하는 게 좋을 것 같다 그러면 거기만 즉시 로딩으로 약간 설정만 다다닥 해주면 되거든요. 아무튼 그런 식으로 최적화가 가능합니다.
자 아무튼 이제 쭉 설명을 드렸는데요.

JPA라는 기술은 결국 ORM이라는 기술이에요. Object Relational Mapping, 그러니까 객체랑 관계형 데이터베이스를 중간에서 맵핑해주는 기술이에요. 자 그러면 여러분 뭐가 중요할까요? 사실 JPA를 잘 다루기 위해서는 두가지를 다 잘 알아야 돼요. 바로 이 객체 지향이라는 개념과 관계형 데이터베이스라는 두 가지 개념을 다 잘 알아야 JPA를 굉장히 자유자재로 쓸 수 있는 거에요. 이제 그 사실 관계형 DB를 잘 모르고 JPA를 쓸 수 있다는 건 말이 안됩니다.
JPA 같은 거 쓰면 DB 잘 몰라도 된다는데 전혀 그러지 않습니다. 두 개를 다 알고 고민해야 두 가지를 다 잘 쓸 수 있습니다. 강의에서 하나하나 그런 내용들에 대해서는 쭉 설명을 드릴 거예요.
이렇게 해서 JPA에 대해서 설명을 해드렸습니다.
'스프링 > 자바 ORM 표준 JPA 프로그래밍 - 기본편' 카테고리의 다른 글
| 영속성 컨텍스트 1 (0) | 2024.05.25 |
|---|---|
| Hello JPA - 애플리케이션 개발 (0) | 2024.05.25 |
| Hello JPA - 프로젝트 생성 (0) | 2024.05.25 |
| SQL 중심적인 개발의 문제점 (0) | 2024.05.24 |
| 강좌 소개 (0) | 2024.05.23 |