본문 바로가기

안녕하세요!

프로그래밍 언어/Java

[ Java ] HANA CLOUD DB 연동

Dialect

    - JPA  : 기본적으로 어플리케이션에서 직접 JDBC 레벨의 SQL 작성하지 않고 JPA가 직접 SQL을 작성 및 실행

    - DBMS 종류마다 사용하는 SQL이 다름

    - Dialect : JPA에 어떤 DBMS를 사용해야 하는 지에 대해 알려주는 방법


ORM(Object-Relation Mapping)

    - 애플리케이션 Class와 RDB(Relational DataBase)의 테이블 매핑(연결)

    - 애플리케이션객체를 RDB 테이블에 자동으로 영속화 해주는 것

    - 장점

      1) SQL 문이아닌 Method 통해DB 조작 가능해 개발자는 객체 모델을 이용해 비즈니스 로직 구성 집중 가능

      2) 필요한 선언문, 할당 등의 부수적인 코드가 줄어들어 각종 객체에 대한 코드를 별도로 작성해 코드 가독성 향상

      3) 오직 객체지향적 접근만 고려하면 되기 때문에 생산성 증가

      4) 매핑하는 정보가 Class로 명시됐기 때문에 ERD를 보는 의존도 감소, 유지보수및 리팩토링 유리

    - 단점

      1) 프로젝트 규모가 크고 복잡해 설계가 잘못된 경우, 속도 저하 및 일관성 붕괴

      2) 복잡하고 무거운 Query는 속도를 위해 별도의 튜닝이 필요하기 때문에 결국 SQL문 써야할 때도 있음

      3) 학습 비용이 비쌈

 

JPA(Java Persistence API)

    - Java 진영에서 ORM  기술 표준으로 사용하는 인터페이스 모음

    - 자바어플리케이션에서 관계형 데이터베이스를 사용하는방식 정의한 인터페이스

    - 인터페이스이기 때문에 Hibernate, OpenJPA 등이 JPA 구현   

 


https://start.spring.io

    - Gradle - Groovy 선택

    - Java 선택

    - Spring Boot 2.7.8 선택

      1) 3 버전인 경우, JAVA 17 이상만 구동됨

      2) 2 버전인 경우, JAVA 11 선택

    - Dependencies : Lombok, Spring Web, Spring Data JPA 추가

 

○ GENERATE 압축 파일을 해제한 후, VsCode에서 폴더 열기

 

https://mvnrepository.com/artifact/com.sap.cloud.db.jdbc/ngdbc

    - SAP HANA JDBC Driver 최신 버전 다운로드

 

○ dependencies 추가

// https://mvnrepository.com/artifact/com.sap.cloud.db.jdbc/ngdbc
implementation 'com.sap.cloud.db.jdbc:ngdbc:2.15.10'

    - sourceCompatibility : 설정한 JAVA 버전과 일치하는지 확인

 

○ 실행 중인 인스턴스 우측의 actions 클릭

    - Copy SQL Endpoint 클릭

 

application.properties --> application.yaml 로 변경

    - url : Copy SQL Endpoint 이용해 입력

    - username, password 입력

 

○ gradle 구동하기

    - ./gradlew : gradle 설치

    - gradle build : gradle 구동

    - gradle bootRun : springboot 실행  


[ User.java ]

@EqualsAndHashCode

    - equals : 두 객체의 내용이 같은지 동등성(equality) 비교 연산자

    - hashCode : 두 객체가 같은 객체인지 동일성(identity) 비교 연산자

    - callSuper : equals와 hashCode 메소드 자동 생성 시 부모 클래스의 필드까지 감안할지 여부 설정

      1) @EqualsAndHashCode(callSuper = true) : 부모 클래스 필드 값들도 동일한지 체크

      2) @EqualsAndHashCode(callSuper = false) : 자신 클래스의 필드 값만 고려

@AllArgsConstructor : 모든 필드 값을 파라미터로 받는 생성자 만듦

@NoArgsConstructor : 파라미터가 없는 기본 생성자 생성

@RequiredArgsConstructor : final이나 @NonNull 필드 값만 파라미터로 받는 생성자 만듦

@Entity

    - DB 테이블에 대응하는 하나의 클래스

    - 접근 제어자가 public / protected 인 기본 생성자 필수

    - final 클래스, enum, interface, inner 클래스에 사용 불

@Id : 테이블 상의 Primary Key

    - @GeneratedValue

      1) PK 컬럼의 데이터 형식은 정해져 있지는 않으나 구분이 가능한 유일한 값을 가지고 있어야 함

      2) 데이터 경합으로 인해 발생되는 데드락과 같은 현상 방지하기 위해 대부분 BigInteger 즉 Java의 Long 주로 사용

        * deadlock : 동일한 시점에 요청이 유입되었을 때 데이터베이스는 테이블 혹은 레코드를 lock 걸어

                            데이터가 변경되지 않도록 막아 놓고 다른 작업 진행

package hana.dool.hanadooldemo.model;

import java.lang.reflect.Field;

import javax.persistence.Column;
import javax.persistence.Entity;

import javax.persistence.Id;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity(name = "User")
public class User {
   
    @Id
    //@GeneratedValue(generator = "uuid2")
    //@GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Column(columnDefinition = "varchar(36)")
    private String uid;

    @Column(name = "username", nullable = false, columnDefinition = "varchar(100)")
    private String username;

    @Column(columnDefinition = "varchar(100)")
    private String password;

    @Column(name = "first_name", nullable = false, columnDefinition = "varchar(100)")
    private String firstName;

    @Column(name = "last_name", nullable = false, columnDefinition = "varchar(50)")
    private String lastName;

    @Column(name = "day_of_birth", columnDefinition = "varchar(8)")
    private String dayOfBirth;

    @Column(columnDefinition = "boolean default true")
    private Boolean use;

    @Builder
    public User(String username, String firstName, String lastName) {
        this.username = username;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public void apply(User source) throws IllegalArgumentException, IllegalAccessException {
        Field[] fields = User.class.getDeclaredFields();
        for(Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(source);
            if(value != null) {
                field.set(this, value);
            }
        }
    }

    public void update(User source) throws IllegalArgumentException, IllegalAccessException {
        Field[] fields = User.class.getDeclaredFields();
        for(Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(source);
            field.set(this, value);
        }
    }

}

 

[ UserRepository.java ]

package hana.dool.hanadooldemo.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import hana.dool.hanadooldemo.model.User;

@Repository
public interface UserRepository extends JpaRepository<User, String> {
    
}

 

[ UserService.java ]

package hana.dool.hanadooldemo.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import hana.dool.hanadooldemo.model.User;
import hana.dool.hanadooldemo.repository.UserRepository;

@Service
public class UserService {
    
    @Autowired
    private UserRepository repository;

    public List<User> findAll() {
        return repository.findAll();
    }

    public User findById(String uid) {
        return repository.findById(uid).get();
    }

    public User save(User user) {
        repository.save(user);
        return user;
    }

    public void deleteById(String uid) {
        repository.deleteById(uid);
    }

    public void applyById(String uid, User user) throws IllegalArgumentException, IllegalAccessException {
        User storedUser = this.findById(uid);
        storedUser.apply(user);
        repository.save(storedUser);
    }

    public void updateById(String uid, User user) throws IllegalArgumentException, IllegalAccessException {
        User storedUser = this.findById(uid);
        storedUser.update(user);
        repository.save(storedUser);
    }

}

 

[ UserController.java ]

package hana.dool.hanadooldemo.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import hana.dool.hanadooldemo.model.User;
import hana.dool.hanadooldemo.service.UserService;

@RestController
@RequestMapping("/user")
public class UserController {
    
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserService userService;
    
    // GET ALL
    @GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> user = userService.findAll();
        return new ResponseEntity<List<User>>(user, HttpStatus.OK);
    }

    // POST
    @PostMapping
    public ResponseEntity<User> save(@RequestBody User user) {
        return new ResponseEntity<User>(userService.save(user), HttpStatus.OK);
    }

    // PUT
    @PutMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<User> putUser(@RequestBody User user)
            throws IllegalArgumentException, IllegalAccessException {
                userService.updateById(user.getUid(), user);
                return new ResponseEntity<User>(user, HttpStatus.OK);
            }
    // GET ONE
    @GetMapping(value = "/{uid}", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<User> getUser(@PathVariable("uid") String uid) {
        User user = userService.findById(uid);
        return new ResponseEntity<User>(user, HttpStatus.OK);
    }

    // PUT
    @PutMapping(value = "/{uid}", produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<User> putUser(@PathVariable("uid") String uid, @RequestBody User user) {
        try {
            user.setUid(uid);
            userService.updateById(uid, user);
            return ResponseEntity.ok(user);
        } catch (IllegalArgumentException | IllegalAccessException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    // PATCH (apply if exists)
    @PatchMapping(value = "/{uid}", consumes = "application/json", produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<User> patchUser(@PathVariable("uid") String uid, @RequestBody User user) {
        try {
            userService.applyById(uid, user);
            return ResponseEntity.ok(user);
        } catch (IllegalAccessException | IllegalArgumentException | SecurityException e) {
            log.error(e.getLocalizedMessage(), e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
    
    // DELETE
    @DeleteMapping(value = "/{uid}", produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<Void> deleteUser(@PathVariable("uid") String uid) {
        userService.deleteById(uid);
        return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
    }


}
728x90
반응형

loading