(책) 자바 웹을 다루는 기술

Chap 7 키워드 정리

EunaSon 2023. 8. 17. 11:57

7장. 서블릿 비즈니스 로직 처리


7.1 서블릿의 비즈니스 로직 처리 방법

- 서블릿 비즈니스 처리 작업

: 서블릿이 클라이언트로부터 요청을 받으면 그 요청에 대해 작업을 수행하는 것

웹 프로그램에서 대부분의 비즈니스 처리 작업은 db 연동 관련 작업이지만 그 외에 다른 서버와 연동해서 데이터를 얻는 작업도 수행함.

- 비즈니스 처리 과정

1. (클라이언트->서블릿) 서블릿- 클라이언트로부터 요청받음

2. (서블릿<->DB)서블릿- db 연동 등의 비즈니스 로직을 처리

3. (클라이언트<-서블릿) 서블릿-처리결과를 클라이언트에게 돌려줌

 

7.2 서블릿의 데이터베이스 연동하기

226p 그림7-3 서블릿의 데이터베이스 연동과정 

228p 데이터베이스 연동

sql developer 실행 > 새 접속 > 데이터베이스 연동정보 입력 > 워크시트에 테이블 생성 및 데이터 입력 > select문으로 조회해서 확인

> 이클립스에서 입력한 테이블 조회 : ojdbc6.jar(오라클 db와 연동에 필요한 드라이버)를 프로젝트의 /WebContent/WEB-INF/lib에 복사해서 붙여넣음

> 새 패키지(sec01.ex01)를 만들고, 회원 조회와 관련된 자바 클래스 파일인 MemberDAO, MemberServlet, MemberVO 클래스를 각각 생성함

 

MemberServlet 클래스 - DAO객체 생성해서 회원정보 조회, VO객체 가져와서 html 태그 문자열로 만들어줌(for문 이용)

MemberDAO 클래스 - 회원정보조회 SQL문을 실행함, 조회한 레코드들의 컬럼값을 VO 객체의 속성에 설정 후 ArrayList에 저장, 호출한 곳으로 반환함.

MemberVO 클래스 - 값을 전달하는데에 사용됨(VO = Value Object), 테이블의 컬럼과 동일한 자료형, 이름으로 속성을 선언 후 getter, setter를 각각 생성함

 

코드 7-3 DAO클래스 중

- Connection(java.sql.Connection)은 DB 접속에 필요한 클래스

- DriverManager.getConnection 메서드 사용시 url, user, password가 필요함

url은 db 연결시 찾는 주소를 적음("jdbc:oracle:thin:@localhost:1521:XE")

user는 접속할 아이디, password는 접속할 아이디에 설정해놓은 비밀번호

- connection 시 오류 발생하면 (https://aricode.tistory.com/8) 하단 참고

- Statement(java.sql.Statement)는 Connection으로 연결한 객체에 쿼리 작업을 실행하기 위한 객체

 Statement 객체 생성하기 위해서는 Connection이 먼저 연결되어야함

 'Statement stmt = con.createStatement();' 문을 통해 Statement 객체 생성

- 조회문(select) 처리시 executeQuery(String sql) 메서드 사용, 조회문 외(create, insert, delete, update, drop) 사용시 executeUpdate(String sql) 메서드 사용함

조회문을 처리하여 조회된 목록들은 ResultSet 객체에 담겨 반환됨

- ResultSet은 조회된 목록들이 저장된 객체라고 보면됨

 while 반복문을 통해 목록들을 가져올 수 있음( 'while (rs.next()' )

 최초의 커서는 1행 이전에 위치하고, next()는 다음 행이 있으면 true를 반환 후 커서를 다음행으로 넘김 

 선택된 행에서 getString(), getInt() 등 get타입("컬럼명") 메서드를 이용해 행에서 해당 컬럼의 값을 기져옴(컬럼명 대신 컬럼숫자 써서 값 가져올 수도 있음)

 -VO객체 만들어서 각 속성에 getString("속성(컬럼)명") 메서드로 얻어온 값 저장(set속성명() 메서드 이용)

- ArrayList에 설정한 VO 객체 저장, 모든 VO 저장 후 list return함

 

Statement 인터페이스를 사용하여 db 연동시, 연동할 때마다 dbms에서 다시 sql문을 컴파일해야 하므로 속도가 느리다는 단점 => PrepareStatement 인터페이스 사용 : sql문을 미리 컴파일해서 재사용함

237p 코드 7-5

-PrepareStatement는 Statement와 다르게 execute를 따로 해야함 (???)

-여기서도 executeQuery, executeUpdate 메서드를 사용함

-prepareStatement() 메서드에 sql문을 전달하여 PrepareStatement 객체를 생성

-> 해당 객체에서 executeQuery() 메서드를 호출해여 미리 설정한 sql문을 실행함

ex)

pstmt = con.prepareStatement(query); // query에는 String으로 된 sql문이 담겨있다

ResultSet rs = pstmt.executeQuery(); // 담겨있는 sql문이 실행된다

* 출처

https://aricode.tistory.com/8

https://aricode.tistory.com/9

https://aricode.tistory.com/10

https://aricode.tistory.com/101

https://aricode.tistory.com/12

 

7.3 DataSource 이용해 데이터베이스 연동하기

239p 필요할 때마다 db에 연결하여 작업시 db연결에 시간이 많이 걸리므로 비효율적

=> 커넥션풀 사용 : 웹 애플리케이션이 실행됨과 동시에 연동할 db의 연결을 미리 설정해둠. 미리 db와 연결시킨 상태를 유지하는 기술을 커넥션풀이라 부름

-애플리케이션 실행 시 미리 ConnectionPool 객체를 생성한 후 db와 연결을 맺음

-애플리케이션은 db연동 작업 발생시 이 ConnectionPool 객체를 이용해서 작업함

 

240p 커넥션풀 동작 과정

톰캣 컨테이너 실행 후 응용프로그램 실행, 커넥션풀 객체 생성 > 생성된 커넥션풀 객체와 dbms와 연결됨 > 응용프로그램에서 db연동작업 필요시 커넥션풀에서 제공하는 메서드를 호출하여 연동함

톰캣 컨테이너는 자체적으로 커넥션풀 기능을 제공함, 톰캣이 만들어놓은 커넥션풀에 접근할때 JNDI를 이용함

 

JNDI(Java and Directory Interface)

: 필요한 자원을 키/값 쌍으로 저장 후 필요할 때 키를 이용해 값을 얻는 방법. 즉, 접근할 자원에 미리 키를 지정한 후 애플리케이션이 실행중일때 키를 이용해 자원에 접근해서 작업하는것. 톰캣 컨테이너가 커넥션풀 객체 생성하면 이 객체에 대한 JNDI 이름(key)을 미리 설정해놓음. 그러면 웹 애플리케이션에서 데이터베이스와 연동 작업을 할 때 이 jndi 이름으로 접근하여 작업함

 

242p 톰캣 connectionpool 설정 과정(웹 애ㅡㄹ리케이션에서 톰캣이 제공하는 커넥션풀 객체를 이용해 db와 연동하는 과정)  ... jdbc 드라이버, connectionpool 관련 jar 파일 -  WEB-INF/lib 에 들어있음, 톰캣 서버 설정파일(context.xml)  - Servers/Tomcat v9.0 ~~~에 들어있음

context.xml 보면 <Resource> 태그로 톰캣 실행시 연결할 db 설정한 것 알 수 있음('name="jdbc/oracle"')


-Connection

유저가 보낸 요청을 처리하는 과정에서 서버(WAS)가 db에 접근하기 위해서는 Connection 타입의 객체가 필요함

-DriverManager

JDBC에서는 DriverManager를 사용하면 Connection을 다음과 같이 가져올 수 있음

'Connection con = DriverManager.getConnection(url, user, password);'

-이렇게 db 접근시마다 Connection을 생성하는 것은 비효율적

: db와 연결할때 TCP 통신을 함. TCP 통신은 커넥션의 안정성과 신뢰성 보장을 위해 연결시 3 Way-handshake, 연결 종료시 4 Way-handshake 과정을 거치는데 이 과정에서 통신 비용이 많이 소모되므로 커넥션을 계속해서 생성하는데에 비용이 많이 드는 것임 => 커넥션풀이 필요함

-Connection Pool : Connection을 미리 만들어 Pool에 저장하고, 필요할 때마다 커넥션을 꺼내서 사용함. 커넥션을 생성하는 데에 드는 비용을 줄일 수 있음

-DataSource : db나 파일 같은 물리적 데이터소스에 연결할 때 사용하는 인터페이스. DataSource를 사용하면 ConnectionPool을 활용할 수 있음. DriverManager가 아닌 DataSource를 사용하는 것도 이 때문임. 뿐만 아니라 애플리케이션 코드를 직접 수정하지 않고 properties로 db 연결을 변경할 수도 있으며 분산 트랜잭션도 사용할 수 있음

 

JdbcDataSource dataSource = new JdbcDataSource();

dataSource.setURL(H2_URL);

// Connection을 새로 생성하지 않고 이미 만들어진 Connection을 get으로 가져옴

Connction con = dataSource.getConnection(user, password);

 

-HikariCP : 스프링부터2.0부터는 hikariCP를 기본 DataSource로 채택하고 있음. 빠르고 간편하며 오버헤드가 zero임

-HikariCP Property

maximumPoolSize : 커넥션풀이 가질수 있는 최대 커넥션 개수. 디폴트:10개

connectionTimeout : 클라이언트가 pool에서 connection을 기다리는 최대시간(ms). 초과되면 SQLException 발생함.

maxLifeTime : 풀에 존재하는 커넥션의 최대 lifetime. 사용중인 커넥션은 절대 제거되지 않으며 커넥션이 닫히고 나서만 제거됨. 설정하는 것을 권장함. db나 인프라의 커넥션타임 limit보다 몇 초 더 짦아야 의미가 있음. 0이면 설정이 적용되지 않음(=lifetime이 무한)

keepaliveTime : 커넥션이 유효한지 확인하는 주기 설정(ms). 유효하지 않으면 커넥션을 풀에서 제거함. 이 값은 반드시 maxLifeTime보다 작아야 함. 길면 이미 커넥션에서 제거된 후 검증하는 것이므로 설정이 무의미함.

* 출처

https://colour-my-memories-blue.tistory.com/15

 

* 내 프로젝트에 build path의 libraries 보면 hikariCP-2.7.8.jar 추가되어있음


7.4 DataSource 이용해 회원 정보 등록하기

248p~252p

MemberVO 복붙,

회원가입화면(MemberForm.html) 만들어주고,

MemberServlet 에서는 넘어온 command에 따라

 -회원가입(addMember) -> form에서 넘어온 값들 변수로 저장 후 VO 객체 생성해서 속성에 저장(setter 이용), DAO의  addMember() 메서드 이용해 sql문으로 테이블에 새 회원정보 추가

 - 회원탈퇴(delMember) -> 넘어온 id 값 변수로 저장 후 DAO의 delMember(id) 메서드 통해 테이블해서 해당 id 행 삭제,

 화면에는 DAO의 listMember() 통해 전체 회원정보 받아와서 테이블로 표시되도록 html 태그 작성, 테이블 제일 우측 컬럼에는 '삭제' 링크가 뜨도록 하는데, a 태그를 이용해 해당 서블릿에 command로 delMember, id로 해당 행의 id값을 넘겨줌

MemberDAO에는 addMember() 메서드를 추가함

 - DataSource 이용해 db와 연결하고, 인자로 받아온 VO객체의 속성값들을 변수에 저장 후 쿼리문 String으로 만들어서(insert문임) PrepareStatement 이용해 insert문의 각 ?에 해당되는 값으로 세팅함(setter), executeUpdate()로 쿼리문 실행, pstmt.close()

 

251p PrepareStatement에서 insert문 사용하는 방법

insert문에서 id, pwd, name, age에 ? 사용함

각 ?에 대응하는 값을 지정하기 위해 PrepareStatement의 setter 사용함

setter() 메서드의 첫번째 인자는 ?의 순서를 지정함

?는 1부터 시작하고, insert, delete, update문은 executeUpdate() 메서드를 호출함

 

7.5 회원 정보 삭제하기

회원정보 삭제 기능 구현하기 위해 MemberServlet 수정

- command값이 delMember인 경우 id값 가져와 DAO 통해(dao.delMember(id)) sql문으로 회원정보 삭제함

- 테이블의 제일 우측 컬럼에 a태그 이용해서 해당 서블릿(/pro07/member3)에 command와 id 전달함

 

MemberDAO도 수정

- delMember(String id) 추가 : connection 가져오고, delete문 String으로 작성, pstmt.setString(물음표순서, 값)으로 delete문의 ?에 값 설정, pstmt.executeUpdate()로 쿼리문 날림, close()

 

CRUD(Create, Read, Update, Delete) 중update는 뒤에서 jsp 배운 후 적용해 볼것.

 

* 255p 이클립스 디버깅 기능 사용하기