Guide_Accessing data with MySQL

Dev.Hammy·2023년 12월 25일
0

Spring Guides

목록 보기
31/46
post-custom-banner

이 가이드는 MySQL 데이터베이스(대부분의 다른 가이드와 많은 샘플 애플리케이션에서 사용하는 메모리 내 임베디드 데이터베이스와 반대)에 연결된 Spring 애플리케이션을 생성하는 과정을 안내합니다. 이는 데이터베이스에 액세스하기 위해 Spring Data JPA를 사용하지만 이는 가능한 많은 선택 중 하나일 뿐입니다(예를 들어 일반 Spring JDBC를 사용할 수 있음).

mysql 설치

https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/

https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-22-04

https://www.ionos.com/digitalguide/websites/web-development/mysql-on-ubuntu-2204/

mysql-server 설치

sudo apt update
sudo apt install mysql-server

서버가 자동 실행 되었는지 확인

systemctl status mysql

사용자 비밀번호 설정

$ sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '비밀번호';
mysql > exit

보안 스크립트 호출 및 설정

보안 스크립트를 실행하면 익명 유저, 테스트 데이터베이스, 루트 권한 사용자의 원격 이용 등 여러 보안 관련 설정에 대한 문답이 이어진다. 모든 변경사항을 적용하려면 mysql을 닫고 다시 실행한다.

인증 프로세스 변경

$ mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED WITH auth_socket;

IDENTIFIED WITH auth_socket은 MySQL의 사용자 계정이 운영 체제의 인증 소켓(authentication socket)을 통해 인증되도록 하는 것을 의미합니다. 이 설정은 사용자가 MySQL에 암호 없이 로그인할 수 있게 만듭니다. 즉, 해당 운영 체제에 로그인한 사용자는 MySQL에 암호 입력 없이 자동으로 접속할 수 있게 됩니다. 즉, sudo mysql로 접속할 수 있다.

root 외에 데이터베이스 작업용 계정 만들기

$ sudo mysql
CREATE USER 'username'@'host' IDENTIFIED WITH authentication_plugin BY 'password';

사용자 인증 플러그인을 선택할 때 여러 가지 옵션이 있습니다. 앞서 언급한 auth_socket 플러그인은 유효한 사용자가 데이터베이스에 액세스하기 위해 비밀번호를 입력하지 않고도 강력한 보안을 제공하므로 편리할 수 있습니다. 그러나 이는 외부 프로그램이 MySQL과 상호 작용해야 할 때 상황을 복잡하게 만들 수 있는 원격 연결도 방지합니다.

대안으로, 사용자가 MySQL의 기본 플러그인인 caching_sha2_password를 사용하여 인증하도록 구문의 WITH authentication_plugin 부분을 완전히 생략할 수 있습니다. MySQL 문서에서는 강력한 보안 기능으로 인해 비밀번호로 로그인하려는 사용자에게 이 플러그인을 권장합니다.

caching_sha2_password로 인증하는 사용자를 생성하려면 다음 명령을 실행합니다. sammy를 원하는 사용자 이름으로 변경하고 비밀번호를 선택한 강력한 비밀번호로 변경하세요.

CREATE USER 'sammy'@'localhost' IDENTIFIED BY 'password';

GRANT PRIVILEGE ON database.table TO 'username'@'host';

작업용 계정에 권한을 부여한다. 이를테면 아래와 같이 부여할 수 있다.

GRANT CREATE, ALTER, DROP, INSERT, UPDATE, INDEX, DELETE, SELECT, REFERENCES, RELOAD on *.* TO 'sammy'@'localhost' WITH GRANT OPTION;

무엇을 구축할 것인가

MySQL 데이터베이스를 생성하고 Spring 애플리케이션을 빌드한 후 새로 생성된 데이터베이스에 연결합니다.

MySQL은 GPL 라이선스를 받았으므로 MySQL과 함께 배포하는 모든 프로그램 바이너리도 GPL을 사용해야 합니다. GNU 일반 공중 사용 허가서를 참조하세요.

Starting with Spring Initializr

Create the Database

터미널(Microsoft Windows의 명령 프롬프트)을 열고 새 사용자를 생성할 수 있는 사용자로 MySQL 클라이언트를 엽니다.

예를 들어 Linux 시스템에서는 다음 명령을 사용합니다.

$ sudo mysql --password

이는 루트로 MySQL에 연결하고 모든 호스트에서 사용자에 대한 액세스를 허용합니다. 이는 프로덕션 서버에 권장되는 방법이 아닙니다.

새 데이터베이스를 생성하려면 mysql 프롬프트에서 다음 명령을 실행합니다.

mysql> create database db_example; -
mysql> create user 'springuser'@'%' identified by 'ThePassword'; 
mysql> grant all on db_example.* to 'springuser'@'%'; 

Create the application.properties File

Spring Boot는 모든 것에 대한 기본값을 제공합니다. 예를 들어 기본 데이터베이스는 H2입니다. 따라서 다른 데이터베이스를 사용하려면 application.properties 파일에서 연결 속성을 정의해야 합니다.

다음 목록에 표시된 대로 src/main/resources/application.properties라는 리소스 파일을 만듭니다.

spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.jpa.show-sql: true

여기서 spring.jpa.hibernate.ddl-autonone, update, create 또는 create-drop일 수 있습니다. 자세한 내용은 Hibernate 문서를 참조하세요.

  • none: MySQL의 기본값입니다. 데이터베이스 구조는 변경되지 않습니다.

  • update: Hibernate는 주어진 엔터티 구조에 따라 데이터베이스를 변경합니다.

  • create: 매번 데이터베이스를 생성하지만 닫을 때 삭제하지 않습니다.

  • create-drop: 데이터베이스를 생성하고 SessionFactory가 닫힐 때 삭제합니다.

아직 데이터베이스 구조가 없기 때문에 create 또는 update부터 시작해야 합니다. 첫 번째 실행 후 프로그램 요구 사항에 따라 update 또는 none으로 전환할 수 있습니다. 데이터베이스 구조를 일부 변경하려면 update를 사용하십시오.

H2 및 기타 내장 데이터베이스의 기본값은 create-drop입니다. MySQL과 같은 다른 데이터베이스의 경우 기본값은 none입니다.

데이터베이스가 프로덕션 상태가 된 후에는 이를 none으로 설정하고 Spring 애플리케이션에 연결된 MySQL 사용자의 모든 권한을 취소하고 MySQL 사용자에게 SELECT, UPDATE, INSERTDELETE만 제공하는 것이 좋은 보안 관행입니다. 이에 대한 자세한 내용은 이 가이드 끝부분에서 확인할 수 있습니다.

@Entity 모델 만들기

다음 목록(src/main/java/guides/accessingdatamysql/User.java)에 표시된 대로 엔터티 모델을 생성해야 합니다.

package guides.accessingdatamysql;


import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity // Hibernate에게 이 클래스로부터 테이블을 만들라고 말함
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    private String email;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Hibernate는 자동으로 엔터티를 테이블로 변환합니다.

저장소 생성

다음 목록(src/main/java/repository/accessingdatamysql/UserRepository.java)에 표시된 대로 사용자 레코드를 보관하는 저장소를 생성해야 합니다.


package guides.accessingdatamysql;

import org.springframework.data.repository.CrudRepository;

// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete
public interface UserRepository extends CrudRepository<User, Integer> { }

Spring은 동일한 이름을 가진 빈에서 이 저장소 인터페이스를 자동으로 구현합니다(대소문자가 변경되어 userRepository라고 함).

컨트롤러 생성

다음 목록(src/main/java/guides/accessingdatamysql/MainController.java)에 표시된 대로 애플리케이션에 대한 HTTP 요청을 처리하는 컨트롤러를 생성해야 합니다.

package guides.accessingdatamysql;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller // This means that this class is a Controller
@RequestMapping(path="/demo")  // This means URL's start with /demo (after Application path)
public class MainController {

    @Autowired // This means to get the bean called userRepository
    // Which is auto-generated by Spring, we will use it to handle the data
    private UserRepository userRepository;

    @PostMapping(path="/add")
    public @ResponseBody String addNewUser (@RequestParam String name, @RequestParam String email) {
        // @ResponseBody means the returned String is the response, not a view name
        // @RequestParam means it is a parameter from the GET or POST request

        User n = new User();
        n.setName(name);
        n.setEmail(email);
        userRepository.save(n);
        return "Saved";
    }

    @GetMapping(path="/all")
    public @ResponseBody Iterable<User> getAllUsers() {
        // This returns a JSON or XML with the users
        return userRepository.findAll();
    }
}

앞의 예에서는 두 엔드포인트에 대해 POSTGET을 명시적으로 지정합니다. 기본적으로 @RequestMapping은 모든 HTTP 작업을 매핑합니다.

애플리케이션 클래스 생성

Spring 초기화는 애플리케이션을 위한 간단한 클래스를 생성합니다. 다음 목록은 이 예제를 위해 초기화가 생성한 클래스(src/main/java/guides/accessingdatamysql/AccessingDataMysqlApplication.java)를 보여줍니다.

package guides.accessingdatamysql;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataMysqlApplication {

    public static void main(String[] args) {
        SpringApplication.run(AccessingDataMysqlApplication.class, args);
    }

}

애플리케이션 테스트

이제 애플리케이션이 실행되고 있으므로 curl이나 유사한 도구를 사용하여 테스트할 수 있습니다. 테스트할 수 있는 두 개의 HTTP 엔드포인트가 있습니다.

  • GET localhost:8080/demo/all: 모든 데이터를 가져옵니다.
  • POST localhost:8080/demo/add: 데이터에 한 명의 사용자를 추가합니다.

다음 curl 명령은 사용자를 추가합니다.

$ curl http://localhost:8080/demo/add -d name=First -d email=someemail@someemailprovider.com

응답은 다음과 같아야 합니다.

Saved

다음 명령은 모든 사용자를 표시합니다.

$ curl http://localhost:8080/demo/all

응답은 다음과 같아야 합니다.

[{"id":1,"name":"첫번째","email":"someemail@someemailprovider.com"}]

데이터베이스 조회해보기

sudo mysql
show databases;
show tables;
select * from user;

일부 보안 변경

프로덕션 환경에서는 SQL 주입 공격에 노출될 수 있습니다. 해커는 DROP TABLE 또는 기타 파괴적인 SQL 명령을 주입할 수 있습니다. 따라서 보안을 위해 애플리케이션을 사용자에게 공개하기 전에 데이터베이스를 일부 변경해야 합니다.

다음 명령은 Spring 애플리케이션과 관련된 사용자의 모든 권한을 취소합니다.

revoke all on db_example.* from 'springuser'@'%';

이제 Spring 애플리케이션은 데이터베이스에서 아무 것도 할 수 없습니다.

애플리케이션에는 일부 권한이 있어야 하므로 다음 명령을 사용하여 애플리케이션에 필요한 최소 권한을 부여하세요.

grant select, insert, delete, update on db_example.* to 'springuser'@'%';

모든 권한을 제거하고 일부 권한을 부여하면 Spring 애플리케이션에 구조(스키마)가 아닌 데이터베이스의 데이터만 변경하는 데 필요한 권한이 제공됩니다.

데이터베이스를 변경하려는 경우:
1. 권한을 다시 부여합니다.
2. spring.jpa.hibernate.ddl-auto를 변경하여 update하세요.
3. 응용 프로그램을 다시 실행하십시오.

그런 다음 여기에 표시된 두 명령을 반복하여 애플리케이션을 프로덕션 용도로 다시 안전하게 만듭니다. 더 나은 방법은 Flyway 또는 Liquibase와 같은 전용 마이그레이션 도구를 사용하는 것입니다.

post-custom-banner

0개의 댓글