# JSP 저장영역
ex)
- setApplicationAttribute.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String name = request.getParameter("name");
String value = request.getParameter("value");
if(name != null && value != null){
application.setAttribute(name,value); //전역변수
//application 기본 객체에 속성을 설정. 파라미터로 전달받은 값을 속성 이름과 값으로 사용
}
%>
<!DOCTYPE>
<html>
<head>
<title>application 속성 지정</title>
</head>
<body>
<%
if (name != null && value != null){
%>
application 기본 객체의 속성 설정
<%=name %> = <%=value %>
<%
}else{
%>
application 기본 객체의 속성 설정 안함.
<%
}
%>
</body>
</html>
- viewApplicationAttribute.jsp
<%@ page import="java.util.Enumeration"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE>
<html>
<head>
<title>application 기본 객체 속성보기</title>
</head>
<body>
<%
Enumeration<String> attrEnum = application.getAttributeNames();
//속성의 이름 목록을 구한다.
while(attrEnum.hasMoreElements()){
String name = (String) attrEnum.nextElement();
Object value = application.getAttribute(name);
//이름이 name의 속성의 값을 구한다.
%>
application 속성 : <b><%=name %></b> = <%=value %> <br>
<%
}
%>
</body>
</html>
- request_PageContextSave.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<h2> request와 pageContext 차이 알아보기</h2>
<%
//정보저장하기
request.setAttribute("id", "hong");
pageContext.setAttribute("name","홍길동");
%>
<h2> 저장된 정보 출력해보기 </h2>
request : <%=request.getAttribute("id") %><br/>
pageContext : <%=pageContext.getAttribute("name") %> <br/>
<hr>
<a href="request_PageContextGet.jsp"> 이동하기 </a>
<!-- pageContext.forward("request_PageContextGet.jsp") -->
<jsp:forward page="request_PageContextGet.jsp"/>
</body>
</html>
- request_PageContextGet.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<h2> request와 pageContext 정보 가져오기 </h2>
request : <%=request.getAttribute("id") %><br/>
pageContext : <%=pageContext.getAttribute("name") %> <br/>
<hr>
</body>
</html>
# Connection Pool(커넥션 풀)
데이터베이스와 연결된 Connection 객체를 미리 생성하여 풀(Pool) 속에 저장해두고
필요할 때마다 이 풀에 접근하여 Connection 객체를 사용하고, 작업이 끝나면 다시 반환하는 것
- Connection Pool의 필요성 및 장점
사용자가 웹사이트에 요청을 할 때마다 매번 Connection 객체를 생성하여 연결 시
메모리에 너무 많은 객체 생성된다는 비효율성 및 문제점이 있다.
커넥션 풀을 사용하는 경우
① Pool 속에 미리 Connection이 생성 되어 있기 때문에
Connection 생성 시 소요되는 연결 시간이 소비되지 않는다.
② 현재 다른 사용자가 사용하지 않는 Connection을 재사용할 수 있기 때문에
사용자가 접속할 때마다 계속 새로운 Connection을 생성할 필요가 없다.
③ 한 번에 생성될 수 있는 Connection 수를 제어하기 때문에
동시 접속자 수가 몰려도 어플리케이션이 쉽게 다운되지 않는다.
④ 커넥션을 생성하고 닫는 시간을 소모하지 않아 어플리케이션의 실행 속도가 빨라진다.
- Connection Pool의 속성
속성 | 설명 |
maxActive | Connection Pool이 제공할 최대 Connection 갯수 |
whenExhaustedAction | Connection Pool에서 가져올 수 있는 Connection이 없을 때 어떻게 동작할 것인지 지정함 0 : 에러 발생 1 : maxWait 속성에서 지정한 시간만큼 Connection을 구할 때까지 기다림 2 : 일시적으로 Connection을 생성해서 사용 |
maxWait | whenExhaustedAction 속성 값이 1일 때 사용되는 대기 시간 단위 : 1/1000초 0보다 작을 경우 무한 대기함 |
maxIdle | 사용되지 않고 Pool에 저장될 수 있는 최대 Connection 갯수 음수일 경우 제한 없음 |
minIdle | 사용되지 않고 Pool에 저장될 수 있는 최소 Connection 갯수 |
testOnBorrow | true일 경우 Connection Pool에서 Connection을 가져올 때 Connection이 유효한지 여부 검사 |
testOnReturn | true일 경우 Connection Pool에서 Connection을 반환할 때 Connection이 유효한지 여부 검사 |
timeBetweenEvctionRunsMillis | 사용되지 않는 Connection을 추출하는 Thread의 실행 주기 지정 양수가 아닌 경우 실행되지 않음 단위 : 1/1000초 |
numTestsPerEvictionRun | 사용되지 않는 Connection을 몇 개 검사할 지 지정 |
minEvictableIdleTimeMillis | 사용되지 않는 Connection을 추출할 때 이 속성에서 지정한 시간 이상 비활성화 상태인 Connection만 추출 양수가 아닌 경우 비활성화된 시간으로는 Pool에서 제거되지 않음 단위 : 1/1000초 |
testWhileIdle | true일 경우 비활성화 Connection을 추출할 때 Connection이 유효한지 여부 검사하여 유효하지 않은 Connection은 Pool에서 제거함 |
+
- JNDI(Java Naming and Directory Interface)
명디렉터리 서비스에서 제공하는 데이터 및 객체를 발견하고 참고하기 위한 자바 API
필요한 자원을 key/value 쌍으로 저장한 후 필요할 때 키를 이용해 값을 얻는 방법으로,
미리 접근할 자원에 키를 지정한 후 어플리케이션이 실행 중일 때 이 키를 이용해 자원에 접근한 후 작업하는 것
① Naming & Directory 서비스 : 분산환경에서 자원을 연결해주는 기능
Naming & Directory 서비스는 실제 어떤 자원을 가지고 서비스 한다는 의미가 아닌
어떤 서버나 애플리케이션에서 분산환경에 서비스하고자 하는 자원을
이 Naming & Directory 서버에 이름값과 실제 자원을 연결하여 등록하면,
해당 자원을 이용하고자 하는 다른 애플리케이션에서 Naming & Directory 서버에 접근하여
이름값 만을 가지고 자원을 연결하여 이용할 수 있게 하는 개념이다.
네이밍 서비스의 대표적인 예로 DNS서버가 이런 기능을 한다.
브라우저창에 URL을 입력하면 브라우저는 DNS서버를 통해 도메인에 해당하는 IP주소를 얻는다.
그리고 IP 주소를 통해 실제 인터넷 서버에 접속한다.
결국 DNS 서버는 실제 인터넷 서비스를 수행해주는 곳이 아니며,
단지 도메인과 IP 주소만을 연결해주는 기능을 하는 것이다.
Connection Pool 관리 목적으로 사용되는 객체
서버에서 관리하는 리소스인 커넥션 풀을 사용할 수 있게 한다.
어플리케이션에서는 이 객체를 통해 Connection을 얻어오고 반납하는 등의 작업을 수행할 수 있다.
서버가 시작할 때 커넥션 풀이 서버에 준비되어 있어야 합니다.
DB 프로그래밍을 할 때 커넥션 풀에서 Connection 객체를 얻어낼 수 있기 때문이다.
- Pooling 기법
디자인 패턴의 일종
한 번 생성될 때 자원의 소모가 크며, 계속해서 생성, 소멸시킬 필요가 없다고 생각되는 객체를
미리 여러 개 만들어 놓은 뒤, 그 것을 계속 사용하는 기법
흔히 Servlet과 같은 웹프로그래밍에서는, DB Connection Pooling을 대부분 사용한다.
DB와의 통신이 빈번하게 이뤄지는 웹 어플리케이션의 경우,
DB Connection 생성에서 자원의 소모가 가장 심하게 발생한다.
수백 명의 클라이언트가 동시에 접속해서 수십번의 요청을 날리는 경우
그 횟수만큼 Connection 객체를 생성/소멸시키면, 서버의 부하를 초래할 수 있다.
따라서 미리 연결을 시켜놓은 몇 개의 Connection 객체를 생성해놓고,
이들을 별도의 공간에 대기시키는데 이를 Factory라고 한다.
위와 같이 미리 연결되어 있는 일정 수의 Connection 객체를 돌아가면서 사용하는 식으로 DB 연결이 이뤄진다.
정확히는 계속 DB는 연결되어있고 돌아가면서 그 연결을 통해 쿼리를 날리는 것이다.
보통 Servlet Container들에서는 JNDI와 DataSource를 이용하여 DB Connection Pooling을 쉽게 구현할 수 있다.
https://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html
ex)
- list.jsp
<%@page import="java.util.ArrayList"%>
<%@page import="com.superman.www.*"%>
<%@ page import="java.sql.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="description" content="HTML Study">
<meta name="keywords" content="HTML,CSS,XML,JavaScript">
<meta name="author" content="Bruce">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시판 목록</title>
</head>
<body>
<h3>목록</h3>
<%
BoardDAO dao = new BoardDAO();
ArrayList<BoardDTO> list = dao.selectBoard();
for(int i=0;i<list.size();i++)
{
BoardDTO dto = list.get(i);
out.print("번호 " + dto.getNo()+"<br>");
out.print("제목 " + dto.getTitle()+"<br>");
out.print("작성자 " + dto.getName()+"<br>");
out.print("작성일 " + dto.getWtime()+"<br>");
out.print("조회수 " + dto.getRcnt()+"<br><br>");
}
%>
<a href="write.jsp">글쓰기</a>
</body>
</html>
- BoardDAO.java
package com.superman.www;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class BoardDAO {
// private String driver = "com.mysql.cj.jdbc.Driver";
// private String url = "jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC";
// private String user = "root";
// private String password = "1234";
private DataSource dataSource;
public BoardDAO() {
// try {
// Class.forName(driver);
// } catch(ClassNotFoundException e) {
// System.out.println("드라이버 로드 실패");
// }
try {
Context context = new InitialContext();
dataSource = (DataSource)context.lookup("java:comp/env/jdbc/testdb");
} catch (Exception e) {
e.printStackTrace();
}
}
public ArrayList<BoardDTO> selectBoard()
{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "SELECT no, title, name, wtime, rcnt FROM board ORDER BY no DESC";
ArrayList<BoardDTO> list = new ArrayList<BoardDTO>();
try {
// conn = DriverManager.getConnection(url, user, password);
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while(rs.next())
{
BoardDTO dto = new BoardDTO();
dto.setNo(rs.getInt("no"));
dto.setTitle(rs.getString("title"));
dto.setName(rs.getString("name"));
dto.setWtime(rs.getString("wtime"));
dto.setRcnt(rs.getInt("rcnt"));
list.add(dto);
}
} catch(SQLException e) {
e.printStackTrace();
} finally {
try {
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(conn != null) conn.close();
} catch(SQLException e) {
e.printStackTrace();
}
}
return list;
}
}
커넥션 풀에 접근하려면 JNDI 서비스를 사용해야 한다.
JNDI는 서버에서 관리하고 있는 리소스에 대한 정보를 알고 있고
특정 리소스를 찾아서 사용할 수 있도록 객체를 반환해주는 역할을 한다.
JNDI 서버역할을 하는 객체를 생성한다.
리소스가 로컬에 있을 때는 단순히 InitialContext 객체만 생성하면 된다.
// Tip : context.lookup( )
리소스를 찾은 후 리소스를 사용할 수 있도록 객체를 반환해주는 메소드
lookup( ) 메소드의 인자값으로는 찾으려는 리소스의 등록된 이름을 지정한다.
우리가 찾으려는 리소스의 이름은 "jdbc/testdb"이고
WAS인 톰캣에서 리소스를 관리하는 가상의 디렉터리는 "java:comp/env"입니다.
그래서 lookup( ) 메소드의 최종인자 값은 "java:comp/env/jdbc/testdb"이 됩니다.
lookup( ) 메소드가 반환하는 객체의 타입은 Object 이기 때문에 원래 리소스 타입으로 변환해줍니다.
앞에서 server.xml 파일에 커넥션 풀을 설정할 때 리소스의 타입을 DataSource로 등록했습니다.
즉, 원래 DataSource로 타입을 변환합니다.
- BoardDTO.java
package com.superman.www;
public class BoardDTO {
private int no;
private String title;
private String name;
private String password;
private String email;
private String contents;
private String wtime;
private int rcnt;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContents() {
return contents;
}
public void setContents(String contents) {
this.contents = contents;
}
public String getWtime() {
return wtime;
}
public void setWtime(String wtime) {
this.wtime = wtime;
}
public int getRcnt() {
return rcnt;
}
public void setRcnt(int rcnt) {
this.rcnt = rcnt;
}
}
'Web > JSP' 카테고리의 다른 글
[실습문제] Day81 - MVC Model2 문제 및 해답 (0) | 2020.10.22 |
---|---|
[필기정리]Day79-2 - MVC(Model, View, Controller) (0) | 2020.10.22 |
[필기정리]Day78 - ActionTag, JavaBeans, DAO, DTO, VO 등 (0) | 2020.10.20 |
[개인실습] JSP로 회원형 게시판 만들기 (0) | 2020.10.19 |
[필기정리]Day77 - include(), forward() 등 (0) | 2020.10.17 |