altair의 프로젝트 일기
MySQL을 사용한 중복 파일 관리 프로그램 본문
개요
방학 동안 SQL에 대해 공부했다. 그동안 데이터 관리에 많은 관심이 있었지만 데이터베이스에 관해서는 깊이있게 공부하지 못했다. 그래서 일단 데이터베이스를 사용하는 방법인 SQL을 배우고 익히기 위해 프로젝트에 이를 적용해보기로 했다.
처음으로 K-MOOC에서 SQL 강의를 들었다.
SQL의 대략적인 사용법은 강의에서 배웠지만 코드에서 데이터베이스를 사용하지 못하면 의미 없는 것이라 생각했다. 처음에는 JPA나 Hibernate 같은 추상화된 레이어를 써볼까 했지만, 데이터베이스와 SQL을 처음으로 쓰는 프로젝트이므로 일단 SQL을 내 손으로 직접 추상화하고 그 과정에서 느끼는 불편함을 나중에 다른 프레임워크들로 개선하려 했다.
요구사항 분석
만들고자하는 프로그램은 다음과 같은 일을 해야한다.
- 주어진 폴더 내 중복된 파일들을 검출한다.
- 새 파일이 추가될 때마다 똑같은 폴더를 매번 검사하는 것은 낭비다.
- 수정하지 않은 파일들을 중복해 검사하게 된다.
- 새 파일을 검사할 때마다 해당 파일의 정보를 데이터베이스에 저장한다.
- 프로그램이 끝나면 시간을 기록한다.
- 다음 프로그램 시작 시 기록된 시간보다 이후에 생성, 수정된 파일들만 검사한다.
- 중복되지 않은 파일들의 정보는 데이터베이스에 저장한다.
- 중복된 파일은 유저에게 처리를 물어본 후 처리한다.
시퀀스 다이어그램 작성
저번 학기에 여러 다이어그램을 그리는 법을 배웠다. 먼저 가장 처음 그린 시퀀스 다이어그램을 여기에 보인다.
Crawler는 폴더를 긁어와 File manager에게 전달한다. File manager는 DB에 저장한 정보와 대조해 수정된 파일이 있는지 확인한다. 수정된 파일은 Hasher를 사용해 해시값을 갱신한다. 이후 DB에 같은 해시값을 가진 파일의 정보가 있는지 확인한다. 만약 있다면 유저에게 처리를 물어본 후 처리한다. 이후 변경된 파일들의 해시값을 갱신한다.
물론 아무 코드도 나오기 전에 만든 다이어그램이라 이름이 바뀌거나 동작이 바뀐 부분이 있다.
플로우차트 작성
시퀀스 다이어그램만으로는 동작을 모두 표현하기 어려워서 플로우차트도 그려보았다.
JDBC
Java는 java.sql 패키지를 통해 JDBC를 제공하고 있다. 원하는 데이터베이스에 드라이버로 연결하고 그 Connection을 사용해 쿼리를 보내도록 했다.
public class DBSetup {
private final String DB_URL;
private final String DB_USER;
private final String DB_PASSWORD;
public DBSetup(String DB_URL, String DB_USER, String DB_PASSWORD) {
this.DB_URL = DB_URL;
this.DB_USER = DB_USER;
this.DB_PASSWORD = DB_PASSWORD;
}
public DBSetup(DatabaseConfig databaseConfig) {
this.DB_URL = databaseConfig.getDatabaseUrl();
this.DB_USER = databaseConfig.getDatabaseUser();
this.DB_PASSWORD = databaseConfig.getDatabasePassword();
}
public Connection getConnection() throws SQLException {
return java.sql.DriverManager.getConnection(
"jdbc:mysql://" +
DB_URL +
"/duptest?serverTimezone=UTC&useSSL=false",
DB_USER,
DB_PASSWORD);
}
}
DBSetup 클래스는 DB의 주소와 ID, PW를 받아 getConnection 함수에서 Connection 객체를 반환한다.
public class FileMetadataDao {
private final Connection connection;
/**
* Table name for FileMetadata.
*/
public static final String FILE_TB_NAME = "file_metadata";
/**
* Constructor for FileMetadataDao.
* @param connection connection to the database
*/
public FileMetadataDao(Connection connection) {
this.connection = connection;
}
/**
* Insert metadata into the database.
* @param FileMetadata metadata to insert
*/
public void insert(FileMetadata FileMetadata) {
String insertQuery = "INSERT INTO " + FILE_TB_NAME + " (path, last_modified, size, hash) VALUES (?, ?, ?, ?)";
try (PreparedStatement pstmt = connection.prepareStatement(insertQuery)) {
pstmt.setString(1, FileMetadata.path());
pstmt.setLong(2, FileMetadata.lastModified());
pstmt.setLong(3, FileMetadata.size());
pstmt.setString(4, FileMetadata.hash());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
...
위 코드는 파일의 메타데이터와 데이터베이스 사이에 상호작용을 처리하는 DAO 클래스다. 보인 코드는 insert 함수만 있지만, update, search 등의 동작이 구현되어 있다.
insert 함수를 살펴보면 쿼리를 직접 String으로 만들고 있다. 또한 필요한 정보를 PreparedStatement를 사용해 '?' 문자를 직접 대치한다. 비록 지금은 작은 프로젝트지만 더 큰 클래스를 데이터베이스에 저장하려고 쿼리를 쓴다면 훨씬 복잡해질 것이다.
Github
실사용과 평가
대체로 원하는 동작은 잘 작동했다. 루트 폴더 전체를 올바르게 탐색하고 업데이트 된 폴더만 탐색하기도 했다. 이 프로젝트를 통해 배운 것은
- SQL을 처음 코드와 함께 다루어보았다. 아주 기본적인 사용법은 익힐 수 있었다.
- 외부 데이터베이스에 연결하고 사용하는 법을 배웠다.
- h2와 같은 인메모리 데이터베이스를 유닛 테스트에서 사용하는 법을 배웠다. 실제 실행될 코드를 만드는데 아주 큰 도움이 되었다.
- 파일이 파일시스템에서 어떻게 저장되고 어떤 정보와 함께 저장되는지 알게 되었다.
그러나 예상보다는 크게 만족스럽지 못했는데 다음과 같은 이유 때문이다.
- 처음 배운 SQL을 직접 다루어보기 위해 시작한 프로젝트인 만큼 결과물의 필요성이 높지 않아 자주 사용하지 않았다.
- 파일을 다루기 위한 파일 시스템이라는 좋은 도구가 이미 있고 심지어 불가피하게 써야만 한다.
- 정규화를 할 만큼 복잡하지 않아서 모두 한 테이블에 담았더니 중복된 데이터가 너무 많았다.
- 긴 실행시간이 필요했는데 대부분의 지연은 파일 탐색과 SQL 통신에서 발생했다.
느낀 점
- 역시 데이터베이스는 아주 재미있고 신기하다.
- 파일 데이터나 경로 이외의 파일과 관련된 정보는 굳이 데이터베이스에 저장하지 말자. 파일 시스템이 더 잘 다룬다.
- 정규화는 중요하다. 특히 이번에는 데이터 무결성을 클라이언트에서 검사했는데, 파일마다 중복을 검사하다보니 n!의 복잡도가 발생했다. DB에서 처리하면 더 나은 방법이 있었을 것이다.
- 통신에서 많은 지연이 발생했다. 내부망이 아니라면 더 심했을 것이다. 프로시저를 사용했다면 통신에서 지연을 줄일 수 있었을 것이다.
- 파일 탐색에서도 많은 지연이 발생했다. 새로 업데이트 된 파일만 살펴본다고 해도 어차피 모든 파일의 수정 시각을 살펴야하기 때문에 파일 용량이 작고 개수가 많다면 말짱 도루묵이다. 파일은 파일 시스템에게 맡기자.
'IT > 기타' 카테고리의 다른 글
중고 Thinkpad X200 리뷰 (4) | 2024.11.08 |
---|---|
Git branch 전략에 대하여 (0) | 2024.09.14 |
강의 자료를 동기화하면서 겪었던 시행착오들 (0) | 2023.04.07 |
비정형 기계와 유전 알고리즘 (0) | 2022.02.01 |
비정형 기계 만들기 (0) | 2022.01.28 |