코드스쿼드 13주차 -4

Mysql 날짜 데이터 - Timestamp 와 Datetime

Datetime

  • 1000-01-01 00:00:00부터 9999-12-31 23:59:59까지 지원

Timestamp

  • 1970-01-01 00:00:01부터 2038-01-19 03:14:07까지 지원
  • Index가 더 빠르게 생성된다.

DatetimeTimestamp 의 차이는, Timestamp는 DB에 설정 된 time_zone 환경변수를 기반으로 데이터가 변경된다는 점 이다. time_zone 설정에 의존하기 때문에 2011-08-21 14:11:09 라는 데이터가 Datetime 컬럼과, Timestamp 컬럼에 각각 저장되어 있는 상태에서

SET TIME_ZONE = "america/new_york";

Query OK, 0 rows affected (0.00 sec)

위와 같은 형태로 time_zone 설정을 변경해주면,

 select * from datedemo;
+---------------------+---------------------+
| mydatetime          | mytimestamp         |
+---------------------+---------------------+
| 2011-08-21 14:11:09 | 2011-08-21 04:41:09 |
+---------------------+---------------------+
1 row in set (0.00 sec)

timestamp 타입으로 설정한 데이터의 저장값이 변경된다.


Q. 위의 내용을 찾아보았을 때, Timestamp가 지원하는 날짜가 얼마 남지 않았다는 점만 제외하면 유동적으로 대응할 수 있는 Timestamp가 더 좋아보이고, Datetime의 장점은 없는 것이 아닌가? 하는 의문이 들었다. 관련된 내용을 찾아 보았으나

해외 서비스를 제공하는 경우 DatetimeTimestamp를 적절히 섞어 사용하는 것이 좋다.

라는 내용을 보았을 뿐 속 시원히 해결되지 않았다.

A. 고민하던 중 Lee가 좋은 생각을 말씀해 주셨는데, 데이터가 작성된 위치(timezone)와 시각이 데이터로 정확히 기록되어야 하는 경우 Datetime을, timezone에 따라서 저장된 데이터의 시간이 다르게 활용되는 경우에는 Timestamp를 사용하지 않을까? 라는 내용을 말씀해 주셨다.

즉, DB의 timezone 설정이 변경된다면, Timestamp 형식은 처음 저장했던 데이터가 어느 지역에서, 어느 시간에 기록 됐는지 정확하게 파악할 방법이 없지만, Datetime의 경우, 저장시점의 timezone과 시간이 기록되므로, DB가 저장 된 서버의 timezone 설정이 변경 되거나, 외부 요인에 의해 변경 되더라도 데이터가 변경되지 않는다.

sns를 예로 들면,

  • 한국에 사는 A가 작성한 글을 보았을 때 미국에 사는 친구 B가 읽더라도 1분 전 작성된 글 입니다. 라고 표시되길 원할 경우 Timestamp의 형태로 저장하면 편리할 것이고,
  • 해당 글이 서버 환경 설정에 영향을 받지 않고 언제나 한국에서, 1분 전 작성된 글 입니다. 라고 표시되길 원할 경우, Datetime의 형태로 저장하면 좋을 것이다.

Timezone 설정의 우선순위

timezone 설정은, OS 수준에서의 설정, Mysql 자체 설정 변경, 접속하는 클라이언트 수준에서의 변경의 방법이 있다.

현재 테스트에 사용한 DB는 timezone 설정이 되어 있지 않은 상태이다.
DB 설정이 되어 있지 않은 경우, SYSTEM 환경 변수 설정을 따라가게 되어 있다. timezone 설정의 우선 순위는

  1. 클라이언트 수준에서의 설정
  2. DB 설정
  3. OS 설정

의 우선순위를 갖고 있다.

우리가 Java 코드에서 DB와 연결을 맺을 때 DB url을 입력하고 뒤에 붙는 serverTimezone 설정이 사용자 수준의 timezone 설정이다.

String url = "jdbc:mysql://localhost/testDB?serverTimezone=UTC";

프로젝트 중 발생한 문제들과 해결과정

외래키 Contraint 설정 바꾸기

참조 : https://prinha.tistory.com/entry/MySQL-PRIMARY-KEY-FOREIGN-KEY-%EC%84%A4%EC%A0%95%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95

외래키 설정 에러

테이블을 만드는 과정에서 아래와 같은 에러가 났다.

foreign key의 제약조건을 만족하지 않았을 경우 생기는 에러라고 한다. user 테이블의 primary keyidnickname 2개로 설정하였기 때문에 발생 하였는데

DB에서 테이블은 오직 하나의 기본키(PK)를 가질 수 있다.

라는 것이 정확한 정의라고 한다. 포인트는 이 문장을 PK를 오직 하나의 컬럼만으로 설정할 수 있다고 해석하면 안된다는 점이다.

위 테이블에서 PK로 설정된 id, nickname는 두 컬럼을 합쳐서 봤을 때 중복이 아니라면 데이터가 입력될 수 있다. 예를 들자면,

PK의 속성으로 idnickname 두 컬럼이 있다면

  • [ id = 1, nickname = 1 ]
  • [ id = 1, nickname = 2 ] 는 중복된 데이터가 아니기 때문에 정상적으로 저장이 된다.

즉, 복합키(Composite Key)를 만드는 것이지 기본키(PK)가 복수가 되는 것이 아니라는 것이다.

외래키는 유일한 데이터 하나만을 참조해야 하는데, 외래키는 user의 nickname으로만 참조한다고 설정해 버리면 nickname 컬럼에는 중복 된 값이 존재할 수 있기 때문에 외래키 제약조건을 추가하지 못하는 에러가 발생한 것이다.

## 추가로,

user 테이블에서 기본키를 idnickname 2개로 복합키로 만드는 것 또한 처음 의도했던 바와 다른 구조로 만들었음을 알게 되었다.

처음 생각으로는 사용자는 id와 마찬가지로 nickname도 유일한 1개의 값만을 가져야 하기 때문에 nickname도 유일한 값으로 설정되어야 한다고 생각하여 기본키로 설정하였지만, 기본키를 2개로 지정하면 위의 예시와 같이, 복합키로 설정되게 되고

이는 id는 동일, nickname만 다른경우 혹은 nickname은 동일, id만 다른경우 DB는 중복된 값이 아니라고 판단하여 데이터 저장이 가능하게 된다.

따라서 idprimary key로 설정하고, nicknameunique key로 설정하는 것으로 변경하였다.

## Primary Key 와 Unique Key

1. PRIMARY KEY

유일한 레코드를 만들려면 다른 칼럼과 구별하고자 특별한 속성을 설정해야 한다.
이럴 때 사용하는 것이 기본 키 PRIMARY KEY 이다.

기본 키는 다음과 같은 특징을 갖는다.

  • 값이 중복되지 않는다.
  • 반드시 값을 입력해야 한다. (Null값이 올 수 없다)
  • 테이블 데이터의 고유 인식번호 (id)

2. UNIQUE KEY

고유 키는 다음과 같은 특징을 갖는다.

  • 값이 중복되지 않는다.
  • 값을 입력하지 않아도 된다. (Null값을 허용)
  • 중복되면 안되는 데이터 (주민등록번호, 이메일 주소 등)

테이블 생성 시 warning 에러

위의 문제를 해결한 후, task 테이블 생성 쿼리를 날려 테이블은 생성 되었으나 warning이 발생했다.

SHOW WARNINGS;

쿼리를 날리면 발생한 경고를 확인할 수 있는데,

mysql 8.0.17 버전부터 int datatype의 width를 설정하는 것을 더이상 지원하지 않고 향후 버전부터 제거될 기능 중 하나이기 때문에 발생하는 경고라고 한다.


좋은 웹페이지 즐겨찾기