전공/객체지향프로그래밍

[객체지향프로그래밍] 자바 데이터 베이스 관리 프로그래밍 실습

Campus Coder 2023. 6. 19. 21:43
728x90
반응형

프로젝트 소개

오늘은 제가 최근에 진행한 자바 실습 프로젝트에 대해 소개하려고 합니다. 이 프로젝트는 데이터베이스의 생성, 조회, 수정, 삭제 등의 작업을 효율적으로 처리하는 시스템을 개발하는 것이 목표입니다. 프로그램의 테스트 케이스로는 도서 관리 시스템을 작동시켜 보았습니다.

 

프로젝트 구조 및 파일 설명

프로젝트는 다음과 같은 구조로 이루어져 있습니다.

 

  1. src/database 폴더: 데이터베이스 관련 파일들을 포함하는 폴더
    • TableImpl.java: 테이블 구현을 담당하는 클래스
    • Table.java: 테이블 인터페이스를 정의한 클래스
    • JoinColumn.java: 조인할 칼럼을 나타내는 클래스
    • Joinable.java: 조인 가능한 엔티티를 나타내는 인터페이스
    • Database.java: 데이터베이스를 관리하는 클래스
    • ColumnImpl.java: 칼럼 구현을 담당하는 클래스
    • Column.java: 컬럼 인터페이스를 정의한 클래스
  2. src/test 폴더: 테스트 관련 파일들을 포함하는 폴더
    • Test.java: 프로젝트의 테스트를 위한 클래스
  3. rsc 폴더: 데스트할 데이터들이 있는 폴더

 

주요 기능 및 구현 내용

데이터베이스 시스템은 다음과 같은 주요 기능을 제공합니다.

  1. 데이터베이스 테이블 생성:
    • CSV 파일을 기반으로 테이블 객체를 생성하는 기능을 구현
    • Database.createTable() 메서드를 사용하여 각 CSV 파일로부터 테이블 객체를 생성
  2. 데이터베이스 테이블 조작:
    • 생성된 테이블을 활용하여 다양한 작업을 수행
    • Database.showTables() 메서드를 사용하여 데이터베이스의 테이블 목록을 출력
  3. 데이터 조회 및 조작:
    • 테이블 객체를 얻은 후, 해당 테이블의 내용을 출력하고 요약 정보를 확인
    • Table.show() 메서드를 사용하여 테이블 내용을 출력
    • Table.describe() 메서드를 사용하여 테이블의 요약 정보를 출력
  4. 서브테이블 추출:
    • 테이블의 일부분만 추출하여 새로운 서브테이블을 생성
    • Table.head() 메서드를 사용하여 처음 n개의 행을 추출한 서브테이블을 생성
    • Table.tail() 메서드를 사용하여 마지막 n개의 행을 추출한 서브테이블을 생성
    • Table.selectRows() 메서드를 사용하여 지정한 행 인덱스 범위의 서브테이블을 생성
    • Table.selectRowsAt() 메서드를 사용하여 지정한 행 인덱스로만 구성된 서브테이블을 생성
  5. 정렬:
    • 테이블을 기준 열 인덱스로 정렬
    • Table.sort() 메서드를 사용하여 테이블을 기준 열로 정렬
    • 오름차순이나 내림차순으로 정렬할 수 있으며, null 값의 처리도 선택 가능
  6. 조인:
    • 테이블 간의 조인 작업을 수행
    • Table.crossJoin() 메서드를 사용하여 두 테이블의 cross join 결과를 생성
    • Table.innerJoin() 메서드를 사용하여 두 테이블의 inner join 결과를 생성
    • Table.outerJoin() 메서드를 사용하여 두 테이블의 outer join 결과를 생성
    • Table.fullOuterJoin() 메서드를 사용하여 두 테이블의 full outer join 결과를 생성
  7. 조건 검색:
    • 특정 조건을 만족하는 행을 추출
    • Table.selectRowsBy() 메서드를 사용하여 지정한 열과 조건 함수를 기반으로 조건 검색을 수행

 

테스트 케이스

더보기
package test;

import database.Database;
import database.JoinColumn;
import database.Table;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;

public class Test {
    public static void main(String[] args) throws FileNotFoundException {
        System.out.println("1) CSV 파일로부터 테이블 객체 생성");
        Database.createTable(new File("rsc/authors.csv"));
        Database.createTable(new File("rsc/editors.csv"));
        Database.createTable(new File("rsc/translators.csv"));
        Database.createTable(new File("rsc/books.csv"));

        System.out.println("\n2) 데이터베이스의 테이블 목록을 출력");
        Database.showTables();

        System.out.println("\n3) 데이터베이스로부터 테이블을 얻는다.");
        Table books = Database.getTable("books");
        Table authors = Database.getTable("authors");
        Table editors = Database.getTable("editors");
        Table translators = Database.getTable("translators");

        Table testTable = books; Table t1 = authors;Table t2 = editors;Table t3 = translators;

        System.out.println("\n4) 테이블 내용을 출력한다.");
        testTable.show();

        System.out.println("\n5) 테이블 요약 정보를 출력한다.");
        testTable.describe();

        Table headTable;

        System.out.println("\n6) 처음 5줄 출력 (새 테이블)");
        testTable.head().show();
        headTable = testTable.head();
        System.out.println("identity test for head(): " + (testTable.equals(headTable) ? "Fail" : "Pass"));

        System.out.println("\n7) 지정한 처음 n줄 출력 (새 테이블)");
        testTable.head(10).show();
        headTable = testTable.head(10);
        System.out.println("identity test for head(n): " + (testTable.equals(headTable) ? "Fail" : "Pass"));

        Table tailTable;

        System.out.println("\n8) 마지막 5줄 출력 (새 테이블)");
        testTable.tail().show();
        tailTable = testTable.tail();
        System.out.println("identity test for tail(): " + (testTable.equals(tailTable) ? "Fail" : "Pass"));

        System.out.println("\n9) 지정한 마지막 n줄 출력 (새 테이블)");
        testTable.tail(10).show();
        tailTable = testTable.tail(10);
        System.out.println("identity test for tail(n): " + (testTable.equals(tailTable) ? "Fail" : "Pass"));

        Table selectedRowsTable;

        System.out.println("\n10) 지정한 행 인덱스 범위(begin<=, <end)의 서브테이블을 얻는다. (새 테이블), 존재하지 않는 행 인덱시 전달시 예외발생.");
        testTable.selectRows(0, 5).show();
        selectedRowsTable = testTable.selectRows(0, 5);
        System.out.println("identity test for selectRows(range): " + (testTable.equals(selectedRowsTable) ? "Fail" : "Pass"));

        System.out.println("\n11) 지정한 행 인덱스로만 구성된 서브테이블을 얻는다. (새 테이블), 존재하지 않는 행 인덱시 전달시 예외발생.");
        testTable.selectRowsAt(7, 0, 4).show();
        selectedRowsTable = testTable.selectRowsAt(7, 0, 4);
        System.out.println("identity test for selectRowsAt(indices): " + (testTable.equals(selectedRowsTable) ? "Fail" : "Pass"));

        Table selectedColumnsTable;

        System.out.println("\n12) 지정한 열 인덱스 범위(begin<=, <end)의 서브테이블을 얻는다. (새 테이블), 존재하지 않는 열 인덱시 전달시 예외발생.");
        testTable.selectColumns(0, 4).show();
        selectedColumnsTable = testTable.selectColumns(0, 4);
        System.out.println("identity test for selectColumns(range): " + (testTable.equals(selectedColumnsTable) ? "Fail" : "Pass"));

        System.out.println("\n13) 지정한 열 인덱스로만 구성된 서브테이블을 얻는다. (새 테이블), 존재하지 않는 열 인덱시 전달시 예외발생.");
        testTable.selectColumnsAt(4, 5, 3).show();
        selectedColumnsTable = testTable.selectColumnsAt(4, 5, 3);
        System.out.println("identity test for selectColumnsAt(indices): " + (testTable.equals(selectedColumnsTable) ? "Fail" : "Pass"));

        Table sortedTable;

        System.out.println("\n14) 테이블을 기준 열인덱스(5)로 정렬한다. 이 때, 오름차순(true), null값은 나중에(false)(원본 테이블 정렬), 존재하지 않는 열 인덱시 전달시 예외발생.");
        testTable.sort(5, true, false).show();
        sortedTable = testTable.sort(5, true, false);
        System.out.println("identity test for sort(index, asc, nullOrder): " + (!testTable.equals(sortedTable) ? "Fail" : "Pass"));

        System.out.println("\n15) 테이블을 기준 열인덱스(5)로 정렬한다. 이 때, 내림차순(false), null값은 앞에(true)(새 테이블), 존재하지 않는 열 인덱시 전달시 예외발생.");
        Database.sort(testTable, 5, false, true).show();
        sortedTable = Database.sort(testTable, 5, false, true);
        System.out.println("identity test for Database.sort(index, asc, nullOrder): " + (testTable.equals(sortedTable) ? "Fail" : "Pass"));

        Table rightTable = authors;

        System.out.println("\n16) cross join");
        Table crossJoined = testTable.crossJoin(rightTable);
        crossJoined.show();

        System.out.println("\n17) inner join");
        Table innerJoined = testTable.innerJoin(rightTable, List.of(new JoinColumn("author_id", "id")));
        innerJoined.show();

        rightTable = translators;

        System.out.println("\n18) outer join");
        Table outerJoined = testTable.outerJoin(rightTable, List.of(new JoinColumn("translator_id", "id")));
        outerJoined.show();

        System.out.println("\n19) full outer join");
        Table fullOuterJoined = testTable.fullOuterJoin(rightTable, List.of(new JoinColumn("translator_id", "id")));
        fullOuterJoined.show();

        System.out.println("\n20) 조건식을 만족하는 행을 얻는다.");
        testTable.selectRowsBy("title", (String x) -> x.contains("Your")).show();
        testTable.selectRowsBy("author_id", (Integer x) -> x < 15).show();
        testTable.selectRowsBy("title", (String x) -> x.length() < 8).show();
        testTable.selectRowsBy("translator_id", (Object x) -> x == null).show();
//
//        ****************************** test for Column ******************************
        int selectedColumnIndex;
        int selectedRowIndex;
        String selectedColumnName;

        System.out.println("\n21) setValue(int index, int value) or setValue(int index, String value)호출 전후 비교");
        System.out.println("*** before setValue ***");
        selectedColumnIndex = (int) (Math.random() * testTable.getColumnCount());
        selectedRowIndex = (int) (Math.random() * testTable.getColumn(selectedColumnIndex).count());
        selectedColumnName = testTable.getColumn(selectedColumnIndex).getHeader();
        System.out.println("Selected Column: " + selectedColumnName);
        testTable.selectRowsAt(selectedRowIndex).show();
        testTable.describe();
        if (testTable.getColumn(selectedColumnIndex).isNumericColumn())
            testTable.getColumn(selectedColumnName).setValue(selectedRowIndex, "Sample");
        else
            testTable.getColumn(selectedColumnName).setValue(selectedRowIndex, "2023");
        System.out.println("Column " + selectedColumnName + " has been changed");
        System.out.println("*** after setValue ***");
        testTable.selectRowsAt(selectedRowIndex).show();
        testTable.describe();

        System.out.println("\n22) T getValue(int index, Class<T> t) or String getValue(int index) 호출 전후 비교");
        System.out.println("*** before getValue ***");
        selectedColumnIndex = (int) (Math.random() * testTable.getColumnCount());
        selectedRowIndex = (int) (Math.random() * testTable.getColumn(selectedColumnIndex).count());
        selectedColumnName = testTable.getColumn(selectedColumnIndex).getHeader();
        System.out.println("Selected Column: " + selectedColumnName);
        testTable.selectRowsAt(selectedRowIndex).show();
        if (testTable.getColumn(selectedColumnIndex).isNumericColumn()) {
            // cell 값이 null이면, 예외 발생할 수 있음.
            double value = testTable.getColumn(selectedColumnName).getValue(selectedRowIndex, Double.class);
            System.out.println("The numeric value in (" + selectedRowIndex + ", " + selectedColumnIndex + ") is " + value);
        } else {
            String value = testTable.getColumn(selectedColumnName).getValue(selectedRowIndex);
            System.out.println("The string value in (" + selectedRowIndex + ", " + selectedColumnIndex + ") is " + value);
        }
    }
}

 

문제 해결 과정

프로젝트를 진행하면서 다양한 문제를 해결해야 했습니다. 가장 큰 어려움은 프로젝트 초기에 인터페이스와 클래스의 상속 관계에 따라 어떤 메소드를 어디에 정의할지, 데이터를 어떤 형태로 처리할지에 대한 부분이었습니다. 대학 수업에서 다뤄진 내용을 정리하여 활용해 보려 노력하고 각종 레퍼런스들을 적절히 참고한 덕분에 이런 문제를 헤쳐나갈 수 있었습니다.

 

 

결과 및 배운 점

데스트 케이스 실행 결과 중 일부분

이 프로젝트를 통해 2-1 학기에 배운 자바 언어와 객체 지향 프로그래밍에 대한 이해를 크게 향상되는데 도움이 되었다고 생각합니다. 이 프로젝트를 통해 자바데이터베이스 관리에 대한 실력을 향상하고, 효율적인 데이터 조작 분석에 대한 경험을 쌓을 수 있었다. 또한, 코드의 재사용성과 확장성을 고려하여 유지보수에 용이한 구조를 구현하는 법을 배울 수 있었습니다.

 

아쉬웠던 점은 첫 프로젝트였다보니 프로젝트 테스트 케이스의 출력 결과에 몰두해 효율적으로 코드를 짜지 못한 부분이 있다는 점과 메소드 구현을 작성할 때 주석을 적절히 활용하지 못했다는 점이 있었습니다. 다름 프로젝트 때에는 이런 문제점을 해결해 더 좋을 프로그램을 작성할 수 있도록 노력해야겠다고 다짐했습니다.

 

 

자세한 내용과 코드

https://github.com/Ares-10/DB_Management

 

GitHub - Ares-10/DB_Management

Contribute to Ares-10/DB_Management development by creating an account on GitHub.

github.com

 

728x90
반응형