[Spring] ORM(Object-Relational Mapping)

devJun's avatar
Aug 06, 2024
[Spring] ORM(Object-Relational Mapping)
 
💡
데이터베이스의 테이블을 객체로 매핑해서, 프로그래머가 객체 지향 방식으로 데이터베이스를 조작할 수 있게 도와준다.
 

ORM의 주요 개념과 특징

1. 객체와 테이블의 매핑

  • 객체는 프로그래밍 언어에서 사용하는 데이터 구조이며, 테이블은 데이터베이스에서 데이터를 저장하는 구조
  • ORM은 클래스(객체)와 테이블, 속성과 컬럼 간의 매핑을 정의하여 객체와 데이터베이스 간의 변환을 자동화

2. CRUD 작업의 자동화

  • ORM은 Create, Read, Update, Delete와 같은 기본 데이터베이스 작업을 자동화
  • 이를 통해 개발자는 SQL을 직접 작성하지 않고도 데이터 조작이 가능

3. 추상화 수준의 향상

  • ORM을 사용하면 데이터베이스의 구체적인 구현에 대한 의존도를 줄이고, 애플리케이션의 비즈니스 로직에 집중할 수 있음
  • 데이터베이스에 대한 추상화 계층을 제공하여 데이터베이스 관리 시스템(DBMS) 간의 전환이 비교적 용이

4. SQL Injection 방지

  • ORM은 SQL 쿼리를 자동으로 생성하며, 이 과정에서 파라미터 바인딩을 사용하여 SQL 인젝션 공격을 방지하는 데 도움

5. 관계형 데이터의 처리

  • ORM은 객체 간의 관계를 정의하고 관리할 수 있습니다. 예를 들어, 일대일(One-to-One), 일대다(One-to-Many), 다대다(Many-to-Many) 관계를 객체 모델로 표현 가능

ORM의 장점

  • 생산성 향상: SQL 작성 및 데이터베이스 관리에 드는 시간을 절약
  • 유지보수 용이성: 코드와 데이터베이스 간의 일관성을 유지하기 쉬움
  • 데이터베이스 독립성: 데이터베이스 종류에 따라 코드를 변경할 필요 없이 ORM이 추상화 계층을 제공하여 여러 데이터베이스를 지원 가능
  • 안전성: SQL 인젝션과 같은 보안 취약점을 줄이는 데 도움

ORM의 단점

  • 성능 오버헤드: ORM의 추상화 계층이 추가되어, SQL을 직접 작성하는 것보다 성능이 떨어질 수 있음
  • 복잡한 쿼리 처리의 어려움: 복잡한 쿼리나 특정 데이터베이스 기능을 사용하는 경우, ORM이 이를 지원하지 않을 수 있음
  • 초기 학습 비용: ORM 프레임워크를 사용하는 데 필요한 초기 학습 비용이 발생할 수 있음
 
 

연습 코드

1.ex01(Setter, 생성자 활용)

 
user
package ex01.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class User { private int userId; private String username; private String email; }
 
App1
package ex01; import ex01.model.User; public class App1 { public static void main(String[] args) { // 1. DB에서 가져온 데이터 - Flat(평평) 하게 가져올 수 밖에 없다 DBData1 dbData = new DBData1(1, "제목1", "내용1", 3, "love", "love@nate.com"); //DBData1는 db에서 조회한 데이터 //ViewData1는 view 에 뿌리기 위해 // 2. dbData1를 ViewData1에 옮기시오 - ORM //1. setter로 하나씩 넣기 ViewData1 v1 = new ViewData1(); v1.setBoardId(dbData.getBoardId()); v1.setTitle(dbData.getTitle()); v1.setContent(dbData.getContent()); User user = new User(); user.setUserId(dbData.getUserId()); user.setUsername(dbData.getUsername()); user.setEmail(dbData.getEmail()); v1.setUser(user); //2. 생성자 이용 User user1 = new User(dbData.getUserId(), dbData.getUsername(), dbData.getEmail()); ViewData1 v2 = new ViewData1(dbData.getBoardId(), dbData.getTitle(), dbData.getContent(),user); } }
 
DBData1
package ex01; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class DBData1 { //평평한 데이터는 테이블 데이터 private int boardId; private String title; private String content; private int userId; private String username; private String email; }
 
viewdata1
package ex01; import ex01.model.User; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data //굴곡진 데이터 public class ViewData1 { private int boardId; private String title; private String content; private User user; }
 
 

2. ex01v2

 
user
package ex01v2.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class User { private int userId; private String username; private String email; }
 
App1
package ex01v2; import ex01.model.User; public class App1 { public static void main(String[] args) { // 1. DB에서 가져온 데이터 - Flat(평평) 하게 가져올 수 밖에 없다 DBData1 dbData = new DBData1(1, "제목1", "내용1", 3, "love", "love@nate.com"); //DBData1는 db에서 조회한 데이터 //ViewData1는 view 에 뿌리기 위해 // 2. dbData1를 ViewData1에 옮기시오 - ORM //오류가 나서 주석처리 이렇게 하는거임 ViewData1 viewData = new ViewData1(dbData); } }
 
dbdata1
package ex01v2; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class DBData1 { //평평한 데이터는 테이블 데이터 private int boardId; private String title; private String content; private int userId; private String username; private String email; }
 
viewdata1
package ex01v2; import ex01.model.User; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data //굴곡진 데이터 public class ViewData1 { private int boardId; private String title; private String content; private User user; //생성자 직접 만들어야됨 public ViewData1(DBData1 dbData) { this.boardId = dbData.getBoardId(); this.title = dbData.getTitle(); this.content = dbData.getContent(); this.user = new User(dbData.getUserId(), dbData.getUsername(), dbData.getEmail()); } }
 

3. ex01v3

 
user
package ex01v3.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class User { private int userId; private String username; private String email; }
 
App1
package ex01v3; public class App1 { public static void main(String[] args) { // 1. DB에서 가져온 데이터 - Flat(평평) 하게 가져올 수 밖에 없다 DBData1 dbData = new DBData1(1, "제목1", "내용1", 3, "love", "love@nate.com"); //DBData1는 db에서 조회한 데이터 //ViewData1는 view 에 뿌리기 위해 // 2. dbData1를 ViewData1에 옮기시오 - ORM ViewData1 viewData1 = dbData.toViewData(); } }
 
dbdata
package ex01v3; import ex01.model.User; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class DBData1 { //평평한 데이터는 테이블 데이터 private int boardId; private String title; private String content; private int userId; private String username; private String email; public ViewData1 toViewData(){ return new ViewData1(boardId,title,content,new User(userId,username,email)); } }
 
viewdata
package ex01v3; import ex01.model.User; import ex01v2.DBData1; import lombok.AllArgsConstructor; import lombok.Data; @AllArgsConstructor @Data //굴곡진 데이터 public class ViewData1 { private int boardId; private String title; private String content; private User user; //생성자 직접 만들어야됨 }
 

4. ex02

 
reply
package ex02.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class Reply { private int replyId; private String comment; }
 
app
package ex02; import ex02.model.Reply; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class App2 { public static void main(String[] args) { // 1. DB에서 가져온 데이터 - Flat(평평) 하게 가져올 수 밖에 없다 DBData2 dbData1 = new DBData2(1, "제목1", "내용1", 1, "댓글1"); DBData2 dbData2 = new DBData2(1, "제목1", "내용1", 2, "댓글2"); DBData2 dbData3 = new DBData2(1, "제목1", "내용1", 3, "댓글3"); List<DBData2> dbList = Arrays.asList(dbData1, dbData2, dbData3); // 2. ddbList(컬렉션을) ViewData(오브젝트)에 옮기시오 - ORM if(dbList.size()==0)return; // dbList 값이 없으면 종료 ViewData2 viewData2 = new ViewData2( dbList.get(0).getBoardId(), dbList.get(0).getTitle(), dbList.get(0).getContent() ); for(DBData2 data : dbList){ Reply r = new Reply(data.getReplyId(), data.getComment()); viewData2.addReply(r); } } }
 
dbdata
package ex02; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class DBData2 { private int boardId; private String title; private String content; private int replyId; private String comment; }
 
viewdata
package ex02; import ex02.model.Reply; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; @NoArgsConstructor @Data public class ViewData2 { private int boardId; private String title; private String content; // Board 데이터만 넣는 생성자 public ViewData2(int boardId, String title, String content) { this.boardId = boardId; this.title = title; this.content = content; } // 댓글들은 addReply로 추가하기 private List<Reply> replies = new ArrayList<>(); public void addReply(Reply reply){ replies.add(reply); } }
 

5. ex02v2

 
Reply
package ex02v2.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class Reply { private int replyId; private String comment; }
 
App
package ex02v2; import java.util.Arrays; import java.util.List; public class App2 { public static void main(String[] args) { // 1. DB에서 가져온 데이터 - Flat(평평) 하게 가져올 수 밖에 없다 DBData2 dbData1 = new DBData2(1, "제목1", "내용1", 1, "댓글1"); DBData2 dbData2 = new DBData2(1, "제목1", "내용1", 2, "댓글2"); DBData2 dbData3 = new DBData2(1, "제목1", "내용1", 3, "댓글3"); List<DBData2> dbList = Arrays.asList(dbData1, dbData2, dbData3); // 2. ddbList(컬렉션을) ViewData(오브젝트)에 옮기시오 - ORM ViewData2 viewData2 = new ViewData2(dbList); System.out.println(viewData2); } }
 
DBData2
package ex02v2; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Data public class DBData2 { private int boardId; private String title; private String content; private int replyId; private String comment; }
 
ViewData2
package ex02v2; import ex02.model.Reply; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; @AllArgsConstructor @NoArgsConstructor @Data public class ViewData2 { private int boardId; private String title; private String content; // 댓글들은 addReply로 추가하기 private List<Reply> replies = new ArrayList<>(); // Board 데이터만 넣는 생성자 public void addReply(Reply reply){ replies.add(reply); } public ViewData2(List<DBData2> dbList) { if(dbList.size()>0){ this.boardId = dbList.get(0).getBoardId(); this.title = dbList.get(0).getTitle(); this.content = dbList.get(0).getContent(); } // dbList.stream().forEach(db ->{ // addReply(new Reply(db.getReplyId(),db.getComment())); // } ); //이렇게 해도 됨. // replies = dbList.stream().map(db ->new Reply(db.getReplyId(),db.getComment())).toList(); for(DBData2 data : dbList){ Reply r = new Reply(data.getReplyId(),data.getComment()); addReply(r); } } }
Share article

devJun