1. MariaDB 설치·생성

 1) MariaDB 설치

 

 2) 데이터베이스 생성과 사용자 계정 추가

  • 데이터베이스에서 필요한 작업을 명령하는 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을 전달해서 데이터베이스가 이를 실행하는 흐름
    1. 네트워크를 통해 데이터베이스와 연결을 맺는 단계
    2. 데이터베이스에서 보낼 SQL을 작성하고 전송하는 단계
    3. 필요하다면 데이터베이스가 보낸 결과를 받아서 처리하는 단계
    4. 데이터베이스와 연결을 종료하는 단계
  • 실습_1. 테스트 프로그램 작성하기
// src > test > java > org.zerock.dao > ConnectTests
package org.zerock.dao;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class ConnectTests {

  // Test를 적용하는 메서드는 반드시 public으로 선언, 파라미터나 return 없이 사용
  @Test
  public void test1() {
    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;

public class ConnectTests {

  @Test
  public void testConnection() 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 리스트를 저장하기 위한 테이블 생성
create table tbl_todo (
    tno int auto_increment primary key,
    title varchar(100) not null,
    dueDate date not null,
    finished tinyint default 0
);
    • tbl_todo라는 이름으로 생성
    • tno는 primary key로 사용하며, auto_increment는 새로운 데이터 추가 시 자동으로 새로운 번호가 생성되도록 함
    • dueDate는 '년-월-일'로 기록할 수 있는 date타입 이용
    • MariaDB에서 boolean 값은 true / false 값 대신 0 / 1로 사용하는 경우가 많으므로 tinyint타입으로 처리

정상적으로 생성된 tbl_todo

 

  • 실습_3. 데이터 insert
    • 데이터 추가
insert into tbl_todo (title, dueDate, finished)
values  ('Test...', '2022-12-31', 1);

위의 코드 여러 번 실행
실행 결과 tbl_todo에 데이터 여러 개가 추가 된 모습, tno는 자동으로 1부터 5까지 추가되어 있음

 

  • 실습_4. 데이터 select
    • 데이터 조회
    • 'from'으로 데이터를 가져올 테이블 지정
    • 'where로 조회할 데이터의 조건 지정
select * from tbl_todo where tno=1;

 

  • 실습_5. 데이터 update
    • 기존 데이터 수정
    • 'set'으로 특정 칼럼 내용 수정
    • 'where'로 수정할 데이터의 조건 지정
    • 3번 데이터의 finished와 title 값을 변경하고 싶다면 아래의 코드 작성
update tbl_todo set finished = 0, title = 'Not Yet...' where tno = 3;

 

  • 실습_6. 데이터 delete
    • 데이터 삭제
    • 'where ' 조건에 해당하는 데이터 삭제
    • 'where' 조건이 없다면 모든 데이터 삭제할 수 있으므로 경고 메세지와 함께 실행되지 않음
    • tno가 5보다 큰 데이터를 삭제하고 싶다면 아래의 코드 작성
delete from tbl_todo where tno > 5;

 

 4) DML과 쿼리(select)의 차이

  • DML(insert, update, delete)와 select의 차이
    • DML은 몇 개의 데이터가 처리되었는지 숫자로 결과 반환
    • select문은 데이터를 반환
  • update문 실행 예시

한 개의 row가 영향을 받았다고 숫자로 결과가 출력됨

  • select문 실행 예시
select * from tbl_todo;

실제 데이터인 tbl_todo 표 자체가 출력됨

 

 5) JDBC 프로그래밍을 위한 API와 용어들

  • java.sql.Connection
    • Connection 인터페이스는 데이터베이스와 네트워크 상의 연결을 의미
    • 데이터베이스에 SQL을 실행하기 위해 반드시 정상적인 Connection 타입의 객체 생성해야 함
    • 가장 중요한 사실은 "Connection은 반드시 close()해야 한다", 연결이 종료되지 않으면 새로운 연결을 받을 수 없는 상황이 발생함
    • Connection 종료를 위해 try ~ catch ~ finally 또는 try-with-resource를 사용(후자 사용 시 자동으로 close()가 호출됨)
    • 가장 중요한 기능은 Statement 혹은 Prepared-Statement 등 SQL을 실행할 수 있는 객체를 생성하는 기능
// Prepared-Statement 객체 생성 코드
Connection connection = ...
PreparedStatement preparedStatement = connection.preparedStatement("select * from tbl_todo");

 

  • java.sql.Statement / PreparedStatement
    • JDBC에서 SQL을 데이터베이스로 보내기 위해 Statement / PreparedStatement 타입 이용
    • PreparedStatemetn는 SQL문을 미리 전달하고 나중에 데이터를 보내는 방식
    • Statement는 SQL문 내부에서 모든 데이터를 같이 전송하는 방식
    • 실제 개발에서는 SQL 내부에 고의적으로 다른 SQL 문을 심는 SQL injection을 막기 위해 PreparedStatement만 사용
    • Statement / PreparedStatement의 주요 기능
      • setXXX(): setInt(), setString(), setDate()와 같이 다양한 타입에 맞게 데이터 세팅
      • executeUpdate(): DML을 실행하고 결과를 int 타입으로 반환(몇 행이 영향을 받았는지)
      • executeQuery(): 쿼리(select)를 실행할 때 사용, ResultSet이라는 return 타입 이용
    • Statement도 Connection처럼 마지막에 close() 해주어야, 데이터베이스 내부에서도 메모리와 같이 사용했던 자원들이 즉각 정리됨

 

  • java.sql.ResultSet
    • 쿼리(select)를 실행했을 때 반환하는 데이터를 읽어들이기 위한 인터페이스
    • 자바 코드에서 데이터를 읽어 들이기 때문에 getInt(), getString() 등의 메서드를 이용해서 필요한 타입으로 데이터를 읽어 들임
    • ResultSet의 메서드 next(): ResultSet은 데이터를 순차적으로 읽는 방식으로 구성되기 때문에 next()를 이용해 다음 행의 데이터를 읽을 수 있도록 이동하는 작업이 필요
    • ResultSet 역시 마지막에 close() 해주어야 데이터베이스에서 자원을 즉각 회수

 

  • Connection Pool과 DataSource
    • JDBC 프로그램은 기본적으로 필요한 순간 잠깐 데이터베이스과 네트워크로 연결하고 데이터를 주고 받는 방식
    • 이 과정에서 데이터베이스와 연결을 맺는 작업은 많은 시간과 자원을 쓰므로 SQL을 여러 번 실행하면 성능 저하
    • 이 때, Connection Pool을 이용하여 문제 해결
    • Connection Pool: 미리 Connection들을 생성해 보관, 필요할 때 꺼내 쓰는 방식
    • javax.sql.DataSource 인터페이스는 Connection Pool을 자바에서 API 형태로 지원
    • Connection Pool은 이미 작성된 라이브러리 이용(DBCP, C3PO, HikariCP 등)

 

  • DAO(Data Access Object)
    • 데이터를 전문적으로 처리하는 객체
    • 데이터베이스의 접근과 처리를 전담하는 객체이고, 주로 VO(Value Object, 읽을 수 있는 값) 단위로 처리
    • DAO를 호출하는 객체는 DAO 내부에서 어떤 식으로 데이터를 처리하는지 알 수 없도록 구성

 

  • VO(Value Object) 혹은 엔티티(Entity)
    • 객체지향 프로그램은 데이터를 객체 단위로 처리(ex)테이블 한 행이 자바 프로그램에서 하나의 객체)
    • 데이터베이스에서는 하나의 데이터를 하나의 엔티티라고 하며 자바 프로그램은 이를 처리하기 위해 테이블과 유사한 구조의 클래스를 만들어 객체로 처리
    • 이때 만든 객체는 값을 보관하는 용도라는 의미에서 VO라고 함
    • DTO는 각 계층을 오고 가는데 사용되는 택배 상자와 비슷 / VO는 데이터베이스의 엔티티를 자바 객체로 표현
    • DTO는 getter / setter를 이용해 자유롭게 데이터 가공 / VO는 주로 데이터 자체를 의미하므로 getter만 사용

+ Recent posts