[211215] 교육 45일차

oxllz·2022년 2월 17일
1

교육

목록 보기
30/41

DAO Pattern

class Bang01VO 
{
	private Integer no = null;
	public Integer getNo(){ return this.no; }
	public void setNo( Integer i ){ this.no = i; }
	//
	private String content = null;
	public String getContent(){ return this.content; }
	public void setContent( String i ){ this.content = i; }
	//
	private String theTime = null;
	public String getTheTime(){ return this.theTime; }
	public void setTheTime( String i ){ this.theTime = i; }
	//
	private String author = null;
	public String getAuthor(){ return this.author; }
	public void setAuthor( String i ){ this.author = i; }
}
//
class BangDAO {
	public List<Bang01VO> findAll() throws Exception 
	{
		List<Bang01VO> ls = new ArrayList<Bang01VO>();
		//	어떤 상황에서도 close() 가 실행되도록 예외처리 & 에러가 나면 받고 다시 던지는 형태 포함
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			Class.forName("org.mariadb.jdbc.Driver");
			conn = DriverManager.getConnection( "jdbc:mariadb://...", "...", "..." );
			stmt = conn.createStatement();
			rs = stmt.executeQuery("SELECT * FROM bang01_T");
			while( rs.next() ) {
				Bang01VO vo = new Bang01VO();
				vo.setNo( rs.getInt("no") );
				vo.setContent( rs.getString("content") );
				vo.setTheTime( rs.getString("the_time") );
				vo.setAuthor( rs.getString("author") );
				ls.add( vo );
			}
		}
		catch( Exception e ) {
			throw e;
		}
		finally {
			if( rs != null ) rs.close();
			if( stmt != null ) stmt.close();
			if( conn != null ) conn.close();
		}
		return ls;
	}
	//
	public void add( Bang01VO pvo ) throws Exception {
		Connection conn = null;
		Statement stmt = null;
		try {
			Class.forName("org.mariadb.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mariadb://...", "...", "...");
			stmt = conn.createStatement();
			String sql = "INSERT INTO bang01_T VALUES ( default, '"+
				pvo.getContent() + "', NOW() , '" + pvo.getAuthor() + "')";
			stmt.executeUpdate( sql );
		}
		catch ( Exception e ) {
			throw e;			
		}
		finally {
			if( stmt != null ) stmt.close();
			if( conn != null ) conn.close();
		}
	}
}
//
public class Test296 {
	public static void main( String[] args )
	{
		BangDAO dao = new BangDAO();
		try {
			Bang01VO pvo = new Bang01VO();
			pvo.setContent("DAO Content");
			pvo.setAuthor("daoAuthor");
			//
			dao.add( pvo );
			//	SELECT 결과를 List<Bang01VO> 담아서 리턴하는 형태로 동작하는 함수
			List<Bang01VO> ls = dao.findAll();
			for( Bang01VO vo : ls ) {
				System.out.println( vo.getNo() + "," + vo.getContent() );
			}
		}
		catch( Exception e ) {
			System.out.println( e.toString() );
		}
	}
}

DAO Pattern
실전에서는 data 를 읽고/쓰고/수정/삭제 하는 역할을 하는 함수는 DAO 라는 클래스에 모아서 함수 형태로 만들어 준다. ( Data Access Object )

DAO 패턴의 원칙

  1. DAO 안에는 DB 또는 데이터와 관련된 코드로만 채운다
  2. O-R Mapping 개념을 적용한다
    (테이블 : 클래스/ 필드 : 프로퍼티/ 레코드 : 인스턴스 )
  3. 예외처리를 꼼꼼하게 하고, 발생시에 다시 던져주는 형태로 구현 ( 에러가 나도 close() 필수 )
  4. SELECT 문은 find / select / sel 등의 접두어를 붙여서 이름만 보고 그 의미를 알 수 있어야 한다.
    ( 예 : findByPK , findByOrderNo , findByClassName ... )
  5. INSERTadd / insert / ins 등의 접두어
  6. DELETEdel / remove 등의 접두어
    ( 예 : delByPK , removeByName , delByOrderNo ... )
  7. UPDATEmod / update / up 등의 접두어
    ( 예 : modNickNameByPK , modTheTimeByPK ... )

interface BangDAO 
{
	public List<Bang01VO> findAll() throws Exception ;
	public void add( Bang01VO pvo ) throws Exception ;
}
//
class BangDAO_MariaImpl implements BangDAO{
	ublic List<Bang01VO> findAll() throws Exception {}
    public void add( Bang01VO pvo ) throws Exception {}
}

DAO Pattern 의 결정적인 핵심 개념

  • IA a = new A() 개념을 적용한다.
  • 클래스 이름에 사용하는 DB 타입을 명시한다.

BangDAO dao = new BangDAO(); 코드를
BangDAO dao = new BangDAO_MariaImpl(); 로 인스턴스만 바꾼다.


가짜로 하나 인터페이스를 상속하여 돌아가게 만들고 이걸로 일단 BackEnd 를 구현하고 테스트 한 뒤에 DB 담당이 BangDAO_MariaImpl 을 가져오면 인스턴스만 교체하면 된다
( 동시 진행 가능 )


PreparedStatement

String data = null;
String sql = "INSERT INTO temp09_T VALUES ('"+ data +"')" :
stmt.executeUpdate( sql );

INSERT INTO temp09_T VALUES ('null');
'null' 은 NULL 값이 아니라 4글자 문자열이다.

String data = null;
String sql = ( data != null ) ? 
	"INSERT INTO temp09_T VALUES ('"+ data +"')" :
	"INSERT INTO temp09_T VALUES ( NULL )";
stmt.executeUpdate( sql );

String sql = "INSERT INTO temp09_T VALUES ( ? )";
PreparedStatement stmt = conn.prepareStatement( sql );
//		
stmt.setString( 1, null );		
//	stmt.setString( 1, "XY" );
stmt.executeUpdate();
int no = 10101;
String data = "YZ";
//		
String sql = "INSERT INTO temp10_T VALUES ( ?, ? )";
PreparedStatement stmt = conn.prepareStatement( sql );		
stmt.setInt( 1, no );
stmt.setString( 2, data );
stmt.executeUpdate();


Statement 는 conn 에 달려있는 바구니. 이때 바구니에 SQL 문을 아예 새겨넣은 바구니가 PreparedStatement 이다.
해당 SQL 에는 ? 라는 빈 공간을 만들어 넣을 수 있다.

stmt.setString( 1, "XY"); -- ? 로 비워놓은 공간에 데이터를 채워 넣는다. 이 때는 executeUpdate 시에 매개변수가 존재하지 않는다.

다른 이유도 있지만, NULL 에 대한 처리가 PreparedStatement 를 쓰면 훨씬 깔끔하다.


PROCEDURE 프로시저


그냥 SQL 문을 실행시키는 것과 프로시저를 만들어서 실행시키는 것은 속도에서 차이가 난다.

CREATE TABLE temp11_T (
	no INT NULL,
	data VARCHAR(10) NULL
);
INSERT INTO temp11_T VALUES ( 100 , 'HelloWorld' );

프로시저 생성

DELIMITER //
CREATE PROCEDURE proc_apple()
BEGIN
	INSERT INTO temp11_T VALUES ( 100 , 'HelloWorld' );
END;
//
DELIMITER ;

프로시저를 생성만 했을때는 INSERT 동작하지 않는다.

프로시저 호출

CALL proc_apple();

INSERT 동작

만약 프로시저가 존재한다면 삭제

DROP PROCEDURE IF EXISTS proc_apple;  

프로시저 생성

DELIMITER //
CREATE PROCEDURE proc_apple ( IN v_no INT, IN v_data VARCHAR(10) )
BEGIN
	INSERT INTO temp11_T VALUES ( v_no , v_data );
//
DELIMITER ;

매개변수를 사용한 프로시저 호출

CALL proc_apple( 300, 'AppleKiwi' );

프로시저 생성

DELIMITER //
CREATE PROCEDURE proc_apple2( IN v_no INT, IN v_data VARCHAR(10), OUT v_uc INT )
BEGIN
	DECLARE v_count INT;
	SELECT COUNT(*) INTO v_count FROM temp11_T;
	IF v_count < 5 THEN
        INSERT INTO temp11_T VALUES ( v_no, v_data );
        SET v_uc = 1;
    ELSE
        SET v_uc = 0;
    END IF;
END;
//
DELIMITER ;

DECLARE v_count INT; : 변수 선언
SELECT COUNT(*) INTO v_count FROM temp11_T; : SELECT 결과를 이용한 변수 대입

프로시저 호출

CALL proc_apple2(600,'Hello600',@abcd);

OUT 파라미터 확인

SELECT @abcd;

IN/OUT 파라미터


CallableStatement

jdbc 프로시저 호출

String sql = "CALL proc_apple(?,?)";
CallableStatement stmt = conn.prepareCall( sql );
//	proc_apple ( IN v_no INT, IN v_data VARCHAR(10) )
stmt.setInt( 1, 401 );
stmt.setString( 2, "WorldHello" );
stmt.execute();

OUT 파라미터 받아오기

String sql = "CALL proc_apple2(?,?,?)";
CallableStatement stmt = conn.prepareCall( sql );
//	proc_apple2( IN v_no INT, IN v_data VARCHAR(10), OUT v_uc INT )
stmt.setInt( 1, 401 );
stmt.setString( 2, "WorldHello" );
stmt.registerOutParameter( 3, Types.INTEGER );
stmt.execute();
//
int abcd = stmt.getInt( 3 );
System.out.println( abcd );

registerOutParameter 를 사용하여 OUT 파라미터를 받아올 수 있다.

SELECT 결과 받아오기

DELIMITER //
CREATE PROCEDURE proc_banana ()
BEGIN
    SELECT no, data FROM temp11_T;
	-- SELECT * FROM temp10_T;
END;
//
DELIMITER ;

프로시저는 주석을 쓸 때 -- 을 사용한다.

CALL proc_banana();
CallableStatement stmt = conn.prepareCall("CALL proc_banana()");
stmt.execute();
ResultSet rs = stmt.getResultSet();
while( rs.next() ) {
	Integer no = rs.getInt("no");
	String data = rs.getString("data");
	System.out.println( no + "," + data );
}

프로시저에서 SELECT 결과를 발생시키는 경우 getResultSet 으로 ResultSet 을 추출할 수 있다.

1개의 댓글

comment-user-thumbnail
2022년 2월 24일

덕분에 에러 해결했습니다..! 감사드려요~!~!

답글 달기