데브코스 웹풀스택 과정/TIL

0930 타임 존(timezone) 설정, 디비 연동 및 쿼리 가져오기

thinktank911 2025. 9. 30. 16:04

ZEROFILL 옵션

  • 데이터를 저장하거나 표시할 때 지정된 길이에 맞춰 숫자 앞을 0으로 채우는 기능
  • MySQL 의 int, tinyint 등 정수형 타입과 함께 사용
  • ex> INT(5) ZEROFILL로 선언된 컬럼에 숫자 '1'이 저장되면, 결과는 '00001'로 표시

 

DB 연동

// A simple SELECT query
connection.query(
'SELECT * FROM users',
function (err, results, fields) {
    console.log(err);
    console.log(results); // results contains rows returned by server
    console.log(fields); // fields contains extra meta data about results, if available
}
);
  • results : 쿼리 결과
  • fields : 테이블정의. 메타 데이터

 

timezone 추가

  • DB의 created_at 시간 값을 노드 서버에 가져올 때 DB 시간대와 다르다
conn.query(
  'SELECT * FROM `users`',
  function (err, results, fields) {
    var {id, email, name, created_at} = results[0];

    console.log(id);
    console.log(email);
    console.log(name);
    console.log(created_at);
  }
);

 

1) node에서 timezone 설정

- 무시됨


2) db에서 timezone 설정

  • 전체 데이터베이스의 timezone을 'Asia/Seoul'로 변경 => 바뀌지 않음
  • 현재 session의 timezone을 바꿈 => 한국 시간으로 잘 나옴
  • 타임존이 제대로 설정되었는지 조회
-- 전체 데이터베이스 timezone 설정
SET GLOBAL time_zone = 'Asia/Seoul';

-- 현재 session timezone 설정
SET time_zone = 'Asia/Seoul';

-- 타임존 설정값 조회
SELECT @@global.time_zone, @@session.time_zone;

 

3) node에서 dateStrings값 true로 변경

  • connection 프로퍼티의 dateStrings을 true로 추가
    • 날짜를 출력할 때 뒤에 Z가 붙는데 해당시간이 UTC (세계 협정시) 기준임을 나타내는 표시
      => Z를 빼고 YYYY-MM-DD HH:MM:SS 날짜 형식대로 표기되도록 하는 역할

db 모듈화

  • mariadb.js에서 connection 모듈을 export 해준다.
// db 모듈화
module.exports = connection

 

  • mariadb.js에 있던 connection.query를 users.js로 옮겨서 구현해보기

 

SELECT SQL 쿼리 형식 - 로그인

conn.query(sql문,변수,콜백함수(err, results, fields))
  • sql문 안에 변수는 ?로 표시한다.
  • conn.query의 두번째 매개변수에 ?에 들어갈 변수를 작성
  • 콜백함수의 인자는 순서대로 err, results, fields로 생략 가능하나 순서를 잘 지켜서 작성해줘야 한다.
// 로그인
router.post('/login',(req,res)=>{
    const {email, pwd} = req.body
    // SELECT 쿼리문
    conn.query(`SELECT * FROM users WHERE email= ?`, email,
        function (err, results) {
            var loginUser = results[0]

            if(loginUser && loginUser.pwd === pwd){
                res.status(200).json({
                    message : `${loginUser.name}님 환영합니다.`
                })
            }

 

INSERT SQL 쿼리 형식 - 회원가입

conn.query('insert sql문',변수배열,콜백함수)
  • INSERT문 안에 변수는 똑같이 ?로 표시해준다.
  • 변수가 여러 개인 경우 배열로 받을 수 있다.
// 회원가입
router.post('/join',(req,res)=>{
    const userInfo = req.body
   
    if(Object.keys(userInfo).length > 0){
        const {email, name, pwd, contact} = userInfo
        // INSERT 쿼리문
        conn.query(`INSERT INTO users (email, name, pwd, contact)
            VALUES (?, ?, ?, ?)`, [email, name, pwd, contact],
            function (err, results) {
                if(results.length){
                    res.status(201).json(results)

 

DELETE SQL 쿼리 형식 - 회원삭제

  • SELECT문과 동일하게 SQL문 변수에 ? 작성하고, 두번째 인자에 변수 담는다.
.delete((req,res)=>{
        let {email} = req.body
        // DELETE 쿼리문
        conn.query(`DELETE FROM users WHERE email= ?`, email,
            function (err, results) {
                if(results.length){
                    res.status(200).json(results)
                }
                else{
                    res.status(404).json({
                        message : "존재하지 않는 회원입니다."
                    })
                }
            }
        );

 

users.js 코드정리 - 리팩토링

  • 필요없는 코드 없애기
    • 변경 전 : if문이 중첩되어 복잡하다.
    • 1차 변경 : login정보유무와 비밀번호 일치 여부 조건을 합친다.
    • 변경 후 : else 예외처리 메세지를 요즘 트렌드인 '아이디 또는 비밀번호가 일치하지 않습니다'로 바꿔 else if문을 날린다.
// 변경 전
var loginUser = results[0]

if(loginUser){
	if(loginUser.pwd === pwd){
    	res.status(200).json({
            message : `${loginUser.name}님 환영합니다.`
        })
    }
    else{
        res.status(400).json({
            message : "비밀번호가 일치하지 않습니다."
        })
    }
}
else{
    res.status(404).json({
        message : "회원 정보가 없습니다."
    })
}

// 1차 변경
var loginUser = results[0]

if(loginUser && loginUser.pwd === pwd){
    res.status(200).json({
        message : `${loginUser.name}님 환영합니다.`
    })
}
else if(loginUser && loginUser.pwd !== pwd){
    res.status(400).json({
        message : "비밀번호가 일치하지 않습니다."
    })
}
else{
    res.status(404).json({
        message : "회원 정보가 없습니다."
    })
}
// 변경 후
if(loginUser && loginUser.pwd === pwd){
    res.status(200).json({
        message : `${loginUser.name}님 환영합니다.`
    })
}
else{
    res.status(404).json({
        message : "아이디 또는 비밀번호가 일치하지 않습니다."
    })
}

 

  • 주석 수정 : 코드를 보고 알 수 있으면 지우기
  • 문자열 오타 수정 및 변수로 sql문과 values 빼기

 

단축 평가

  • 단축 평가는 && (논리곱) 또는 || (논리합) 같은 논리 연산자를 사용할 때, 표현식의 결과가 이미 확정되었다면 나머지 피연산자 평가를 생략하는 기능이다. 이를 통해 불필요한 연산을 줄여 성능을 향상시키고, if 문 없이 조건부 로직을 간결하게 작성할 수 있
let sql = `SELECT * FROM channels WHERE user_id = ?`
// 단축평가 : 앞에 먼저 true/false 체크하고 true면 다음 조건 체크
userId && conn.query(sql, userId,
    function (err, results) {
        if(results.length){
            res.status(200).json(results)
            return
        }else{
            notFoundChannel(res)
            return
        }
    }
)
res.status(400).end()
  • 단축 평가를 통해 적절한 값을 얻을 수 있을 때 사용한다. channel.js의 채널 전체 조회 api 예외 처리는 if문을 사용하겠다.
if(userId){
    conn.query(sql, userId,
        function (err, results) {
            if(results.length){
                res.status(200).json(results)
                return
            }else{
                notFoundChannel(res)
                return
            }
        }
    )
}
else{
    res.status(400).end()
}

 


DB의 시간대가 이상하게 저장될 때, 서버에서 이상하게 출력될 때 TIMEZONE이 어떻게 셋팅되어 있는지 확인하고 셋팅할 수 있는 방법에 대해 배웠다. MYSQL에 ZEROFILL이 있어서 신기했다. 오라클을 사용할 땐 직접 LPAD()나 RPAD() 메소드 써서 채워줬다. conn.query 메소드를 이용해 sql문을 직접 가져와서 db 결과를 가져왔는데, 이를 공통함수로 빼서 구현할 수 있는지 여부와 프로시저를 사용했을 때 서버 호출법에 대해 더 알아봐야겠다.