[ 최종 수정일 : 2023년 09월 20일 ]

 

 

 

SqlSessionFactory는 사용자가 정의한 설정파일(mybatis-config.xml)을 바탕으로 SqlSession 객체를 생성합니다.

 

 

MyBatis Official Document


 

 

먼저 SqlSessionFactory 객체를 생성하고, 해당 객체를 활용하여 실제 OCI(DB)와의 연결(Session)을 획득합니다.

 

 

1. SsqlSessionFactory 객체 생성

SqlSessionFactory 필드를 선언하고 전처리 메서드에서 객체를 생성 후 저장합니다.

@Log4j2
@NoArgsConstructor

@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SqlSessionFactoryBuilderTests {
    private SqlSessionFactory sqlSessionFactory;


    @BeforeEach
    void testCreateSession() throws IOException {
        log.trace("testCreateSession() invoked.");

        // 1. SqlSessionFactoryBuilder 객체 생성		
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        log.info("\t session: {}", builder);
		
        // 2. MyBatis의 설정파일의 레퍼런스를 획득 후, 입력 스트림 객체에 할당
        String config = "mybatis-config.xml";	// 설정파일        
        @Cleanup InputStream is = Resources.getResourceAsStream(config);
		
        
        // builder 객체에게 입력 스트림 객체를 전달해서 SqlSessionFactory 필드에 저장
        this.sqlSessionFactory = builder.build(is);
        log.info("\t sqlSessionFactory: {}", sqlSessionFactory);
		
	} // beforeEach

 

 

2. OCI(DB) 연결

SqlSessionFactory를 활용하여 OCI와의 연결(Session)을 획득합니다.

    @Test
    @Tag("fast")
    @Order(1)
    @DisplayName("testSqlSessionFactory")
    @Timeout(3L)
    void testSqlSessionFactory() throws IOException {
        log.trace("testSqlSessionFactory() invoked.");
    
        // 1. 필드에 저장된 SqlSessionFatory에서 하나의 SqlSession 객체 획득
        @Cleanup SqlSession sqlSession = this.sqlSessionFactory.openSession();
    
        Assertions.assertThat(sqlSession).isNotNull(sqlSession);
        log.info("\t SqlSession: {}", SqlSession);
    
    } // testSqlSessionFactory
    
} // end class

검증 라이브러리는 assertj-core를 사용하였습니다.

 

SqlSession은 자원객체이므로 @Cleanup 어노테이션으로 누수를 방지합니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'Database > MyBatis' 카테고리의 다른 글

MyBatis 시작하기  (0) 2023.09.20

[ 최종 수정일 : 2023년 09월 20일 ]

 

 

 

MyBatis(SQL Mapper Framework)는 자바 객체를 SQL 문장으로 자동 매핑(사상)해주는 프레임워크입니다.

Apache MyBatis의 Document는 한국어를 지원하므로 참조하시면 좋을 것 같습니다.

https://mybatis.org/mybatis-3/ko/index.html

 

 

 


 

 

 

pom.xml 설정하기

[아파치 메이븐/의존성] - 라이브러리

[아파치 메이븐] - 메이븐 설정 파일

위 글을 참조합니다.

 

 

 

 

mybatis-config.xml 설정하기

기본적인 Syntax를 참조하여 자신의 개발 환경에 맞게 작성합니다.
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
  
<configuration>

  <environments default="development">
  
	<!-- 개발환경은 Driver SPY 적용 -->  
    <environment id="development">
      <transactionManager type="JDBC"/>
      
      <dataSource type="UNPOOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
    
    <!-- 실제 서비스 환경은 Driver SPY 해제 -->
    <environment id="production">
      <transactionManager type="JDBC"/>
      
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
    
  </environments>
  
</configuration>

 

개발 환경에 따라 dataSource의 타입을 설정합니다.

활성화 : POOLED

비활성화 : UNPOOLED

 

 

'Database > MyBatis' 카테고리의 다른 글

MyBatis  (0) 2023.09.21

 

 

 

정규화(Normalization)은 다양한 정보를 포함하고 있는 하나의 테이블을 각 정보에 맞게 쪼개는 작업을 의미합니다.

따라서, 정규화는 '무손실 분해'라고 합니다.

 

 


 

 

정규화는 각각의 정보를 별도의 릴레이션으로 무손실 분해해서 이상현상을 제거하는 것에 목적을 두고 있습니다.

 

이러한 정규화는 6가지로 나눌 수 있지만 일반적으로 세 종류의 정규화를 주로 사용합니다.

정규화 단계를 거쳐야 다음 정규화 과정을 수행할 수 있습니다.

 

 

# 정규화

 

  1.  1NF 릴레이션
  2.  2NF 릴레이션
  3.  3NF 릴레이션
  4.  BCNF 릴레이션
  5.  4NF 릴레이션
  6.  5NF 릴레이션

 

 

 

1. 제 1정규형(1NF)

 

1NF는 다중값 속성을 제거하는 단계입니다.

즉, 정규화를 수행하는 릴레이션의 모든 속성값이 원자(단일)값을 가지면 1NF라고 합니다.

 

 

2. 제 2정규형(2NF)

 

2NF는 하나의 릴레이션에 두 개의 릴레이션이 종속되어 있다면 분해하는 단계입니다.

즉, 기본키가 아닌 속성이 기본키에 완전 함수 종속일 때 2NF라고 합니다.

 

 

3. 제 3정규형(3NF)

 

비이행적(non-transitive)으로 종속할 때 3NF라고 합니다.

이행적 종속이란 A = B, B = C일때, A = C가 성립되는 함수 종속성입니다.

 

 

 

 

 

'Database > SQL' 카테고리의 다른 글

외부 조인  (0) 2023.08.21
그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16

 

 

 

OUTER JOIN은 한 쪽 테이블의 모든 행을 기준으로 다른 테이블을 JOIN합니다.

예를 들어, LEFT OUTER JOIN이라면 왼쪽 테이블의 모든 행을 기준으로 오른쪽 테이블을 JOIN합니다.

 

 


 

 

다음은 OUTER JOIN에 대한 쿼리입니다.

 

-- Oracle LEFT OUTER JOIN --

SELECT
  e.last_name AS 사원명,
  e.employee_id AS 사원번호,
  m.last_name AS 관리자명,
  m.employee_id AS 관리자사번
FROM
  employees e,
  employees m
WHERE
  e.manager_id = m.employee_id (+);
  
 
 
 -- Ansi LEFT OUTER JOIN --
 
SELECT
  e.last_name AS 사원명,
  e.employee_id AS 사원번호,
  m.last_name AS 관리자명,
  m.employee_id AS 관리자사번
FROM
  employees e LEFT OUTER JOIN employees m -- OUTER 키워드 생략 가능 --
  ON e.manager_id = m.employee_id;

 

RIGHT OUTER JOIN도 동일한 개념으로 동작합니다.

 

 

그런데 Ansi JOIN에서만 있는 FULL OUTER JOIN이 있습니다.FULL OUTER JOIN은 두 테이블의 모든 행을 결합하되, NULL값을 모두 포함하여 결합합니다.

 

-- Ansi FULL OUTER JOIN --

SELECT
  e.last_name AS 사원명,
  e.employee_id AS 사원번호,
  m.last_name AS 관리자명,
  m.employee_id AS 관리자사번
FROM
  employees e FULL OUTER JOIN employees m -- OUTER 키워드 생략 가능 --
  ON e.manager_id = m.employee_id;

 

 

 

 

'Database > SQL' 카테고리의 다른 글

정규화  (0) 2023.09.06
그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16

 

 

 

GROUP BY(그룹화)는 SELECT 절에서 집계함수와 단순칼럼이 복합적으로 선택될 때 사용됩니다.

 

 


 

 

1. GROUP BY

 

GROUP BY절은 NULL을 제외하지 않고 그룹화하여 로우의 가장 아래에 생성합니다.

 

먼저 SELECT 절에 스칼라를 선택하는 쿼리를 작성하였습니다.

스칼라는 쿼리의 결과가 하나인 것을 의미합니다.

 

SELECT
    MAX(salary)
FROM
    employees;

 

스칼라

 

결과에서도 알 수 있듯이,

집계함수가 단독적으로 사용된다면 그룹화는 필요 없습니다.

 

 

하지만 집계함수와 단순칼럼이나 표현식이 함께 사용된다면 GROUP BY 절이 사용되야 합니다.

고용된 날짜 별 총 급여를 쿼리로 작성하였습니다.

 

SELECT
    TO_CHAR(hire_date, 'YYYY/MM') AS 고용연월,
    SUM(salary)   AS "총 급여"
FROM
    employees
GROUP BY
    TO_CHAR(hire_date, 'YYYY/MM')
ORDER BY
    1 ASC;

 

위 쿼리는 TO_CHAR를 그룹화하여 해당 고용날짜에 해당하는 사원의 총 급여에 대한 쿼리입니다.

만약 SELECT절에 추가적인 칼럼이나 표현식이 선택되면 GROUP BY절에서 추가적인 그룹화가 필요합니다.

 

 

 

2. HAVING

 

HAVING절은 그룹화와 함께 사용됩니다.

HAVING절은 GROUP BY를 통해 그룹화하고 로우(row, 행)가 아닌 그룹을 제외시킬 수 있습니다.

또한 WHERE절에서는 사용이 불가능한 집계함수를 HAVING절에서는 사용할 수 있습니다.

 

SELECT
    TO_CHAR(hire_date, 'YYYY/MM') AS 고용연월,
    SUM(salary)   AS "총 급여"
FROM
    employees
GROUP BY
    TO_CHAR(hire_date, 'YYYY/MM')
HAVING
    SUM(salary) >= 10000
ORDER BY
    1 ASC;

 

위 쿼리처럼 HAVING절은 집계함수 사용이 가능하며, WHERE절과 같은 그룹에 대한 필터링을 수행합니다.

 

 

 

 

 

 

 

 

'Database > SQL' 카테고리의 다른 글

정규화  (0) 2023.09.06
외부 조인  (0) 2023.08.21
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16

 

 

 

인라인 뷰는 기존 테이블에서 필요한 칼럼만 추출 후 일종의 임시 테이블로 사용하는 방식입니다.

 

 


 

 

인라인 뷰를 사용하면 쿼리가 더 간결해지고 중복 코드를 제거할 수 있습니다.

다만, 과도하게 중첩된 인라인 뷰는 쿼리의 복잡도를 높일 수 있기 때문에 주의해야 합니다.

 

 

간단한 예시 코드입니다.

 

SELECT
    부서번호,
    평균월급
FROM
    ( SELECT
          department_id AS 부서번호,
          AVG(salary)   AS 평균월급
      FROM
          employees
      WHERE
          department_id IS NOT NULL
      GROUP BY
          department_id
      ORDER BY
          department_id ASC;
     );

 

위 쿼리에서 FROM 절에 해당하는 부분이 ' 인라인 뷰 ' 입니다.

메인 쿼리인 SELECT 절에서는 인라인 뷰의 쿼리 결과를 별칭을 선택해서 받아왔습니다.

 

 

 

 

'Database > SQL' 카테고리의 다른 글

외부 조인  (0) 2023.08.21
그룹화  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16
크로스 조인  (0) 2023.08.10

 

 

 

FORGEIGN KEY(외래 키 또는 참조 키)는 자식 테이블에서 부모 테이블을 참조할 때,

올바른 데이터만 참조하도록(참조 무결성) 제약합니다.

 

 


 

 

외래 키는 부모 테이블과 자식 테이블 간 참조 무결성을 위한 제약 조건이므로, 

자식 테이블에서 참조하는 칼럼을 부모 테이블에서 PRIMARY KEY 또는 UNIQUE로 설정해야 합니다.

 

 

부모 테이블을 만들고 자식 테이블에서 참조할 칼럼에 제약 조건을 설정하고, 로우를 입력합니다.

 

START

    CREATE TABLE dept (
        deptno  NUMBER(2)     CONSTRAINT dept_deptno_pk PRIMARY KEY,
        dname   VARCHAR2(15),
        loc     VARCHAR2(15)
    );

    INSERT INTO dept02 (deptno, dname, loc)
    VALUES (10, '인사', '서울');


    INSERT INTO dept02 (deptno, dname, loc)
    VALUES (20, '개발', '광주');


    INSERT INTO dept02 (deptno, dname, loc)
    VALUES (30, '관리', '부산');


    INSERT INTO dept02 (deptno, dname, loc)
    VALUES (40, '영업', '경기');

    COMMIT

END;

 

 

이제 자식 테이블을 만들고, 로우를 입력합니다.

 

START
    
    CREATE TABLE emp02 (
        empno   NUMBER(4)       CONSTRAINT emp02_empno_pk PRIMARY KEY,
        ename   VARCHAR2(15),
        deptno  NUMBER(2)       CONSTRAINT emp02_deptno_fk REFERENCES dept02(deptno)
    );


    INSERT INTO emp02 (empno, ename, deptno)
    VALUES (1000, 'John', 10);


    INSERT INTO emp02 (empno, ename, deptno)
    VALUES (2000, 'Smith', 20);


    INSERT INTO emp02 (empno, ename, deptno)
    VALUES (3000, 'Sam', NULL);


    -- ORA-02291: integrity constraint (SCOTT.EMP02_DEPTNO_FK) violated - parent key not found
    -- INSERT INTO emp02 (empno, ename, deptno)
    -- VALUES (4000, 'Mike', 50);

    COMMIT

END;

 

 

이제 각 테이블의 제약 조건을 데이터 사전을 통해 조회합니다.

 

SELECT
    table_name,
    constraint_type,
    constraint_name,
    r_constraint_name
FROM
    user_constraints
WHERE
    table_name IN ('DEPT02', 'EMP02')
ORDER BY
    table_name ASC;

 

FORGEIGN KEY

 

위의 결과에서, emp02 테이블의 참조키는 dept02 테이블의 기본키를 참조하는 것을 알 수 있습니다.

 

 


 

 

특정 칼럼을 참조하고 있는 자식이 있으면 해당 칼럼을 삭제할 수 없습니다.

만약 부모 테이블의 칼럼을 삭제하고 싶다면,

테이블 작성 시, FK에 ON DELETE CASCADE 키워드나 ON DELETE SET NULL 키워드를 사용하면 됩니다.

 

CREATE TABLE emp02 (
    empno NUMBER(4)     CONSTRAINT emp02_empno_pk PRIMARY KEY,
    ename VARCHAR(15),
    deptno NUMBER(2)
        CONSTRAINT emp02_deptno_fk REFERENCES dept02(deptno) ON DELETE CASCADE
);

-- ON DELETE CASCADE --
-- 참조하는 부모 테이블의 로우가 삭제되면, 해당 로우를 참조하는 자식 테이블의 로우도 연쇄 삭제됨 --



CREATE TABLE emp03 (
    empno NUMBER(4)     CONSTRAINT emp02_empno_pk PRIMARY KEY,
    ename VARCHAR(15),
    deptno NUMBER(2)
        CONSTRAINT emp03_deptno_fk REFERENCES dept02(deptno) ON DELETE SET NULL
);

-- ON DELETE SET NULL --
-- 참조하는 부모 테이블의 로우가 삭제되면, 해당 로우를 참조하는 자식 테이블의 필드값은 NULL로 바뀜--

 

 

 

 

'Database > SQL' 카테고리의 다른 글

그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
데이터 사전  (0) 2023.08.16
크로스 조인  (0) 2023.08.10
동등 조인  (0) 2023.07.26

 

 

 

SQL은 데이터 사전을 통해 제약 조건을 확인할 수 있습니다.

 

 


 

CREATE TABLE

 

데이터 사전을 조회하기 전, 실습용 테이블을 생성하였습니다.

 

CREATE TABLE department (
    deptno NUMBER(2)    CONSTRAINT department_deptno_pk PRIMARY KEY,
    dname  VARCHAR2(15),
    loc    VARCHAR2(15)
);

-- 테이블 명만 다른 동일한 쿼리입니다. --

CREATE TABLE department2 (
    deptno NUMBER(2),
    dname  VARCHAR2(15),
    loc    VARCHAR2(15),
    
    CONSTRAINT department2_deptno_pk PRIMARY KEY (deptno)
);

 

칼럼에 제약 조건을 걸 때, 해당 로우에 제약 조건 쿼리를 작성할 수 있지만,

department2처럼 칼럼을 먼저 작성하고, 아래에 제약 조건 쿼리를 작성하여 지정할 수 있습니다.

 

 


 

 

1. USER_CONSTRAINTS

USER_CONSTRAINTS 데이터 사전은 특정 테이블의 제약 조건을 확인할 수 있지만,

어떤 칼럼에 제약 조건이 설정되어 있는지는 확인 불가합니다.

 

다음은 제약 조건의 타입입니다.

 

  • P : PRIMARY KEY (기본키)
  • R : FOREIGN KEY (외래키)
  • U : UNIQUE (고유키)
  • C : NOT NULL, CHECK ( 필드의 NULL값 제한, 칼럼에 특정 제약 조건 설정 )

 

 

다음은 department, department2 테이블의 USER_CONSTRAINTS 데이터 사전 쿼리입니다.

 

SELECT
    *
FROM
    USER_CONSTRAINTS
WHERE
    table_name IN ('DEPARTMENT', 'DEPARTMENT2');

 

USER_CONSTRAINTS

 

앞서 두 테이블의 deptno 칼럼을 PRIMARY KEY(기본키)로 제약 조건을 설정했기 때문에, 

CONSTRAINT TYPE이 P로 나왔습니다.

 

 

 

2. USER_CONS_COLUMNS

USER_CONSTRAINTS 데이터 사전은 특정 테이블의 제약 조건을 확인했다면,

USER_CONS_COLUMNS는 어떤 칼럼에 제약 조건이 설정되어 있는지 확인할 수 있습니다.

SELECT
    *
FROM
    USER_CONS_COLUMNS
WHERE
    table_name IN ('DEPARTMENT', 'DEPARTMENT2');

 

USER_CONS_COLUMNS

 

쿼리 결과처럼 deptno 칼럼이 PRIMARY KEY(기본키)로 설정되어 있음을 볼 수 있습니다.

 

 

데이터 사전을 통해 조회를 할 때, 분별력을 부여하기 위해

CREATE TABLE시, CONSTRAINT NAME을 잘 작성해야 합니다.

일반적으로 " 테이블 명_칼럼 명_키 타입" 으로 작명합니다.

 

 

 

 

 

 

 

 

'Database > SQL' 카테고리의 다른 글

그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
크로스 조인  (0) 2023.08.10
동등 조인  (0) 2023.07.26

+ Recent posts