본문 바로가기
TIL with Programmers

[TIL] 8/23 데이터베이스, SQL, docker, mariadb, db연결, 프론트랑 백 연동하기

by 보먀 2024. 8. 23.
728x90
반응형

데이터베이스

 

데이터베이스

  • 데이터를 통합하여 효율적으로 관리하기 위한 데이터의 집합체가 데이터베이스 (Database; DB)
  • 데이터를 구조화하여 관리함으로써 데이터 중복을 막고, 효율적이고 빠른 데이터 연산을 가능하게 함

 

DBMS

  • 데이터베이스를 운영하고 관리하기 위한 DBMS(Database Management System) 을 통해 데이터베이스를 사용
  • Oracle, MySQL, MariaDB

SQL (Stuctured Query Language)

데이터베이스에 연산을 요청하기 위해 사용되는 구조화된 명령어(질의어)로 데이터를 생성, 수정, 삭제 등과 같은 기능을 수행

  • 데이터 삽입: INSERT
  • 데이터 조회: SELECT
  • 데이터 수정: UPDATE
  • 데이터 삭제: DELETE
  • 데이터 생성: CREATE

 

도커 (Doker) 

  • 도커는 응용 프로그램들을 격리하는 기술로 컨테이너를 실행하고 관리하는 오픈 소스
  • 도커 컨테이너는 일종의 소프트웨어를 소프트웨어의 실행에 필요한 모든 것을 포함하는 완전한 파일 시스템 안에 감쌈

 

 

Host Operating System : 운영체제

-> 프로그램을 돌릴 수 있게 만들어 놓은 운동장

 

원래 프로그램을 설치할 때는 OS 와 소통을 하면서 설치하는데, 프로그램은 프로그램이 돌아가기 위해 필요한 환경도 같이 구축을 한다. 

도커를 사용하면, 프로그램을 직접 컴퓨터에 설치하는 것이 아니라 도커를 한 겹 깔고 설치를 한다. 

 

실제로 도커가 어플리케이션을 설치하는 방법?

-> 도커는 컨테이너를 여러 개 들고 다니는데, 프로그램을 위한 컨테이너를 마련하고 그 공간 안에 어플리케이션을 설치해뒀다가 필요할 때 사용할 수 있도록 해줌

-> 쉽게 말해사, 어플리케이션의 환경 + 실행되는 모든 것들을 하나의 박스에 넣어놓고 필요하면 박스를 열어 작업할 수 있게 해줌

-> 도커를 사용하면 OS 가 훨씬 더 빠르고 가벼워지고, 어플리케이션도 독립적으로 움직일 수 있게 됨

 

 

도커 & mariadb 설치

 

그냥 도커를 검색해 들어가서 다운로드를 하니 Docker Errors: Incompatible CPU detected 이런 문구가 뜨면서 제대로 설치되지 않았다.  구글링하다 보니 맥북을 사용하면 종종 있는 문제 같았다. (M 칩이 들어가있으면 그런듯했음, 내 컴퓨터는 M3 Pro 칩이다) 

아무튼 아래의 링크로 들어가서 다운로드하고 설치하면 문제가 발생하지 않으니, 이 링크로 들어가서 설치하면 된다.

 

https://docs.docker.com/desktop/install/mac-install/

 

Install Docker Desktop on Mac

Install Docker for Mac to get started. This guide covers system requirements, where to download, and instructions on how to install and update.

docs.docker.com

 

 

도커에 mariadb 설치는 터미널을 켜고 아래 명령어를 입력해주면 된다. 

docker pull mariadb
docker run --name mariadb -d -p 3306:3306 --restart=always -e MYSQL_ROOT_PASSWORD=root mariadb

 

여기까지 했다면 설치는 끝났다. 이제 실행을 해보자.

 

1) mariadb 가 있는 컨테이너 접속

docker exec -it mariadb /bin/bash

 

2) mariadb 실행

mariadb -u root -p

 

실행하면 password 를 치라고 나오는데 아까 MYSQL_ROOT_PASSWORD=root 설치할 때 이 부분에서 입력한 비밀 번호, 즉 root 를 치면 된다.

 

그럼 이렇게 되는데, none 은 아직 아무 방에 들어가지 않았다는 의미이다. (일단 여기까지 했다면, 데이터를 저장할 창고까지 들어온 것)

 

 

 

데이터를 저장할 방(database) 만들고 데이터 조회 / 삽입 / 수정 / 삭제

  • 방 확인: SHOW DATABASES;
  • 방 만들기: CREATE DATABASE 방이름;
  • 방 들어가기: USE 방 이름;
  • 테이블 보기: SHOW TABLES;

 

Tennis 라는 방을 만듦.

 

1. SQL: CREATE

 

 

- 테이블 생성

# 테이블 생성 
CREATE TABLE member
(
    id VARCHAR(30),
    name VARCHAR(30),
    pwd VARCHAR(30)
);

 

 

 

USE Tennis(방 들어감) -> SHOW TABLES(테이블 확인 -> empty set -> 테이블 생성 -> SHOW TABLES(테이블 확인 -> member 테이블 생김)

 

2. SQL: SELECT, INSERT

 

테이블 데이터 삽입: INSERT 컬럼명1, 컬럼명2, ... INTO 테이블명 VALUES (컬럼1 데이터, 컬럼2 데이터, ...);

INSERT INTO member VALUES ('ssongCoding', 'kim songa', 'aaaaa');
INSERT INTO member VALUES ('tennisking', 'park songa', 'bbbbb');
INSERT INTO member VALUES ('programmers', 'song songa', 'ccccc');

 

※ 추가

컬럼명을 생략하는 것과 안하는 것의 차이가 있는지 궁금해서 찾아보았다. 

INSERT 할 때 컬럼명은 생략하고 위 코드처럼 쓸 수 있는데, 데이터베이스의 구조 변경시 데이터가 잘못 삽입될 가능성이 있기 때문에 컬럼명을 적어주는 것이 더 안정적이라고 한다!

 

 

테이블 조회:

 

컬럼명을 모두 출력하고 싶을 때는

SELECT * FROM 테이블이름

 

특정 데이터를 찾고 싶을 때는 

SELECT 컬럼명 FROM 테이블이름 WHERE 조건
# 또는 SELECT * FROM 테이블이름 WHERE 조건

 

3. SQL: UPDATE, DELETE

 

테이블 데이터 수정: UPDATE 테이블명 SET 컬럼명 = 수정할 값 WHERE 조건;

UPDATE member SET pwd = 'zzzzz' WHERE id='tennisking';

주의할 점은 데이터를 수정할 때 꼭 조건을 걸어줘야 한다. 조건을 걸지 않고 수정을 하게 되면 전체 데이터가 수정된다. 

 

테이블 데이터 삭제: DELETE FROM 테이블명 WHERE 조건;

 

DELETE FROM member WHERE name='park songa';

DELETE 도 UPDATE 와 마찬가지로 조건을 걸어주지 않으면 다 테이블 안에 데이터가 모두 삭제되니 주의하기!

 

 

Node.js 에 DB 연결하기 + Node.js 에 프론트 연동하기

 

node.js 파일이 있는 폴더에 가서 터미널을 열고 명령어를 쳐서 mysql 모듈 받기

npm install mysql __save

 

근데 나는 위의 명령어를 사용하니 에러남.. 열심히 구글링해보니 __save 옵션이 문제였다. 

__save 옵션은 모듈을 설치할 때 pakage.json 의 dependency 항목에 자동으로 추가하는 명령어인데, npm@5 부터는 __save 옵션이 기본이 되어 npm install 모듈명으로만 실행해도 설치된 모듈은 자동으로 dependency 항목에 추가된다고 한다!

 

옵션 떼고 쓰니 설치 완료

npm install mysql

 

 

설치한 mysql 모듈 불러오기

// index.js

const mariadb = require('mysql');

const conn = mariadb.createConnection(
    {   
        host: 'localhost',
        port: 3306, 
        user: 'root',
        password: 'root',
        database: 'Tennis'
    }
);

module.exports = conn;

 

 

 

메인 페이지 연동하기

 

fs 모듈로 연결할 html 파일을 가져와서 response.write 의 인자로 main_view 를 넣어주었다. 

response.query 로 sql 문을 던져 db데이블 데이터를 콘솔창에 출력해하도록 코드를 짰다. 

// requestHandler.js

const fs = require('fs'); // 이 모듈을 가지고 만들어둔 html 가져올 수 있음
const main_view = fs.readFileSync('./main.html', 'utf-8'); // 읽어와달라

const mariadb = require('./database/connect/mariadb');

function main(response) {
    console.log('main');

    mariadb.query("SELECT * FROM product", function(err, rows) {
        console.log(rows);
    });

    response.writeHead(200, {'Content-Type' : 'text/html'});
    response.write(main_view);
    response.end();
}

let handle = {}; // key:value
handle['/'] = main;

exports.handle = handle;

 

 

db 에 있는 Tennis Product 테이블

id name description price
1 Red Racket Hot Red! 300000
2 Blue Racket Cool Blue! 350000
3 Black Racket Chick Black! 500000

 

출력

 

 

 

그런데 문제가 생겼다. 서버를 실행시켰는데, 이미지가 제대로 뜨지 않는다. 

서버에서 pathname 을 읽어서 router -> requestHandler 로 넘겨주는데, 이미지가 경로로 읽히기 때문이다.  

 

redRacket, blueRacket, blackRacket 함수로 red/blue/black 라켓의 이미지 경로에 대한 요청을 처리해주면 이미지가 정상적으로 뜨는 것을 확인할 수 있다. 

// requestHandler.js

const fs = require('fs'); // 이 모듈을 가지고 만들어둔 html 가져올 수 있음
const main_view = fs.readFileSync('./main.html', 'utf-8'); // 읽어와달라

const mariadb = require('./database/connect/mariadb');

function main(response) {
    console.log('main');

    response.writeHead(200, {'Content-Type' : 'text/html'});
    response.write(main_view);
    response.end();
}

function redRacket(response) {
    fs.readFile('./img/redRacket.png', function(err, data) {
        response.writeHead(200, {'Content-Type' : 'text/html'});
        response.write(data);
        response.end();
    })
}

function blueRacket(response) {
    fs.readFile('./img/blueRacket.png', function(err, data) {
        response.writeHead(200, {'Content-Type' : 'text/html'});
        response.write(data);
        response.end();
    })
}

function blackRacket(response) {
    fs.readFile('./img/blackRacket.png', function(err, data) {
        response.writeHead(200, {'Content-Type' : 'text/html'});
        response.write(data);
        response.end();
    })
}

let handle = {}; // key:value
handle['/'] = main;

/* img directory */
handle['/img/redRacket.png'] = redRacket;
handle['/img/blueRacket.png'] = blueRacket;
handle['/img/blackRacket.png'] = blackRacket;

exports.handle = handle;

 

order 버튼을 눌러 아이템을 orderlist 에 추가하기

// server.js

let http = require('http');
let url = require('url');

function start(route, handle) {
    function onRequest(request, response) {
        let pathname = url.parse(request.url).pathname; 
        let queryData = url.parse(request.url, true).query; // 쿼리 가져오기
        
        // 파비콘 처리
        if (pathname === '/favicon.ico') {
            response.writeHead(200, { 'Content-Type': 'image/x-icon' });
            return response.end();
        }
        // 쿼리데이터를 라우터에 인자로 줌
        route(pathname, handle, response, queryData.productId); 
    }
    
    http.createServer(onRequest).listen(8888);
}

exports.start = start;
// requestHandler.js

const fs = require('fs'); 
const main_view = fs.readFileSync('./main.html', 'utf-8'); // 읽어와달라
const mariadb = require('./database/connect/mariadb'); // 마리아db 가져오기

// ...

function order(response, productId) { // order 버튼 눌렀을 때 요청 처리, productId는 라우터에서 인자로 받음
    response.writeHead(200, {'Content-Type' : 'text/html'});
	
    // 쿼리문으로 데이터베이스에 데이터 넣어주기
    mariadb.query("INSERT INTO orderlist VALUES (" + productId + ", '" + new Date().toLocaleDateString() + "');", function(err, rows) {
        console.log(rows);
    })
    response.write('order page');
    response.end();
}

let handle = {}; 
handle['/'] = main;
handle['/order'] = order;

/* img directory */
handle['/img/redRacket.png'] = redRacket;
handle['/img/blueRacket.png'] = blueRacket;
handle['/img/blackRacket.png'] = blackRacket;

exports.handle = handle;

 

 

오더리스트 페이지 연동

 

mariadb.query 로 db 에서 데이터를 가져와서 테이블로 만듦. 

// requestHandler.js

const fs = require('fs');
const main_view = fs.readFileSync('./main.html', 'utf-8'); 
const orderlist_view = fs.readFileSync('./orderlist.html', 'utf-8');
const mariadb = require('./database/connect/mariadb');

// ...

function orderList(response) {
    response.writeHead(200, {'Content-Type' : 'text/html'});
    mariadb.query("SELECT * FROM orderlist;", function(err, rows) {
        response.write(orderlist_view); // 오더리스트 html 가져옴 
        console.log(rows);
		
        // db에서 가져온 데이터를 table로 만들어줌
        rows.forEach(element => {
            response.write("<tr>"
                + "<td>" + element.product_id + "</td>"
                + "<td>" + element.order_date + "</td>"
                + "</tr>"
            );
        });
        response.write("</table>");
        response.end();
    })    
}

let handle = {}; // key:value
handle['/'] = main;
handle['/order'] = order;
handle['/orderlist'] = orderList;

/* img directory */
handle['/img/redRacket.png'] = redRacket;
handle['/img/blueRacket.png'] = blueRacket;
handle['/img/blackRacket.png'] = blackRacket;

exports.handle = handle;
728x90
반응형