JDBC 실습 예제 - 10

목차

    1. 요구사항

    JDBC를 사용하여 학생 관리 시스템을 구축해 보자.

    ● 학생의 정보를 데이터베이스에 저장하고 관리하는 간단한 시스템을 구축합니다.
    ● 학생 정보를 추가, 조회, 수정, 삭제할 수 있는 기능을 구현합니다.
    1. 기능 요구사항
      • 학생 정보 추가
      • 학생 정보 조회
      • 학생 정보 수정
      • 학생 정보 삭제
    2. 비기능 요구사항
      • 사용자 친화적인 콘솔 인터페이스 제공
      • 적절한 예외 처리 및 로그 기록
      • 데이터베이스 연결 풀 사용(HikariCP)

    2. 프로젝트 설계

    1. 데이터베이스 설계 및 테이블 생성

     테이블 - tbstudent

     컬럼 - id, name, age, email

    create database studentdb;
    
    CREATE TABLE students (
        id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(100) NOT NULL,
        age INT NOT NULL,
        email VARCHAR(100) NOT NULL UNIQUE
    );

     

    2. 클래스 설계(자유롭게 설계)

    package student_management;
    
    public class ManagementRespositoryImpl implements ManagementRespository {
    
    	public static final String SELECT = " select * from students where name = ? ";
    	public static final String SELECT_ALL = " select * from students ";
    	public static final String INSERT_ALL = " insert into students(name, age, email) values (?,?,?) ";
    	public static final String UPDATE_AGE = " update students set age = ? where name = ? ";
    	public static final String UPDATE_EMAIL = " update students set email = ? where name = ? ";
    	public static final String DELETE = " delete from students where name = ? ";
    
    	@Override
    	public int addStudent(String name, int age, String email) throws SQLException {
    		int resultRowCount = 0;
    		try (Connection conn = DBConnectionManger.getConnection()) {
    			PreparedStatement pstmt = conn.prepareStatement(INSERT_ALL);
    			pstmt.setString(1, name);
    			pstmt.setInt(2, age);
    			pstmt.setString(3, email);
    			resultRowCount = pstmt.executeUpdate();
    		}
    		return resultRowCount;
    	}
    
    	@Override
    	public List<StudentDTO> viewStudent(String name) throws SQLException {
    		List<StudentDTO> list = new ArrayList<>();
    		try (Connection conn = DBConnectionManger.getConnection()) {
    			PreparedStatement pstmt = conn.prepareStatement(SELECT);
    			pstmt.setString(1, name);
    			if (name.equals("all")) {
    				pstmt = conn.prepareStatement(SELECT_ALL);
    			}
    			ResultSet rs = pstmt.executeQuery();
    			while (rs.next()) {
    				int id = rs.getInt(1);
    				String name1 = rs.getString(2);
    				int age = rs.getInt(3);
    				String email = rs.getString(4);
    				list.add(new StudentDTO(id, name1, age, email));
    			}
    		}
    		return list;
    	}
    	
    	@Override
    	public int updateAge(String name, int age) throws SQLException {
    		int resultRowCount = 0;
    		try (Connection conn = DBConnectionManger.getConnection()){
    			PreparedStatement pstmt = conn.prepareStatement(UPDATE_AGE);
    			pstmt.setString(2, name);
    			pstmt.setInt(1, age);
    			resultRowCount = pstmt.executeUpdate();
    		}
    		return resultRowCount;
    	}
    	
    	@Override
    	public int updateEmail(String name, String email) throws SQLException {
    		int resultRowCount = 0;
    		try (Connection conn = DBConnectionManger.getConnection()){
    			PreparedStatement pstmt = conn.prepareStatement(UPDATE_EMAIL);
    			pstmt.setString(2, name);
    			pstmt.setString(1, email);
    			resultRowCount = pstmt.executeUpdate();
    		}
    		return resultRowCount;
    	}
    	
    	@Override
    	public int deleteStudent(String name) throws SQLException {
    		int resultRowCount = 0;
    		try (Connection conn = DBConnectionManger.getConnection()){
    			PreparedStatement pstmt = conn.prepareStatement(DELETE);
    			pstmt.setString(1, name);
    			resultRowCount = pstmt.executeUpdate();
    		}
    		return resultRowCount;
    	}
    
    }
    package student_management;
    
    public class StudentManagementTest {
    
    	static final int INSERT = 1;
    	static final int SELECT = 2;
    	static final int UPDATE = 3;
    	static final int DELETE = 4;
    	static final int SELECT_ALL = 5;
    	static final int END = 0;
    	static String name;
    	static int age;
    	static String email;
    
    	public static void main(String[] args) {
    		try (Scanner sc = new Scanner(System.in)) {
    			ManagementRespositoryImpl respositoryImpl = new ManagementRespositoryImpl();
    			while (true) {
    				System.out.println();
    				printMenu();
    				int choice = sc.nextInt();
    				sc.nextLine();
    				switch (choice) {
    				case INSERT:
    					System.out.print("이름을 입력하세요 : ");
    					name = sc.nextLine();
    					name.trim();
    					System.out.print("나이를 입력하세요 : ");
    					try {
    						age = sc.nextInt();
    						sc.nextLine();
    					} catch (Exception e) {
    						System.out.println("숫자만 입력해주세요");
    						sc.nextLine();
    						break;
    					}
    					System.out.print("이메일을 입력하세요 : ");
    					email = sc.nextLine();
    					email.trim();
    					if (!isValidEmail(email)) {
    						System.out.println("잘못된 이메일 형식입니다.");
    						break;
    					}
    					try {
    						respositoryImpl.addStudent(name, age, email);
    					} catch (Exception e) {
    						System.out.println("입력 오류");
    						break;
    					}
    					break;
    				case SELECT:
    					System.out.print("이름을 입력하세요 : ");
    					name = sc.nextLine();
    					name.trim();
    					printStudent(respositoryImpl.viewStudent(name));
    					break;
    				case UPDATE:
    					System.out.println("이름을 입력하세요 : ");
    					name = sc.nextLine();
    					name.trim();
    					
    					if (respositoryImpl.viewStudent(name).size() == 0) {
    						System.out.println("없는 이름입니다.");
    						break;
    					}
    					System.out.println("나이를 변경하려면 1번");
    					System.out.println("이메일을 변경하려면 2번");
    					int choice2 = sc.nextInt();
    					sc.nextLine();
    					if (choice2 == 1) {
    						System.out.println("나이를 입력하세요 : ");
    						try {
    							age = sc.nextInt();
    							sc.nextLine();
    						} catch (Exception e) {
    							System.out.println("숫자만 입력해주세요");
    							sc.nextLine();
    							break;
    						}
    						sc.nextLine();
    						respositoryImpl.updateAge(name, age);
    					} else if (choice2 == 2) {
    						System.out.print("이메일을 입력하세요 : ");
    						email = sc.nextLine();
    						email.trim();
    						if (!isValidEmail(email)) {
    							System.out.println("잘못된 이메일 형식입니다.");
    							break;
    						}
    						try {
    							respositoryImpl.updateEmail(name, email);
    						} catch (Exception e) {
    							System.out.println("입력오류");
    						}
    					} else {
    						System.out.println("잘못된 입력입니다.");
    					}
    					break;
    				case DELETE:
    					System.out.println("이름을 입력하세요 : ");
    					name = sc.nextLine();
    					name.trim();
    					respositoryImpl.deleteStudent(name);
    					break;
    				case SELECT_ALL:
    					printStudent(respositoryImpl.viewStudent("all"));
    					break;
    				case END:
    					return;
    				default :
    					System.out.println("올바른 숫자를 입력하세요");
    					sc.nextLine();
    					break;
    				}
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    	private static void printStudent(List<StudentDTO> viewStudent) {
    		for (StudentDTO studentDTO : viewStudent) {
    			System.out.println(studentDTO);
    		}
    
    	}
    
    	private static void printMenu() {
    		System.out.println("---------------------------------------------");
    		System.out.println("1. 학생 정보 추가");
    		System.out.println("2. 학생 정보 조회");
    		System.out.println("3. 학생 정보 수정");
    		System.out.println("4. 학생 정보 삭제");
    		System.out.println("5. 학생 전체 조회");
    		System.out.println("0. 종료");
    		System.out.print("옵션을 선택하세요 : ");
    	}
    
    	private static boolean isValidEmail(String email) {
    		// 이메일 유효성 검사 정규표현식
    		String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
    		return email.matches(emailRegex);
    	}
    
    }

    3. 풀이 코드

    package student_management.ver02;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    import com.zaxxer.hikari.HikariConfig;
    import com.zaxxer.hikari.HikariDataSource;
    
    // 싱글톤 패턴 - 단 하나의 객체만 필요함을 보장해야 된다면
    // 싱글톤 패턴으로 설계할 수 있다.
    public class DBConnectionManager {
    
    	// 자기 자신의 참조 주소값을 담을 변수 생성 단, private
    	private static DBConnectionManager instance;
    	private HikariDataSource dataSource;
    
    	// 생성자를 <---- 외부에서 생성자를 호출 못하게 막아야 한다.
    	private DBConnectionManager() {
    		HikariConfig config = new HikariConfig();
    		config.setJdbcUrl("jdbc:mysql://localhost:3306/studentdb?serverTimezone=Asia/Seoul");
    		config.setUsername("root");
    		config.setPassword("asd123");
    		config.setMaximumPoolSize(10);
    
    		dataSource = new HikariDataSource(config);
    	}
    
    	// 외부에서 클래스이름.getxxx 메서드를 만들어 주면 된다.
    	// 한 번에 하나의 스레드만 접근하도록 동기화 적용
    	public static synchronized DBConnectionManager getInstance() {
    		if (instance == null) {
    			instance = new DBConnectionManager();
    		}
    		return instance;
    	}
    	
    	// Connection 객체를 반환( 구현체 - HikariCP 이다 )
    	public Connection getConnection() throws SQLException {
    		return dataSource.getConnection();
    	}
    
    }
    package student_management.ver02;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    import student_management.ver02.model.StudentDTO;
    
    // 물론 기능 설계는 인터페이스를 먼저 작성하고 구현 클래스를 만드는 것이 좋다.
    public class StudentDAO {
    
    	// 학생 정보 추가 기능 만들기
    	public void addStudent(StudentDTO dto) throws SQLException {
    		String query = " INSERT INTO students(name, age, email) VALUES(?, ?, ?) ";
    		try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
    			PreparedStatement pstmt = conn.prepareStatement(query);
    			pstmt.setString(1, dto.getName());
    			pstmt.setInt(2, dto.getAge());
    			pstmt.setString(3, dto.getEmail());
    			pstmt.executeUpdate();
    		}
    	}
    
    	// 학생의 아이디로 조회하는 기능 만들기, (id)
    	public StudentDTO getStudentById(int id) throws SQLException {
    
    		String query = " SELECT * FROM students WHERE id = ? ";
    		try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
    			PreparedStatement pstmt = conn.prepareStatement(query);
    			pstmt.setInt(1, id);
    			try (ResultSet rs = pstmt.executeQuery()) {
    				if (rs.next()) {
    					return new StudentDTO(rs.getInt("id"), rs.getString("name"), //
    							rs.getInt("age"), rs.getString("email"));
    				}
    			}
    
    		}
    		return null;
    	}
    
    	// 학생 전체 조회 기능
    	public List<StudentDTO> getAllStudents() throws SQLException {
    		// tip - 리스트라면 무조건 리스트를 생성하고 코드 작성
    		List<StudentDTO> list = new ArrayList<>();
    		String query = " SELECT * FROM students ";
    		try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
    			PreparedStatement pstmt = conn.prepareStatement(query);
    			try (ResultSet rs = pstmt.executeQuery()) {
    				while (rs.next()) {
    					StudentDTO dto = new StudentDTO().builder().id(rs.getInt("id")).name(rs.getString("name")).age(rs.getInt("age"))
    							.email(rs.getString("email")).build();
    					list.add(dto);
    				}
    			}
    
    		}
    		return list;
    	}
    
    	// 학생 정보 수정하기
    	public void updateStudent(String name, StudentDTO dto) throws SQLException {
    		String query = " UPDATE students SET name = ?, age = ?, email = ? WHERE name = ? ";
    		try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
    			PreparedStatement pstmt = conn.prepareStatement(query);
    			pstmt.setString(1, dto.getName());
    			pstmt.setInt(2, dto.getAge());
    			pstmt.setString(3, dto.getEmail());
    			pstmt.setString(4, name); // 조건값 세팅
    			pstmt.executeUpdate();
    		}
    	}
    
    	// 학생 정보 삭제하기
    	public void deleteStudent(int id) throws SQLException {
    		String query = " DELETE FROM students WHERE id = ? ";
    		try (Connection conn = DBConnectionManager.getInstance().getConnection()) {
    			PreparedStatement pstmt = conn.prepareStatement(query);
    			pstmt.setInt(1, id);
    			pstmt.executeUpdate();
    		}
    	}
    
    }
    package student_management.ver02;
    
    import java.sql.SQLException;
    import java.util.List;
    
    import student_management.ver02.model.StudentDTO;
    
    public class StudentManagementSystem {
    	
    	private static final StudentDAO STUDENT_DAO = new StudentDAO();
    	
    	public static void main(String[] args) {
    		// 사용자에게 보여주는 부분 꾸며 줘도 됨
    		try {
    			List<StudentDTO> list = STUDENT_DAO.getAllStudents();
    			System.out.println(list.size());
    			System.out.println(list.toString());
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    	}
    }

    자료 구조(Data Structure) - 4으로 돌아가기

     

    'Java > 자료구조' 카테고리의 다른 글

    자료 구조(Data Structure)  (0) 2024.06.17
    JDBC에서의 예외 처리 - 9  (1) 2024.06.17
    JDBC 성능 최적화 - 8  (0) 2024.06.17
    JDBC를 활용한 CRUD 와 SOLID 원칙 - 7  (1) 2024.06.14
    JDBC 트랜잭션 관리와 배치 처리 - 6  (0) 2024.06.12