밍쎄의 코딩공간

[스프링 부트 핵심 가이드] - 06. 데이터베이스 연동 본문

개발서적/IT

[스프링 부트 핵심 가이드] - 06. 데이터베이스 연동

밍쎄 2023. 9. 10. 23:34

스프링 부트 핵심 가이드

마리아 DB설치

https://mariadb.org/download/?t=mariadb&p=mariadb&r=11.1.2&os=windows&cpu=x86_64&pkg=msi&m=blendbyte 

 

Download MariaDB Server - MariaDB.org

REST API Release Schedule Reporting Bugs … Continue reading "Download MariaDB Server"

mariadb.org

위의 URL에 들어가서 위의 사진과 같이 설정 후 다운로드 받아준다. south korea버전 말고 taipei 버전을 받아도 괜찮다.

그 후 별다른 조작 없이 Next로 넘어가다 보면 위와 같은 창이 나온다. 계정은 설정하되 절대 잊어버리지 말아야 한다.

또한, 가장 대중적으로 사용되는 문자 인코딩 방식인 UTF-8을 기본값으로 설정해 준다.

다음 단계에서는 서버 이름과 포트 번호를 설정을 해야한다. 처음으로 DB를 설치하는 사람은 상관이 없지만, 나같은 경우는 MySQL이 기존에 깔려 있었기 때문에 애를 먹었다. 절대 포트 충돌이 일어나지 않게 설정해 줘야 한다.

HeidiSQL 데이터베이스의 접속 설정을 해준다.

그 후 에는 데이터베이스를 생성하는 쿼리를 입력하고 실행해준다. (도움창의 파란색 플레이 버튼)

 

ORM

- Object-Relational Mapping

객체와 관계형 데이터베이스의 데이터를 자동으로 매핑해주는 것을 말한다
      객체 지향 프로그래밍은 클래스를 사용하고, 관계형 데이터베이스는 테이블을 사용한다.
      객체 모델과 관계형 모델 간에 불일치가 존재한다.
      ORM을 통해 객체 간의 관계를 바탕으로 SQL을 자동으로 생성하여 불일치를 해결해준준다.
- 데이터베이스 데이터 <- 매핑 -> Object 필드
      객체를 통해 간접적으로 데이터베이스 데이터를 다룬다.
- Persistant API라고도 부른다.
      Ex) JPA, Hibernate

 

ORM 장점

- 객체 지향적인 코드로 인해 더 직관적이고, 비즈니스 로직에 더 집중할 수 있게 도와준다.
      ORM을 이용하면 SQL 쿼리가 아닌 직관적인 코드로 데이터를 조작할 수 있어 개발자가 객체 지향 프로그래밍하는 데 집중할 수 있도록 도와준준다.
      선언문, 할당, 종료 같은 부수적인 코드가 없거나 급격히 줄어든다.
      각종 객체에 대한 코드를 별도록 작성하기 때문에 코드의 가독성을 올려준다.
      SQL의 절차적이고 순차적인 접근이 아닌 객체 지향적인 접근으로 인해 생산성이 증가한다.


재사용성 및 유지보수의 편리성이 증가한다.
      ORM은 독립적으로 작성되어있고, 해당 객체들을 재활용할 수 있다.
      이로 인해 모델에서 가공된 데이터를 컨트롤러에 의해 뷰와 합쳐지는 형태로 디자인 패턴을 견고하게 다지는데 유리하다.
      매핑정보가 명확하여 ERD를 보는 것에 대한 의존도를 낮출 수 있다.

 

DBMS에 대한 종속성이 줄어든다.
      대부분 ORM 솔루션은 DB에 종속적이지 않다.
      종속적이지 않다는 것은 구현 방법 뿐만 아니라 많은 솔루션에서 자료형 타입까지 유효하다는 것이다.
      개발자는 Object에 집중함으로써 극단적으로 DBMS를 교체하는 거대한 작업에도 비교적 적은 리스크와 시간이 소요된다.
      또한 자바에서 가공할 경우 equals, hashCode의 오버라이드 같은 자바의 기능을 이용할 수 있고, 간결하고 빠른 가공이 가능해진다.

 

ORM 단점

완벽한 ORM으로만 서비스를 구현하기가 어렵다.
      사용하기는 편하지만 설계는 매우 신중하게 해야한다.
      프로젝트의 복잡성이 커질 경우 ORM 구현 난이도가 증가 할 수 있다.
      잘못 구현된 경우에 속도 저하 및 심각할 경우 일관성이 무너지는 문제점이 생길수 있다.


프로시저가 많은 시스템에서는 ORM의 객체 지향적인 장점을 활용하기 어렵다.
      이미 프로시저가 많은 시스템에서는 다시 객체로 바꿔야함, 그 과정에서 생산성 저하나 리스크가 많이 발생할 수 있다.

 

 

JPA

왜 JPA를 사용해야 하는가

  • SQL 중심적인 개발 → 객체 중심적인 개발
  • JPA가 등장하기 전, 객체를 관계형 DB에 관리하기 위해서는 반복적인 SQL을 써야합니다. 더불어서 객체 Field가 수정된다면 그에 맞추어 SQL도 수정해야 합니다. 이는 결국 개발을 SQL에 의존적으로 하게끔 되었습니다.
  • 생산성
    1. Create: jpa.persist(member)
    2. Read: Member member = jpa.find(memberId)
    3. Update: member.setName("변경할 이름")
    4. Delete: jpa.remove(member)
  • CRUD 작업이 많이 간결화됩니다.
  • 유지보수
  • 어느 객체의 Field가 변경되면 관련 모든 SQL을 수정하는 것에서 단순히 Field만 추가하면 JPA가 알아서 SQL를 맞게 수정합니다.
  • 패러다임의 불일치 해결
  • 객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등의 다양한 장치들을 제공합니다. 그리고 이러한 객체를 보관하는 현실적인 대안은 관계형 DB입니다. 여기서 다음과 같은 객체와 관계형 DB의 차이로 인해 SQL 매핑이 필요합니다.

영속성 컨텍스트

영속성 컨텍스트는 엔티티를 영구 저장하는 환경이라는 뜻이다. 영속성 컨텍스트는 애플리케이션과 DB 사이에서 객체를 보관하는 가상의 DB 역할을 한다. 엔티티 매니저(EntityManager)를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리하게 된다.

 

- 엔티티 생명주기

[그림 1] 엔티티 생명주기(출처 : 참고1)

 

  • 비영속(new/transient) 상태 : 영속성 컨텍스트와 관계가 없는 상태
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

 

  • 영속(managed) 상태 : 영속성 컨텍스트에 저장된 상태
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername(“회원1”);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장한 상태(영속)
em.persist(member);

 

  • 준영속(detached) 상태 : 영속성 컨텍스트에 저장되었다가 분리된 상태
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);

 

  • 삭제(removed) 상태 : 삭제된 상태
//객체를 삭제한 상태(삭제)
em.remove(member);

 

DAO 클래스 생성

 

먼저 사용자 정보를 쉽게 저장하기 위한 객체를 위해 User 클래스를 만들어줍니다.

 

User Class

public class User {
    String id;
    String name;
    String password;
    
    public String getId(){
        return id;
    }
    public void setId(String id){
        this.id = id;
    }
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getPassword(){
        return password;
    }
    public void setPassword(String password){
        this.password = password;
    }
}

 User 클래스를 사용해 DAO 클래스를 만들어줍니다.

 

- Database와 연동하기 위해 JDBC를 사용할 것인데, 일반적인 순서는 아래와 같습니다.

 

  • DB 연결을 위한 Connection을 가져온다.
  • SQL을 담은 Statement(or PreparedStatement)를 만든다.
  • 만들어진 Statement를 실행한다.
  • 조회의 경우 SQL 쿼리의 실행 결과를 ResultSet으로 받아서 정보를 저장할 오브젝트(User)에 옮겨준다.
  • 작업 중에 생성된 Connection, Statement, ResultSet 같은 리소스는 작업을 마친 후 반드시 닫아준다.
  • JDBC API가 만들어내는 예외를 잡아서 직접 처리하거나, throws를 선언해 예외가 발생하면 메서드 밖으로 던지게 한다.

UserDao Class

public class UserDao {
	public void add(User user) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/spring?autoReconnect=true&amp;useSSL=false\";","root","@min753951");

        PreparedStatement ps = c.prepareStatement(
                "insert into users(id, name, password) values(?,?,?)");

        ps.setString(1, user.getId());
        ps.setString(2, user.getName());
        ps.setString(3, user.getPassword());

        ps.executeUpdate();

        ps.close();
        c.close();

    }
	
	public User get(String id) throws ClassNotFoundException, SQLException {
		Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/spring?autoReconnect=true&amp;useSSL=false\";","root","@min753951");

        PreparedStatement ps = c.prepareStatement(
                "select * from users where id = ?");
		ps.setString(1,  id);
		
		ResultSet rs = ps.executeQuery();
		rs.next();
		User user = new User();
		user.setId(rs.getString("id"));
		user.setName(rs.getString("name"));
		user.setPassword(rs.getString("password"));
		
		rs.close();
		ps.close();
		c.close();
        
        return user;
	}

}

 

DAO 객체가 잘 작동하는지 테스트하기 위해서는 main()을 사용해 검증할 수 있습니다.

 

Main Class

public static void main(String[] args) {
        UserDao dao = new UserDao();
        user.setId("alstmdsha");
        user.setName("박민송");
        user.setPassword("123456");
        
        dao.add(user);
        
        System.out.println(user.getId()+" 등록 성공 ");
        
        User user2 = dao.get(user.getId());
        System.out.println(user2.getName());
        System.out.println(user2.getPassword());
        
        System.out.println(user2.getId() + " 조회 성공 ");
    }

컨트롤러 생성

1. 필드 주입

@RestController
public class HelloController {

    @Autowired
    private HelloRepository helloRepository;
    
    @Autowired
    private HelloService helloSerivce;
}

 

필드 주입은 @Autowired 어노테이션을 이용해 객체를 주입하는 방식이다.

코드가 간결하다는 장점이 있다.

 

2. 수정자 주입 (메서드 주입)

@RestController
public class HelloController {

    private HelloRepository helloRepository;
    private HelloService helloService;

    @Autowired
    public void setHelloRepository(HelloRepository helloRepository) {
        this.helloRepository = helloRepository;
    }

    @Autowired
    public void setHelloService(HelloService helloService) {
        this.helloService = helloService;
    }
}

 

수정자 주입은 Setter, 혹은 사용자 정의 메서드를 통해 객체 의존 관계를 주입하는 방식이다.

 

3. 생성자 주입

@RestController
public class HelloController {

    private HelloRepository helloRepository;
    private HelloService helloService;

    @Autowired
    public HelloController(HelloRepository helloRepository, HelloService helloService) {
        this.helloRepository = helloRepository;
        this.helloService = helloService;
    }
}

 

생성자 주입은 위 코드처럼 사용할 의존 객체를 생성자를 통해 주입받는 방식이다.

 

(참고로, 위 코드의 생성자에 선언되어있는 @Autowired 어노테이션은 생성자가 한 개만 있을 경우 생략 가능하다.

 

 

 

 

개념에 더 공부를 한 뒤 Swagger API 등 예제 더 업로드 할 예정

 

 

 

< 참고 URL >

https://velog.io/@tmdgh0221/JPA-%EA%B8%B0%EB%B3%B8%ED%8E%B8-%EC%A0%95%EB%A6%AC

 

JPA 기본편 정리

JPA 기본편 정리본입니다.

velog.io

https://hahahoho5915.tistory.com/47

 

[간단정리] ORM(Object-Relational Mapping) 이란?

개요 ORM(Object-Relational Mapping) 이란 무엇인가 알아보기 내용 Persistence(영속성) - 데이터를 생성한 프로그램이 종료되더라도 사라지지 않는 데이터의 특성을 말합니다. - 영속성을 갖지 않는 데이터

hahahoho5915.tistory.com

 

https://withseungryu.tistory.com/66

 

[Spring] DAO 기본 구조 만들기

🧐 DAO란? DAO(Data Access Object)는 DB를 사용해 데이터를 조회하거나 조작하는 기능을 전담하도록 만든 오브젝트 🧐 DAO 기본 구조 먼저 사용자 정보를 쉽게 저장하기 위한 객체를 위해 User 클래스를

withseungryu.tistory.com

https://programforlife.tistory.com/111

 

[Spring] 생성자 주입을 사용해야 하는 이유

인턴을 시작한 초기 단계에, Spring 프로젝트 코드 분석을 하다가 신기한 점을 발견해서 질문을 한 기억이 있습니다. Spring프로젝트에서 Controller를 작성할 때, 저는 항상 @Autowired 어노테이션을 사

programforlife.tistory.com

 

 

728x90