// SampleDAOImpl@Repository// @Qualifier를 이용해서 SampleDAOImpl에 'normal'이라는 이름 지정@Qualifier("normal")publicclassSampleDAOImplimplementsSampleDAO{
}
// EventSampleDAOImpl@Repository// @Qualifier를 이용해서 EventSampleDAOImpl에 'event'라는 이름 지정@Qualifier("event")publicclassEventSampleDAOImplimplementsSampleDAO{
}
- SampleService에서 @Qualifier를 이용해 이름을 지정하면 해당 이름의 SampleDAO 객체를 사용
// TodoListController에서 다음과 같이 객체 활용 가능package org.zerock.w2.controller;
...
@WebServlet(name = "todoListController", value = "/todo/list")@Log4j2publicclassTodoListControllerextendsHttpServlet{
private TodoService todoService = TodoService.INSTANCE;
@OverrideprotectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
log.info("todo list.................");
// getServletContext() 메서드를 이용해 ServletContext를 이용할 수 있음
ServletContext servletContext = req.getServletContext();
log.info("appName: " + servletContext.getAttribute("appName"));
...
}
}
<!-- list.jsp에 다음과 같이 EL 구문을 추가하면 화면에서 나타내는 용도로 사용가능 --><body><h1>Todo List</h1><!-- appName이라는 이름을 가진 객체(W2)를 호출 --><h2>${appName}</h2><h2>${loginInfo}</h2><h3>${loginInfo.mname}</h3>
...
</body>
${appName}을 입력하여, appName을 이름으로 하는 객체 "W2"를 출력
ServletContextListener와 스프링 프레임워크
ServletContextListener와 ServletContext를 이용하면 프로젝트 실행 시 필요한 객체들을 준비하는 작업 처리 가능
커넥션 풀 초기화 또는 TodoService 같은 객체 미리 생성해서 보관 등
특히, 스프링 프레임워크에서 웹 프로젝트를 미리 로딩하는 작업을 처리할 때 ServletContextListener 이용
실습
2) 세션 관리 리스너
- Servlet의 리스너 중 HttpSession 관련 작업을 감시하는 리스너 등록 가능
(HttpSessionListener나 HttpSessionAttributeListener 등)
- 이를 이용해서 HttpSession이 생성되거나 setAttribute() 등의 작업이 이루어질 때를 감지 가능
- LoginListener는 HttpSessionAttributeListener 인터페이스를 구현
- HttpSessionAttributeListener 인터페이스는 attributeAdded(), attributeRemoved(), attributeReplaced() 를 이용해서, HttpSession에 setAttribute() / removeAttribute() 등의 작업을 감지
// LoginControllerpackage org.zerock.w2.controller;
import lombok.extern.log4j.Log4j2;
import org.zerock.w2.dto.MemberDTO;
import org.zerock.w2.service.MemberService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.UUID;
@WebServlet("/login")@Log4j2publicclassLoginControllerextendsHttpServlet{
...
@OverrideprotectedvoiddoPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
log.info("login post.............");
String mid = req.getParameter("mid");
String mpw = req.getParameter("mpw");
String auto = req.getParameter("auto");
boolean rememberMe = auto != null && auto.equals("on");
try {
MemberDTO memberDTO = MemberService.INSTANCE.login(mid, mpw);
// rememberMe라는 변수가 true(auto 값이 있고 그 값이 "on"이라면, 즉 자동 로그인이 설정되어 있다면)// UUID(java.util 중 임의의 숫자 생성하는 도구)를 이용해서 임의의 번호 생성if(rememberMe) {
String uuid = UUID.randomUUID().toString();
MemberService.INSTANCE.updateUuid(mid, uuid);
memberDTO.setUuid(uuid);
}
// 정상적으로 로그인 된 경우, HttpSession을 이용해서 'loginInfo'라는 이름으로 객체 저장
HttpSession session = req.getSession();
session.setAttribute("loginInfo", memberDTO);
resp.sendRedirect("/todo/list");
} catch (Exception e) { // 예외 발생 시 '/login'으로 이동, result라는 파라미터를 전달해서 문제가 발생했다는 사실 전달
resp.sendRedirect("/login?result=error");
}
}
}
- 결과
로그인 화면에 자동로그인을 설정할 체크박스 생성됨체크 상태로 로그인하면 uuid가 새로 추가된 모습데이터베이스의 테이블에도 추가된 uuid 값
- 쿠키의 생성 및 전송: 쿠키에 들어가야 하는 문자열이 제대로 처리되었다면 브라우저에 'remember-me' 이름의 쿠키 생성해서 전송
// LoginController에서 rememberMe 변수가 있을 때 수행하는 코드 부분 변경if(rememberMe) {
String uuid = UUID.randomUUID().toString();
MemberService.INSTANCE.updateUuid(mid, uuid);
memberDTO.setUuid(uuid);
Cookie rememberCookie = new Cookie("remember-me", uuid);
rememberCookie.setMaxAge(60*60*24*7);
rememberCookie.setPath("/");
resp.addCookie(rememberCookie);
}
- 결과
응답 헤더에 Set-Cookie에 remember-me가 전송됨쿠키도 다음과 같이 확인 가능
브라우저에서 최초로 서버 호출 시 해당 서버에서 발행한 쿠키가 없다면 브라우저는 아무것도 전송 x
서버에서 응답 메세지 보낼 때, 브라우저에 쿠키를 보내는데 이때 'Set Cookie'라는 HTTP 헤더 이용
브라우저는 쿠키를 받은 후 이에 대한 정보를 읽고, 파일 형태로 보관할 지 메모리상에서만 처리할 지 결정(쿠키에 있는 유효기간(만료기간)을 보고 결정)
브라우저에 보관하는 쿠키는 다음에 다시 브라우저가 서버에 요청할 때 HTTP 헤더에 'Cookie'라는 헤더 이름과 함께 전달(쿠키에는 경로를 지정할 수 있어서 해당 경로에 맞는 쿠키 전송)
서버에서는 필요에 따라서 브라우저가 보낸 쿠키를 읽고 사용
1) 쿠키를 생성하는 방법
서버에서 자동으로 생성하는 쿠키: 응답 메세지를 작성할 때 정해진 쿠키가 없는 경우 자동으로 발행(WAS에서 발행되며 WAS마다 고유한 이름 사용(톰캣은 JSESSIONID))
서버에서 발행하는 쿠키는 기본적으로 브라우저 메모리 상에 보관, 브라우저 종료 시 쿠키는 삭제됨
서버에서 발행하는 쿠키의 경로는 '/'
개발자가 생성하는 쿠키: 개발자가 생성하는 쿠키는 서버에서 생성되는 쿠키와 다음이 다름
이름 원하는대로 지정 가능
유효기간 지정가능(유효기간 지정 시, 브라우저가 이를 파일 형태로 보관)
반드시 직접 응답에 추가해 주어야 함
경로나 도메인 등을 지정 가능(특정 서버의 경로를 호출하는 경우에만 쿠키 사용)
2. Servlet 컨텍스트와 세션 저장소
하나의 톰캣은 여러 웹 애플리케이션을 실행할 수 있음
실제 운영 시 웹 애플리케이션 마다 별도의 도메인으로 분리해서 운영됨
프로젝트 실행 경로를 '/'외에 다른 이름으로 각각 지정해서 실행하면 하나의 톰캣에서 여러 애플리케이션 실행 가능
각 애플리케이션은 자신만 사용하는 고유 메모리 영역을 생성하여 이 공간에 Servlet이나 JSP 등을 인스턴스로 만들어 서비스 제공, 이 영역을 Servlet API에서는 Servlet 컨텍스트라고 함
애플리케이션 생성 시 톰캣이 발행하는 쿠키를 관리하기 위한 메모리 영역이 하나 더 생성됨(세션 저장소)
세션 저장소는 기본적으로 키와 값을 보관하는 구조
톰캣에서 JSESSIONID가 키가 됨
새로운 JSESSIONID 쿠키가 만들어질 때마다 메모리 공간을 차지하므로 톰캣은 주기적으로 세션 저장소를 조사하며 사용하지 않는 값 정리(session-timeout 설정 이용, 기본 30분 주기마다 지정된 시간보다 오래된 값 삭제)
1) 세션을 통한 상태 유지 메커니즘
HttpServletRequest의 getSession()이라는 메서드 실행 → 톰캣에서는 JSESSIONID 이름의 쿠키가 요철할 때 있었는지 확인 → 없다면 새로운 값을 만들어 세션 저장소에 보관
A1234와 B111은 해당 공간에 login 정보가 존재하며, 서버에서 프로그램 작성 시 이를 이용해서 해당 사용자가 로그인했다는 것을 인정하는 방식
2) HttpServletRequest의 getSession()
HttpServletRequest의 getSession()은 브라우저가 보내는 정보를 이용해 다음의 작업 수행
JSESSIONID가 없는 경우: 세션 저장소에 새로운 번호로 공간을 만들고 해당 공간에 접근할 수 있는 객체 반환(새로운 번호는 브라우저에 JSESSIONID의 값으로 전송(세션 쿠키))
JSESSIONID가 있는 경우: 세션 저장소에 JSESSIONID 값을 이용해서 할당된 공간을 찾고 이 공간에 접근할 수 있는 객체 반환
getSession()의 결과물은 세션 저장소 내의 공간, 이 공간을 의미하는 타입은 HttpSession타입이며 해당 공간은 세션 컨텍스트 또는 세션이라고 함
HttpSession 타입의 객체를 이용하면 현재 사용자만의 공간에 원하는 객체를 저장 / 수정 / 삭제할 수 있음
isNew() 메서드 등으로 새롭게 공간을 만들 것인지 기존 공간 재사용할 것인지 구분 가능
3. 세션을 이용한 로그인 체크
세션을 이용한 로그인 체크 시나리오
사용자가 로그인에 성공하면 HttpSession을 이용해 해당 사용자의 공간(세션 컨텍스트)에 특정 객체를 이름과 함께 저장
로그인 체크가 필요한 컨트롤러에서 현재 사용자의 공간에 지정된 이름으로 객체가 저장되었는지 확인 → 객체가 존재한다면 해당 사용자는 로그인된 사용자로 간주 → 아니면 로그인 페이지로 이동
실습
1) 등록할 때, 로그인 체크 하기
- 로그인한 사용자만 Todo를 등록할 수 있다고 가정
- TodoRegisterController에서 doGet() 수정
// TodoRegisterController
...
@OverrideprotectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
log.info("/todo/register GET .......");
HttpSession session = req.getSession();
// 기존에 JSESSIONID가 없는 새로운 사용자if (session.isNew()) {
log.info("User with new JSESSIONID cookie");
resp.sendRedirect("/login");
return;
}
// JSESSIONID는 있지만 해당 세션 켄텍스트에 loginInfo라는 이름으로 저장된 객체가 없는 경우if (session.getAttribute("loginInfo") == null) {
log.info("User without login information");
resp.sendRedirect("/login");
return;
}
// 정상적인 경우
req.getRequestDispatcher("/WEB-INF/todo/register.jsp").forward(req, resp);
}
...
- 브라우저는 '/login'으로 redirect 됨
- HttpServletRequest의 getSession()을 호출하여 새로운 값이 생성되어 브라우저로 전송되어 저장
(JSESSIONID가 없는 채로 'todo/register' 경로에 접속했을 때, '/login'으로 redirect되고 '/login'에서 개발자 도구를 통해 register의 응답 헤더를 보면 'Set-Cookie' 헤더가 전송된 것을 확인할 수 있음 ↓)
- 로그에는 '기존에 JSESSIONID가 없는 사용자'에 대한 처리를 했을 때 나오도록 설정한 메세지가 출력됨
2) 로그인 처리 Controller 작성
- 로그인은 '/login' 경로에서 GET방식으로 로그인 화면 보여주고, POST 방식으로 실제 로그인 처리하도록 구성
- controller 패키지 내에 LoginController 클래스와 WEB-INF 폴더 내에 로그인 화면을 나타낼 login.jsp 파일 생성
- LoginController에서 POST 방식으로 파라미터 수집, HttpSession에 'loginInfo' 이름을 이용해서 간단한 문자열을 저장하도록 구성
// LoginController@OverrideprotectedvoiddoPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
log.info("login post.............");
String mid = req.getParameter("mid");
String mpw = req.getParameter("mpw");
String str = mid + mpw;
HttpSession session = req.getSession();
// HttpSession을 이용하여 setAttribute() 메서드를 사용자 공간에 loginInfo 라는 이름으로 문자열을 보관
session.setAttribute("loginInfo", str);
resp.sendRedirect("/todo/list");
}
- 결과
login 화면에서 아무 id와 pw를 입력하고 login 버튼을 누르면 정상적으로 tood/list로 redirect 됨로그인 한 사용자만 들어갈 수 있는 todo/register 경로에서 정상적으로 접근 가능
4. 필터를 이용한 로그인 체크
로그인 여부를 체크해야 하는 Controller마다 동일하게 체크하는 로직을 작성하면 같은 코드를 계속 작성해야 하므로 대부분 필터를 이용해 처리
필터: 특정 Servlet이나 JSP 등에 도달하는 과정에서 필터링하는 역할을 위해 존재하는 Servlet API
@WebFilter 어노테이션을 이용해 특정 경로에 접근 시 필터가 동작하도록 설계하면 동일 로직을 필터로 분리
필터는 한 개 이상, 여러 개 적용 가능
프로젝트에 filter 패키지 구성하고 LoginCheckFilter 클래스 추가
// LoginCheckFilterpackage org.zerock.w2.filter;
import lombok.extern.log4j.Log4j2;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
// '/todo..'로 시작하는 모든 경로에 필터링 시도@WebFilter(urlPatterns = {"/todo/*"})@Log4j2publicclassLoginCheckFilterimplementsFilter{
// doFilter()는 필터가 필터링이 필요한 로직을 구현하는 부분 @OverridepublicvoiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
log.info("Login check filter....");
// 다음 필터나 목적지(Servlet, JSP)로 갈 수 있도록 FilterChain의 doFilter()를 실행// 문제가 생겨서 더 이상 진행할 수 없다면 다음 단계로 진행하지 않고 다른 방식으로 redirect 처리
chain.doFilter(request, response);
}
}
실습
3) 로그인 체크 구현
- LoginCheckFilter에서 '/todo/...'로 시작하는 모든 경로에 접근 시 동작하도록 설정(위의 코드 구체화)
// LoginCheckFilterpackage org.zerock.w2.filter;
import lombok.extern.log4j.Log4j2;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
// '/todo..'로 시작하는 모든 경로에 필터링 시도@WebFilter(urlPatterns = {"/todo/*"})@Log4j2publicclassLoginCheckFilterimplementsFilter{
@OverridepublicvoiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
log.info("Login check filter....");
// doFilter에서 HttpServletRequest와 HttpServletResponse보다 상위 타입의 파라미터 사용// 따라서 HTTP 관련 작업을 위해 (HttpServlerRequest)request처럼 다운캐스팅 필요
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
HttpSession session = req.getSession();
// LoginController에서 로그인했을 때 세션에 loginInfo라는 이름으로 저장하도록 하였음// 이 loginInfo가 없다면 로그인하지 않은 것으로 판단되므로 LoginCheckFilter에 의해 '/login' 경로로 이동if (session.getAttribute("loginInfo") == null) {
resp.sendRedirect("/login");
return;
}
// 어떤 값이든 '/login'에서 로긍니 정보를 전달해서 로그인이 처리되면 그 이후에는 '/todo/...' 경로 이용가능
chain.doFilter(request, response);
}
}
4) UTF-8 처리 필터
- POST 방식으로 '/todo/register'를 통해 전달되는 문자열은 한글이 깨지므로 HttpServletRequest의 데이터를 SetCharacterEncoding("UTF-8")을 적용해 해결
프로젝트에 util 패키지 추가 > ModelMapper의 설정을 변경하고 쉽게 사용할 수 있는 MapperUtil을 enum으로 생성
package org.zerock.jdbcex.util;
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
publicenumMapperUtil{
INSTANCE;
private ModelMapper modelMapper;
MapperUtil() {
this.modelMapper = new ModelMapper();
// ModelMapper의 설정을 변경하려면 getConfiguration()을 이용해서 private로 선언된 필드도 접근할 수 있도록 설정을 변경this.modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE)
.setMatchingStrategy(MatchingStrategies.STRICT);
}
// get()으로 ModelMapper를 사용할 수 있도록 구성public ModelMapper get(){
return modelMapper;
}
}
- 앞서 데이터베이스에서 만든 tbl_todo 테이블의 데이터를 자바 객체로 처리하기 위해 테이블과 유사한 구조의 TodoVO 클래스와 객체 이용
- Lombok을 이용하면 반복적으로 생성하는 코드를 줄여 DTO나 VO 작성 시 편리
package org.zerock.jdbcex.domain;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
import java.time.LocalDate;
// VO는 주로 읽기 전용으로 사용하는 경우가 많으므로 @Getter 추가(getTno(), getTitle() 등을 호출 가능)@Getter// 객체 생성 시 빌더 패턴을 이용하기 위해 @Builder 추가(TodoVO.builder().build() 형태로 객체 생성 가능)@Builder@ToStringpublicclassTodoVO{
// tbl_todo 테이블의 칼럼들을 기준으로 작성private Long tno;
private String title;
private LocalDate dueDate;
privateboolean finished;
}
2. HikariCP 설정
프로젝트에서 Connection의 생성은 Connection Pool인 HikaariCP 이용
데이터베이스에서 필요한 작업을 명령하는 SQL 에디터인 HeidiSQL 프로그램이 같이 설치됨
'신규 ' 버튼을 눌러서 root 계정으로 연결
설치할 때 지정했던 암호를 입력하고 열기
데이터베이스 생성
사용자 계정 생성과 권한 추가
'사용자 관리자'에서 사용자 계정 '추가'
사용자 이름 및 암호 입력 후, 호스트설정을 모든 곳에서 접근 가능하도록 설정, 데이터베이스는 앞에서 생성한 webdb로 설정접근 허용 권한을 데이터베이스 모두 선택
생성된 계정 확인
세션 관리자 메뉴에서 데이터베이스를 사용할 수 있는 지 점검, 암호와 데이터베이스 이름 입력최종적으로 webdb로 접속된 환경 확인
2. 프로젝트 생성과 MariaDB 준비
새로운 jdbcex 프로젝트 생성
1) 인텔리제이의 MariaDB 설정
새로 생성한 프로젝트 창에서 사이드바에 Database 버튼을 눌러 데이터베이스 설정MariaDB에서 생성한 user 정보를 입력하여 connect
데이터베이스가 연동되면 생기는 SQL console 창에 현재 시간 테스트
2) 프로젝트 내 MariaDB 설정
자바와 데이터베이스를 연동하기 위해 JDBC 드라이버라고 부르는 라이브러리 필요
build.gradle에 설정 추가
구글에 'mariadb maven'을 검색하여 MariaDB Java Client에서 Gradle 또는 Gradle(Short의 내용을 복사하여 사용
JDBC 프로그램의 구조
JDBC는 Java Database Connectivity이 약자
자바 프로그램과 데이터베이스를 네트워크 상에서 연결해 데이터를 교환하는 프로그램
관련 API로 java.sql과 javax.sql 패키지 사용
3) JDBC 프로그램 작성 순서
JDBC 프로그램은 네트워크를 통해 데이터베이스와 연결을 맺고, SQL을 전달해서 데이터베이스가 이를 실행하는 흐름
네트워크를 통해 데이터베이스와 연결을 맺는 단계
데이터베이스에서 보낼 SQL을 작성하고 전송하는 단계
필요하다면 데이터베이스가 보낸 결과를 받아서 처리하는 단계
데이터베이스와 연결을 종료하는 단계
실습_1. 테스트 프로그램 작성하기
// src > test > java > org.zerock.dao > ConnectTestspackage org.zerock.dao;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
publicclassConnectTests{
// Test를 적용하는 메서드는 반드시 public으로 선언, 파라미터나 return 없이 사용@Testpublicvoidtest1(){
int v1 = 10;
int v2 = 10;
// 인자로 받은 두 변수의 값이 동일해야 test에 성공
Assertions.assertEquals(v1, v2);
}
}
v1과 v2가 같을 때 test를 성공하여 출력된 결과v2를 20으로 바꿔 v1과 v2를 다르게 했을 때 test에 실패 후 출력되는 결과
이를 이용하여 MariaDB와의 연결을 확인하는 용도의 코드 작성
package org.zerock.dao;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.DriverManager;
publicclassConnectTests{
@TestpublicvoidtestConnection()throws Exception {
// JDBC 드라이버 클래스를 메모리상으로 로딩하는 역할// 문자열은 패키지명과 클래스명의 대소문자까지 정확히 일치
Class.forName("org.mariadb.jdbc.Driver");
// java.sql 패키지의 Connection 인터페이스 타입의 변수// 데이터베이스와의 네트워크 연결을 의미
Connection connection = DriverManager.getConnection(
// jdbc 프로토콜을 이용한다는 의미// localhost:3306은 네트워크 연결정보,// webdb는 연결하려는 데이터베이스 정보 의미"jdbc:mariadb://localhost:3306/webdb",
// 연결을 위해 필요한 사용자 계정과 패스워드"webuser",
"비밀번호");
// 데이터베이스와 정상적으로 연결이 된가면 Connection 타입의 객체는 null이 아니라는 것을 확신
Assertions.assertNotNull(connection);
// 작업이 완료되면 반드시 데이터베이스와의 연결을 종료
connection.close();
}
}
데이터베이스와 Connection에 성공하여 출력된 결과
실습_2. 데이터베이스 테이블 생성
관계형 데이터베이스에서는 데이터 저장을 위해 테이블 생성
테이블은 여러 칼럼과 로우로 구성
각 칼럼에는 이름과 타입, 제약 조건 등이 결합
MariaDB에서 사용하는 데이터 타입
타입
용도
크기
설명
숫자형 데이터 타입
TINYINT
매우 작은 정수
1 byte
-128 ~ 127 (부호 없이 0 ~ 255)
SMALLINT
작은 정수
2 byte
-32768 ~ 32767
MEDIUMINT
중간 크기의 정수
3 byte
-(-8388608) ~ -1(8388607)
INT
표준 정수
4 byte
-2147483648 ~ 2147483647 (부호 없이 0 ~ 4294967295)
BIGINT
큰 정수
8 byte
-2147483648 ~ 2147483647 (부호 없이 0 ~ 4294967295)
FLOAT
단정도 부동 소수
4 byte
-9223372036854775808 ~ 9223372036854775807 (부호 없이 0 ~ 18446744073709551615)
DOUBLE
배정도 부동 소수
8 byte
-1.7976E+320 ~ -1.7976E+320 (부호 없이 쓸 수 없음)
DECIMAL(m, n)
고정 소수
m과 n에 따라 다름
숫자 데이터이지만 내부적으로 String 형태로 저장됨, 최개 65자
BIT(n)
비트 필드
n에 따라 다름
1 ~ 64 bit 표현
날짜형 데이터 타입
DATE
(형태)YYYY-MM-DD
3 byte
1000-01-01 ~ 9999-12-31
DATETIME
(형태)YYYY-MM-DD hh:mm:ss
8 byte
1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
TIMESTAMP
(형태)YYYY-MM-DD hh:mm:ss
4 byte
1970-01-01 00:00:00 ~ 2037
TIME
(형태)hh:mm:ss
3 byte
-839:59:59 ~ 839:59:59
YEAR
(형태)YYYY 또는 YY
1 byte
1901 ~ 2155
문자형 데이터 타입
CHAR(n)
고정 길이 비이진 문자열
n byte
VARCHAR(n)
가변 길이 비이진 문자열
Length + 1 byte
BINARY(n)
고정 길이 이진 문자열
n byte
VARBINARY(n)
가변 길이 이진 문자열
Length + 1 byte or 2 byte
TINYBLOB
매우 작은 Binary Large Object
Length + 1 byte
BLOB
작은 Binary Large Object
Length + 2 byte
최대 크기 64KB
MEDIUMBLOB
중간 크기 Binary Large Object
Length + 3 byte
최대 크기 16MB
LONGBLOB
큰 Binary Large Object
Length + 4 byte
최대 크기 4GB
TINYTEXT
매우 작은 비이진 문자열
Length + 1 byte
TEXT
작은 비이진 문자열
Length + 1 byte
최대 크기 64KB
MEDIUMTEXT
중간 크기 비이진 문자열
Length + 3 byte
최대 크기 16MB
LONGTEXT
큰 비이진 문자열
Length + 4 byte
최대 크기 4GB
Todo 리스트를 저장하기 위한 테이블 생성
createtable tbl_todo (
tno int auto_increment primary key,
title varchar(100) notnull,
dueDate datenotnull,
finished tinyint default0
);
tbl_todo라는 이름으로 생성
tno는 primary key로 사용하며, auto_increment는 새로운 데이터 추가 시 자동으로 새로운 번호가 생성되도록 함
dueDate는 '년-월-일'로 기록할 수 있는 date타입 이용
MariaDB에서 boolean 값은 true / false 값 대신 0 / 1로 사용하는 경우가 많으므로 tinyint타입으로 처리