본문 바로가기

학원/복기

[JDBC] JAVA에서 저장 프로시저 호출 / Properties 파일 / DBCP 클래스 / UCP 라이브러리 / DAO 디자인 패턴

JAVA에서 저장 프로시저 호출하기

 

Connection.prepareCall(String sql) : 저장 프로시저를 호출하는 명령을 전달하여 실행하기 위한 CallableStatement 객체를 반환하는 메소드
→ 저장 프로시저를 호출하는 명령 - {call 저장프로시저명(?,?,...)}
→ 저장 프로시저 호출시 사용한 [ ? ] 기호에는 반드시 setXXX() 메소드를 호출하여 값을 전달하거나 registerOutParameter() 메소드를 호출하여 값을 제공받아 저장 

CallableStatement.setXXX(int parameterIndex, XXX value) : 저장 프로시저에 사용한 매개변수 중 IN 모드의 매개변수에 값을 전달하기 위한 메소드 

CallableStatement.registerOutParameter(int parameterIndex, int sqlType) : 저장 프로시저에서 사용한 매개변수 중 OUT 모드의 매개변수에 저장된 값을 제공받기 위한 메소드
  sqlType : SQL 자료형 - Types 클래스의 상수 사용 

CallableStatement.getString(int parameterIndex) :  저장 프로시저에서 사용한 매개변수 중 OUT 모드의 매개변수에 저장된 값을 반환하는 메소드 

CallableStatement.exectue() : 저장 프로시저를 호출하는 명령을 전달하여 실행하는 메소드 



SQL에서 저장 프로시저 생성

CREATE OR REPLACE PROCEDURE DELETE_STUDENT(VNO IN STUDENT.NO%TYPE
    ,VNAME OUT STUDENT.NAME%TYPE) IS 
BEGIN 
    SELECT NAME INTO VNAME FROM STUDENT WHERE NO=VNO;
    IF SQL%FOUND THEN 
        DELETE FROM STUDENT WHERE NO=VNO;
        COMMIT;
    END IF;
EXCEPTION
    WHEN OTHERS THEN 
        VNAME := NULL;
END;
/

 

키보드로 학번을 입력받아 STUDENT 테이블에 저장된 학생정보 중 해당 학번의 학생정보를 삭제하는 JDBC 프로그램 작성 
(저장 프로시저를 호출하여 학생정보를 삭제 처리)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Types;

public class CallableStatementApp {
	public static void main(String[] args) throws Exception {
		BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
		
		System.out.println("<<학생정보 삭제>>");
		System.out.print("학번 입력 >> ");
		int no=Integer.parseInt(in.readLine());
		System.out.println("=================================================================");
		Connection con=ConnectionFactory.getConnection();
		
		String sql="{call delete_student(?,?)}";
		CallableStatement cstmt=con.prepareCall(sql);
        
		cstmt.setInt(1, no);//IN 모드의 매개변수에 값을 전달
		
		cstmt.registerOutParameter(2, Types.NVARCHAR);//OUT 모드의 매개변수에 저장된 값을 제공받음 
		
		cstmt.execute();//저장 프로시저를 호출하는 명령을 전달하여 실행 
		
		String name=cstmt.getString(2);//OUT 모드의 매개변수에 저장된 값을 반환
		
		if(name==null) {
			System.out.println("[메시지]해당 학번의 학생정보를 찾을 수 없습니다.");
		} else {
			System.out.println("[메시지]"+name+"님을 삭제 하였습니다.");
		}
		
		ConnectionFactory.close(con, cstmt);
	}
}

Properties 파일

: 프로그램 실행에 필요한 값을 제공하기 위한 텍스트 파일 - 확장자 : ~.properties

  • 프로그램을 변경하지 않고 Properties 파일의 내용을 변경하여 프로그램 실행 결과를 변경할 수 있다.
  • 프로그램의 유지보수 효율성이 증가된다. 
  • Properties 파일에서 제공되는 값은 문자열만 가능하다. 
  • Properties 파일에서는 영문자,숫자,일부 특수문자를 제외한 나머지 문자는 유니코드로 변환되어 처리된다.

~.properties 파일 생성 방법 

: 패키지 우클릭 >> New >> File >> ~.properties 로 파일 생성 

user.properties 파일 생성

#Comment - \uC124\uBA85\uBB38
#properties File >> Configuration File
#Name = Value
id = abc123
password = 123456
name = \uC784\uAEBD\uC815

 

user.properties 파일에 저장된 값을 얻어와 출력하는 프로그램 작성

Object.getClass() : 현재 실행중인 클래스에 대한 Class 객체(Clazz)를 반환하는 메소드
Class.getClassLoader() : 클래스를 읽어 메모리에 저장된 ClassLoader 객체를 반환하는 메소드 
ClassLoader.getResourceAsStream(String name) : 리소스 파일에 대한 입력스트림을 생성하여 반환하는 메소드

Properties 파일을 읽기 위한 입력스트림 생성

InputStream in=getClass().getClassLoader().getResourceAsStream("xyz/itwill/dbcp/user.properties")

 

Properties 객체 생성 - 다수의 엔트리(Entry - Key와 Value) 저장 
→ Properties 클래스는 Map 인터페이스를 상속받은 자식클래스 
→ Properties 객체 : Properties 파일의 이름(name)과 값(Value)을 하나의 엔트리(Entry)로 저장하기 위한 객체 

Properties properties = new Properties();

Properties.load(InputStream in): 입력스트림으로 Properies 파일을 제공받아 파일에 저장된 모든 이름과 값으로 Properties 객체에 엔트리를 추가하는 메소드 

properties.load(in);

properties.get(String key) : Properties 객체에 저장된 엔트리에서 맵키(MapKey)를 전달받아 맵키와 매칭된 맵값(MapValue)를 반환하는 메소드 
→ 맵값은 Object 객체로 반환되므로 반드시 명시적 객체 형변환 후 사용이 가능하다. 

String id=(String)properties.get("id");
String password=(String)properties.get("password");
String name=(String)properties.get("name");

 

전체 소스코드

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PropertiesApp {
	public PropertiesApp() throws IOException {
		//Properties 파일을 읽기 위한 입력스트림 생성 
		InputStream in=getClass().getClassLoader().getResourceAsStream("xyz/itwill/dbcp/user.properties");		
		
		//Properties 객체 생성 - 다수의 엔트리(Entry - Key와 Value) 저장 
		Properties properties = new Properties();
		
        	//Properties 객체에 엔트리를 추가
		properties.load(in);
		
        	//맵키와 매칭된 맵값(MapValue)를 반환
		String id=(String)properties.get("id");
		String password=(String)properties.get("password");
		String name=(String)properties.get("name");
		
		System.out.println("아이디 = "+id);
		System.out.println("비밀번호 = "+password);
		System.out.println("이름 = "+name);
	}
	public static void main(String[] args) throws IOException {
		new PropertiesApp();
	}
}

출력 결과


DBCP(DataBase Connection Pool) 클래스

: 다수의 Connection 객체를 미리 생성하여 저장하고 Connection 객체를 반환하는 기능을 제공하는 클래스 

  • Connection 객체를 미리 생성하여 사용하므로 JDBC 프로그램의 실행 속도가 증가한다.
  • Connection 객체를 생성하기 위한 정보의 변경이 용이하다. →  유지보수의 효율성이 증가
  • Connection 객체의 갯수를 제한할 수 있다. 


DBCP 객체 안에는 Connection 객체가 미리 만들어져 있다. (DBMS 서버에 이미 다 접속되어있다.)
JDBC 프로그램은 서버에 접속할 필요 없이 Connection을 빌려다 쓰기만 하면 되기 때문에 속도가 빨라진다는 장점이 있다.


javax.sql.DataSource 

: DBCP 클래스를 작성하기 위해 상속받기 위한 인터페이스 
→  DBCP 클래스의 메소드를 동일한 형식으로 작성하기 위한 규칙을 제공한다.  
*ConnectionPool이 바뀌더라도 프로그램에 영향을 미치지 않는다.


* ConnectionPool 이란?

  • 웹 컨테이너(WAS)가 실행되면서 일정량의 Connection 객체를 미리 만들어서 pool에 저장했다가, 클라이언트 요청이 오면 Connection 객체를 빌려주고 해당 객체의 임무가 완료되면 다시 Connection 객체를 반납 받아서 pool에 저장하는 프로그래밍 기법이다.
  • Container 구동 시 일정 수의 Connection 객체를 생성하게 되며 클라이언트의 요청에 의해 애플리케이션이 DBMS 작업을 수행해야 하면, Connection Pool에서 Connection 객체를 받아와 작업을 진행한다. 이후 작업이 끝나면 Connetion Pool에 Connection 객체를 반납한다.

출처 : https://steady-coding.tistory.com/564



오라클이 제공해주는 ConnectionPool은 UCP 라이브러리 안에 있다.

UCP(Universal Connection Pool) 라이브러리로 제공되는 DBCP 클래스를 이용한 JDBC 프로그램을 작성하기 위해서는, 
https://www.oracle.com 사이트의 페이지에서 UCP 라이브러리 파일(ucp11.jar) 파일을 다운로드 받아 프로젝트에 빌드 처리해야 한다.


UCP(Universal Connection Pool) 라이브러리로 제공되는 DBCP 클래스를 이용한 JDBC 프로그램 작성 

import java.sql.Connection;
import java.sql.SQLException;

import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;

public class DataSourceApp {
	public static void main(String[] args) throws SQLException {
		//PoolDataSource 객체(DBCP 객체)를 반환받아 저장
		PoolDataSource pds=PoolDataSourceFactory.getPoolDataSource();
		
		//PoolDataSource 객체에 저장될 Connection 객체를 생성하기 위한 메소드 호출 
		pds.setConnectionFactoryClassName("oracle.jdbc.driver.OracleDriver");
		
		//PoolDataSource 객체의 URL 주소, 사용자 이름, 사용자 비밀번호 변경 
		pds.setURL("jdbc:oracle:thin:@localhost:1521:xe");
		pds.setUser("scott");
		pds.setPassword("tiger");
		
		//Connection 객체의 갯수 제한(생략가능-생략하면 기본값 사용하여 갯수 제한)
		pds.setInitialPoolSize(2);//최초 생성되는 Connection 객체의 갯수 변경
		pds.setMaxPoolSize(3);//최대 생성되는 Connection 객체의 갯수 변경
		
		Connection con1=pds.getConnection();
		System.out.println("con1 = "+con1);
		//Connection 객체를 제거하면 자동으로 PoolDataSource 객체로 Connection 객체를 반환
		con1.close();
		
		Connection con2=pds.getConnection();
		System.out.println("con2 = "+con2);
		con2.close();
		
		Connection con3=pds.getConnection();
		System.out.println("con3 = "+con3);
		con3.close();
	}
}

PoolDataSource 객체로 Connection 객체를 반환했기 때문에 모두 같다.

만약 Connection 객체를 반환하지 않으면,

다른 Connection 객체를 가져다가 사용한다.


프로그램마다 JDBC 프로그램을 구현할 수 있는데, 이 때 JDBC 기능들을 전달하는 SQL 명령들이 중복될 수 있다.

때문에 클래스(DAO 클래스)를 하나 더 생성해서, 클래스 내부에 JDBC 기능을 구현할 메소드를 구현해 각각의 프로그램에서 가져다 쓸 수 있도록 해준다.

이처럼 JDBC 기능을 DAO 클래스가 구현할 수 있도록 하고, 실제 프로그램에서는 필요한 기능을 DAO 클래스가 가지고 있는 메소드를 호출해 기능을 구현하는 것이 더 효율적이다. >> 생산성과 유지보수의 효율성에 좋다.


DAO 디자인 패턴 ★중요

순서: DTO 클래스 생성 >> DAO 클래스가 상속받을 인터페이스 생성 >> DAO 클래스 생성 

DAO 클래스 생성하기 전에, DAO 클래스가 상속받을 인터페이스를 먼저 생성해주는 것이 좋다.
(DBMS가 바뀌어서 DAO를 다시 만들어 줄 때, 더 편리하게 하기 위해)

DAO 클래스가 상속받을 인터페이스는 추상메소드를 이용하여 인터페이스를 상속받은 자식클래스(DAO 클래스)가 동일한 메소드가 선언되도록 메소드의 작성 규칙을 제공한다. (이는 인터페이스의 가장 중요한 역할이다.)

→ DAO 클래스가 변경되어도 프로그램에 영향을 최소화 할 수 있다. (즉, 결합도를 낮춘다.)

인터페이스 생성하기 전에, DAO 클래스의 메소드에 필요한 정보(값)를 매개변수로 전달하거나 메소드의 실행결과를 저장하여 반환하기 위한 클래스인 DTO(Data Transfer Object) 클래스를 먼저 생성한다. 

DTO(Data Transfer Object) 클래스 

: DAO 클래스의 메소드에 필요한 정보(값)를 매개변수로 전달하거나 메소드의 실행결과를 저장하여 반환하기 위한 클래스 - VO(Value Object) 클래스 
→ 테이블의 컬럼과 1:1로 매핑되는 필드를 선언한다. - Getter & Setter
→ 필드의 이름은 컬럼의 이름과 동일하게 작성하는 것을 권장한다.


-------------------------------

desc student; --SQL


이름       널?       유형            
-------- -------- ------------- 
NO       NOT NULL NUMBER(4)     
NAME              VARCHAR2(50)  
PHONE             VARCHAR2(20)  
ADDRESS           VARCHAR2(100) 
BIRTHDAY          DATE       

------------------------------

StudentDTO 클래스 생성 - STUDENT 테이블에 저장된 하나의 행(학생정보)을 저장하여 전달하기 위한 클래스

public class StudentDTO {
	private int no;
	private String name;
	private String phone;
	private String address;
	private String birthday;
	
	//기본 생성자 선언
	public StudentDTO() {
		// TODO Auto-generated constructor stub
	}
	
	//매개변수가 있는 생성자 선언 
	public StudentDTO(int no, String name, String phone, String address, String birthday) {
		super();
		this.no = no;
		this.name = name;
		this.phone = phone;
		this.address = address;
		this.birthday = birthday;
	}
	
	//Setter Getter 메소드
	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getBirthday() {
		return birthday;
	}

	public void setBirthday(String birthday) {
		this.birthday = birthday;
	}

	
}

 

StudentDAO 인터페이스 생성

DAO 클래스가 상속받기 위한 인터페이스인 StudentDAO 인터페이스 생성

StudentDAO 인터페이스를 상속받은 모든 자식클래스들이 StudentDAO 인터페이스 내부의 메소드들을 모두 오버라이딩 할 수 있도록 추상메소드를 선언해준다.

import java.util.List;

public interface StudentDAO {
	//학생정보를 전달받아 STUDENT 테이블에 삽입하고 삽입행의 갯수를 반환하는 메소드 
	int insertStudent(StudentDTO student);
	
	//학생정보를 전달받아 STUDENT 테이블에 저장된 학생정보를 변경하고 변경행의 갯수를 반환하는 메소드
	int updateStudent(StudentDTO student);
	
	//학번을 전달받아 STUDENT 테이블에 저장된 학생정보를 삭제하고 삭제행의 갯수를 반환하는 메소드 
	int deleteStudent(int no);
	
	//학번을 전달받아 STUDENT 테이블에 저장된 해당 학번의 학생정보를 검색하여 반환하는 메소드
	// => 단일행은 값 또는 DTO 객체를 반환한다. 
	//(예를 들어,이름만 검색해서 반환해달라 했으면 StudentDTO 대신 String 객체를 반환하면 된다.)
	StudentDTO selectStudent(int no);
	
	//이름을 전달받아 STUDENT 테이블에 저장된 해당 이름의 학생정보를 검색하여 반환하는 메소드 
	// => 다중행은 list 객체를 반환한다. 
	List<StudentDTO> selectNameStudentList(String name);//List 객체 안에는 학생정보'들'이 저장되어있다.
	
	//STUDENT 테이블에 저장된 모든 학생 정보를 검색하여 반환하는 메소드 
	List<StudentDTO> selectAllStudentList();
}

 

jdbcDAO 클래스 생성 

- 모든 DAO 클래스가 상속받아 사용하기 위한 부모클래스의 역할
→ DBCP(DataBaseConnectionPool) 객체를 생성하여 미리 Connection 객체를 생성하여 저장하고 DBCP 객체로부터 Connection 객체를 반환하거나 JDBC 관련 객체를 매개변수로 전달받아 제거하는 메소드 생성
→ 객체 생성이 목적이 아닌 상속을 목적으로 작성된 클래스이므로 추상클래스로 선언하는 것을 권장한다. (new 연산자 이용해 해당 클래스로 객체를 생성하지 않도록) 

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;

//모든 DAO 클래스가 상속받아 사용하기 위한 부모클래스
public abstract class JdbcDAO {
	//PoolDataSource 객체(DBCP 객체)를 저장하기 위한 필드 
	private static PoolDataSource pds;
	
	static {
		//PoolDataSource 객체를 반환받아 필드에 저장 
		pds=PoolDataSourceFactory.getPoolDataSource();
		try {
			//PoolDataSource 객체에 Connection 객체를 미리 생성하여 저장 
			pds.setConnectionFactoryClassName("oracle.jdbc.driver.OracleDriver");
			pds.setURL("jdbc:oracle:thin:@localhost:1521:xe");
			pds.setUser("scott");
			pds.setPassword("tiger");
			pds.setInitialPoolSize(10); //Connection 10개 생성
			pds.setMaxPoolSize(15); //Connection 최대 15개까지 생성 가능 
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	//PoolDataSource 객체(DBCP 객체)에 저장된 Connection 객체 중 하나를 반환하는 메소드 
	public Connection getConnection() {
		Connection con=null;
		try {
			con=pds.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return con;
	}
	
	//매개변수로 JDBC 관련 객체를 전달받아 제거하는 메소드 
	public void close(Connection con) {
		try {
			//Connection 객체 제거 : PoolDataSource 객체(DBCP 객체)에게 다시 Connection 돌려주는 기능 구현
			if(con != null) con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public void close(Connection con, PreparedStatement pstmt) {
		try {
			if(pstmt != null) pstmt.close();
			if(con != null) con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public void close(Connection con, PreparedStatement pstmt, ResultSet rs) {
		try {
			if(rs != null) pstmt.close();
			if(pstmt != null) pstmt.close();
			if(con != null) con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

 

DAO(Data Access Object) 클래스 - 데이터에 접근하는 객체를 만들어주는 클래스

: 저장매체에 행 단위 정보를 삽입,삭제,변경,검색하는 기능을 제공하는 클래스 

→ 저장매체 : 정보를 행단위로 저장하여 관리하기 위한 하드웨어 또는 소프트웨어 - DBMS (저장매체로 DBMS를 이용할 것이다)
→ 인터페이스를 상속받아 작성하는 것을 권장한다. - 메소드 작성 규칙을 제공하기 때문에, 유지보수의 효율성이 증가한다.
→ 싱글톤 디자인 패턴을 적용하여 작성하는 것을 권장한다. -> 프로그램에 하나의 객체만 제공되는 클래스로 만들어 줄 수 있다.

StudentDAOImpl 클래스 생성 

STUDENT 테이블에 행을 삽입,삭제,변경,검색하는 기능의 메소드를 제공하는 DAO 클래스인 StudentDAOImpl 클래스 생성 

  •  DAO 클래스의 메소드는 SQL 명령에 필요한 값을 매개변수로 전달받아 하나의 SQL 명령을 DBMS 서버에 전달하여 실행하고 실행결과를 Java 객체(or 값)로 매핑하여 반환한다.
  • JdbcDAO 클래스를 상속받아 DAO 클래스의 메소드에서 JdbcDAO 클래스의 메소드 호출이 가능하다.
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class StudentDAOImpl extends JdbcDAO implements StudentDAO {
	private static StudentDAOImpl _dao;
	
	//싱글톤 디자인 패턴 적용 >> 객체가 정적영역에서 딱 하나만 반환된다. 
	public StudentDAOImpl() {
		// TODO Auto-generated constructor stub
	}
	
	static {
		_dao=new StudentDAOImpl();
	}
	
	public static StudentDAOImpl getDAO() {
		return _dao;
	}

	//학생정보를 전달받아 STUDENT 테이블에 삽입하고 삽입행의 갯수를 반환하는 메소드
	@Override
	public int insertStudent(StudentDTO student) {
		Connection con=null;
		PreparedStatement pstmt=null;
		int rows=0;
		try {
			con=getConnection();
			
			String sql="insert into student values(?,?,?,?,?)";
			pstmt=con.prepareStatement(sql);
			pstmt.setInt(1, student.getNo());
			pstmt.setString(2, student.getName());
			pstmt.setString(3, student.getPhone());
			pstmt.setString(4, student.getAddress());
			pstmt.setString(5, student.getBirthday());
			
			rows=pstmt.executeUpdate();
		} catch (SQLException e) {
			System.out.println("[에러]insertStudnet() 메소드의 SQL 오류 = "+e.getMessage());
		} finally {
			close(con, pstmt);
		}
		return rows; //처리 결과(삽입행의 갯수)를 return해 반환 
	}
	
	//학생정보를 전달받아 STUDENT 테이블에 저장된 학생정보를 변경하고 변경행의 갯수를 반환하는 메소드
	@Override
	public int updateStudent(StudentDTO student) {
		Connection con=null;
		PreparedStatement pstmt=null;
		int rows=0;
		try {
			con=getConnection();
			
			String sql="update student set name=?,phone=?,address=?,birthday=? where no=?";
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, student.getName());
			pstmt.setString(2, student.getPhone());
			pstmt.setString(3, student.getAddress());
			pstmt.setString(4, student.getBirthday());
			pstmt.setInt(5, student.getNo());
			
			rows=pstmt.executeUpdate();
		} catch (SQLException e) {
			System.out.println("[에러]insertStudnet() 메소드의 SQL 오류 = "+e.getMessage());
		} finally {
			close(con, pstmt);
		}
		return rows;
	}
	
	//학번을 전달받아 STUDENT 테이블에 저장된 학생정보를 삭제하고 삭제행의 갯수를 반환하는 메소드 
	@Override
	public int deleteStudent(int no) {
		Connection con=null;
		PreparedStatement pstmt=null;
		int rows=0;
		try {
			con=getConnection();
			
			String sql="delete from student where no=?";
			pstmt=con.prepareStatement(sql);
			pstmt.setInt(1, no);
			
			rows=pstmt.executeUpdate();
		} catch (SQLException e) {
			System.out.println("[에러]insertStudnet() 메소드의 SQL 오류 = "+e.getMessage());
		} finally {
			close(con, pstmt);
		}
		return rows;
	}
	
	//학번을 전달받아 STUDENT 테이블에 저장된 해당 학번의 학생정보를 검색하여 반환하는 메소드
	@Override
	public StudentDTO selectStudent(int no) {
		Connection con=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		StudentDTO student=null;
		try {
			con=getConnection();
			
			String sql="select * from student where no=?";
			pstmt=con.prepareStatement(sql);
			pstmt.setInt(1, no);
			
			rs=pstmt.executeQuery(); 
			
			//ResultSet 객체에 저장된 검색행을 Java 객체(값)로 매핑 처리 (=행을 객체로 바꿔주는 것)
			//검색행이 0 또는 1인 경우 선택문 사용 
			if(rs.next()) {//검색행이 있는 경우
				student=new StudentDTO(); 
				//처리행의 컬럼값을 반환받아 DTO 객체의 필드값으로 변경 처리
				student.setNo(rs.getInt("no"));
				student.setName(rs.getString("name"));
				student.setPhone(rs.getString("phone"));
				student.setAddress(rs.getString("address"));
				student.setBirthday(rs.getString("birthday").substring(0, 10));
			}
		} catch (SQLException e) {
			System.out.println("[에러]insertStudnet() 메소드의 SQL 오류 = "+e.getMessage());
		} finally {
			close(con, pstmt, rs);
		}
		//검색행이 없는 경우 null을 반환하고,
		//검색행이 있는 경우 DTO 객체를 반환한다.(하나의 검색행을 반환)
		return student; 
	}
	
	//이름을 전달받아 STUDENT 테이블에 저장된 해당 이름의 학생정보를 검색하여 반환하는 메소드 
	@Override
	public List<StudentDTO> selectNameStudentList(String name) {
		Connection con=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		List<StudentDTO> studentList=new ArrayList<>();
		try {
			con=getConnection();
			
			String sql="select * from student where name=?";
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, name);
			
			rs=pstmt.executeQuery();
			
			//검색행이 0개 이상인 경우 반복문 사용 
			while(rs.next()) {
				//하나의 검색행을 DTO 객체로 매핑처리 
				StudentDTO student=new StudentDTO();
				student.setNo(rs.getInt("no"));
				student.setName(rs.getString("name"));
				student.setPhone(rs.getString("phone"));
				student.setAddress(rs.getString("address"));
				student.setBirthday(rs.getString("birthday").substring(0, 10));
				
				//DTO 객체를 List 객체의요소로 추가 
				studentList.add(student); 
			}
		} catch (SQLException e) {
			System.out.println("[에러]insertStudnet() 메소드의 SQL 오류 = "+e.getMessage());
		} finally {
			close(con, pstmt, rs);
		}
		return studentList;
	}
	
	//STUDENT 테이블에 저장된 모든 학생 정보를 검색하여 반환하는 메소드 
	@Override
	public List<StudentDTO> selectAllStudentList() {
		// TODO Auto-generated method stub
		return null;
	}
}