-
ConnectionPool,ViewResolverJAVA 2021. 7. 25. 13:09
Connection Pool
JavaApp ---> Connection Pool ( 여러 Connection ) ---> DBMS.
사용자의 요청에 따라 Connection 을 생성하다 보면 많은 수의 연결이 발생했을 때 서버에 과부하가 걸리게 된다 . 이러한 상황을 방지하기 위해 미리 일정수의 Connection 을 만들어 pool 에 담아 뒀다가 사용자의 요청이 발생하면 연결을 해주고 연결 종료 시 pool 에 다시 반 환하여 보관하는 것이다 .
DB Connection Pool 매니저가 일정의 Connection 을 연결하고 있다가 요청이 들어오면 Connection 을 할당해주고 없으면 기다리게 한다. 클라이언트는 Connection 을 다 쓰면 다시 반납하는 구조로 이루어진다.
따라서 속도나 performance 부분 이 향상된다 .
보통의 경우 DB 에 연결을 하고 결과를 가져온 후에 close 시켜버린다.
DB 에 연결하는 과정은 시간이 많이 소요되는 Cost 가 비싼 연산이며 performance 도 많이 떨어진다 .
이러한 문제점 을 해결하기 위해 DB Connection pool 을 사용한다
한번 맺은 DB Connection 을 바로 cl ose 시키지 않고 pool 에 저장한 뒤에 다음 번에 동일한 Connection 을 요청하면 바로 pool 에서 꺼내 제공을 함으로써 빠른 DB Connection Time 을 보장해 준다 .
어제 만든 board_member 에 밑의 내역들 넣기 ( ws2CP 워크스페이스)
수정사항 3개
1. Maven 프로젝트의 pom.xml 에 코드 넣기 - API 다운을 위한 dependencies 코드 하위 1) jsp에서 tomcat 으로 돌아갈 servlet API
2) JAVA-DB연결할 jdbc API
3) db의 Connection 과 Connection Pool 을 가져오는 API 3개
(이 Connection Pool 과 Connection으로 더 빠르고 많이 Connection 가능해짐)만약 API 들이 저 코드를 넣어도 다운되지 않는다면
프로젝트 -> 오른쪽마우스 -> Build Project 로 다시 구동 시켜보기.>> pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.stone</groupId> <artifactId>cp</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.24</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> </dependencies> </project>
2. Connection 정보를 Tomcat 이 읽게하기 (Tomcat이 run 할 때 바로 읽는다) 1) 적용할 프로젝트를 Tomcat 서버에 넣기(평소하던대로 Server설정) 2) 그러면 생성되는 Servers 프로젝트에 context.xml 에다가 아래 Resource 태그 내용을 삽입 >> context.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --><!-- The contents of this file will be loaded for each web application --><Context> <!-- Default set of monitored resources. If one of these changes, the --> <!-- web application will be reloaded. --> <WatchedResource>WEB-INF/web.xml</WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> <Resource name="jdbc/mycp" auth="Container" type="javax.sql.DataSource" maxActive="10" maxIdle="3" maxWait="10000" username="root" password="1234" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/board4?useUnicode=true" closeMethod="close" /> </Context>
// jdbc/mycp 라는 이름으로 Container 가 javax.sql.DataSource 클래스를 가져온다. // maxActive(최대connection갯수) maxWait(최대 기다리는 시간, 넘어가면 오류,,다시?) // closeMethod(우리가 close하는거와 다르며 Connection을 정리하는 것 뿐?)
Connection DB연결관리자 = ConnectionUtil.getConnection(); // 이렇게 한줄에 끝.
>> ConnectionUtil.java
package com_stone.cp.util; import java.sql.Connection; import javax.naming.InitialContext; import javax.sql.DataSource; class BasicDataSource{ DataSource ds = null; // 초기화시 ds 에 db의 Connection 정보를 넣음 BasicDataSource(){ try { InitialContext initialContext = new InitialContext(); ds = (DataSource)initialContext.lookup("java:comp/env/jdbc/mycp"); } catch (Exception e) { e.printStackTrace(); } } } public class ConnectionUtil { // BasicDataSource 생성자로 DataSource 인 ds 에 Connection 정보가 들어갔고 // 이를 바로 가지고옴 private static DataSource ds = new BasicDataSource().ds; // 위에서 가져온 DataSource 로 getConnection() 함. public static Connection getConnection() { // return ds.getConnection(); 하면 예외 처리해야하는데 // try-catch 구문안에 넣으면 return 구문이 밖에 없다고 난리친다... // 그래서 Connection 받는 예외를 안에 넣고 밖에 Connection 을 따로 지정 Connection c = null; try { c = ds.getConnection(); } catch (Exception e) { e.printStackTrace(); } return c; } }
// initialcontext.lookup("java:comp/env 까지 comcat을 의미하는 정해진 문장 // jdbc/mycp 는 위의 context의 name으로, 저 type에 써놓은 객체를 가져온다는 의미이다. // 이 type 인 sql의 DataSource(밑에 연결을 다 해놓은 문구들//평소쓰던 username, password, driverClassName, url) 등이 // 다 들어있는 객체로 getConnection 하면 Connection울 얻을 수 있다.
>> BoardDAO.java (ConnectionUtil 적용)
public class BoardDAO implements IBoardDAO { //메서드에서 회원찾을 때 사용할 "메서드용클래스"를 멤버변수로 설정 private IMemberDAO memberDAO = new MemberDAO(); //게시물 저장하기. public void save(Board board) { Connection DB연결관리자 = ConnectionUtil.getConnection(); PreparedStatement ps = null; try { ps = DB연결관리자.prepareStatement("insert into board(title,contents,writer) values(?,?,?)"); ps.setString(1, board.getTitle()); ps.setString(2, board.getContents()); ps.setInt(3, board.getWriter().getNo()); ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } finally { try { if(!ps.isClosed()) {ps.close(); System.out.println("statement 연결종료");} if(!DB연결관리자.isClosed()) {DB연결관리자.close(); System.out.println("connection 연결종료");} }catch (SQLException e) { e.printStackTrace(); } } } // 페이지별로 게시물 목록 뽑기 public List<Board> selectByPage(int page/*페이지*/, int sizePerPage/*페이지당 게시물수*/, RefInteger totalSize/*총페이지수*/) { int 시작일련번호 = (page - 1) * sizePerPage; // zero-base: 시작을 0으로 본다. ArrayList<Board> array게시물 = new ArrayList<Board>(); try { Connection DB연결관리자 = ConnectionUtil.getConnection(); Statement 명령전달자 = DB연결관리자.createStatement(); // 2-1. 총 게시물수 구하기 String 총개시물수SQL = "select count(*) as 갯수 from board"; ResultSet 수집된갯수표관리자 = 명령전달자.executeQuery(총개시물수SQL); 수집된갯수표관리자.next(); totalSize.value = 수집된갯수표관리자.getInt("갯수"); 수집된갯수표관리자.close(); // 2-2. 페이지당 게시물들 가져오기 String 수집SQL = String.format("select no,title,wdate,views,writer from board order by wdate desc limit %d, %d", 시작일련번호, sizePerPage); ResultSet 수집된표관리자 = 명령전달자.executeQuery(수집SQL); while (수집된표관리자.next()) { int 게시물번호 = 수집된표관리자.getInt("no"); String 제목 = 수집된표관리자.getString("title"); java.sql.Date 작성일 = 수집된표관리자.getDate("wdate"); int 조회수 = 수집된표관리자.getInt("views"); int 작성회원번호 = 수집된표관리자.getInt("writer"); Member member = memberDAO.findByNo(작성회원번호); Board 게시물1 = new Board(); 게시물1.setNo(게시물번호); 게시물1.setTitle(제목); 게시물1.setWdate(작성일); 게시물1.setViews(조회수); 게시물1.setWriter(member); array게시물.add(게시물1); } 수집된표관리자.close(); 명령전달자.close(); DB연결관리자.close(); } catch (Exception e) { e.printStackTrace(); } return array게시물; } // 게시물의 번호로 게시물의 상세내역 보기(+ 조회수 증가여부) public Board findByNo(int no, boolean addView) { Board 찾은게시물 = null; try { Connection DB연결관리자 = ConnectionUtil.getConnection(); Statement 명령전달자 = DB연결관리자.createStatement(); // 조회수증가 if(addView) { 명령전달자.executeUpdate(String.format("update board set views = views + 1 where no = %d", no)); } // 선택한 게시물 가져오기 String 수집SQL = String.format("select * from board where no = %d",no); ResultSet 수집된표관리자 = 명령전달자.executeQuery(수집SQL); if(수집된표관리자.next()) { String 제목 = 수집된표관리자.getString("title"); String 내용 = 수집된표관리자.getString("contents"); java.sql.Date 작성일 = 수집된표관리자.getDate("wdate"); int 조회수 = 수집된표관리자.getInt("views"); // 게시물의 작성자번호를 통해 member을 찾아달라고 MemberDAO에게 부탁. (작성자번호는 게시판번호(no) 이 아님!!) int 작성자번호 = 수집된표관리자.getInt("writer"); Member member = memberDAO.findByNo(작성자번호); 찾은게시물 = new Board(); 찾은게시물.setNo(no); 찾은게시물.setTitle(제목); 찾은게시물.setContents(내용); 찾은게시물.setWdate(작성일); 찾은게시물.setViews(조회수); 찾은게시물.setWriter(member); } 수집된표관리자.close(); 명령전달자.close(); DB연결관리자.close(); } catch (Exception e) { e.printStackTrace(); } return 찾은게시물; } // 게시물번호로 게시물 지우기 public void delete(int no) { } }
DB - Connection 변화
저번방법 이번방법 Driver Class.forName("com.mysql.cj.jdbc.Driver") (xmldriverClassName="com.mysql.cj.jdbc.Driver" getConnection DriverManager
.getConnection("jdbc:mysql://localhost:3306/sys")InitialContext initialContext = new InitialContext();
DataSource ds = (DataSource)initialcontext
.lookup("java/comp/env/jdbc/mycp");
ds.getConnection();close 아예 반납 반납이 아니고 Connection Pool 에서 대기
ViewResolver
control 에서 업무작업 후 view 로 request 의 forward 를 이용하여 넘어갈 때,
Spring 에서 일일히 "뷰이름.jsp" 쓰지 않는다.
그래서 JSP -java class 로 간단히 맛보기.
>> ViewResolver.java
public class ViewResolver { private static String path = "WEB-INF/views/"; public static String getJspViewName(String viewName) { return path + viewName + ".jsp"; } }
UML
Class 의 Editor에서 stereotype:
control = "요청받아 업무하는JSP"
view 는 "control 마치고 나오는 창"
(JSP 도 Class 로 만들어서 stereotype 으로 설계하면 된다.)control 에서 forward 하여 view 로 넘길 테니 dependency 관계로 +forward 를 키워드로 넣는다.
(필요할 때만 요청하기 때문에 dependency)control 에서 업무할 때 필요한 java class를 dependency 관계로 연결 메모장: 요청 & 업무명 => control 창의 이름과 다를 수 있다! 'JAVA' 카테고리의 다른 글
MVC모델2, JSTL (0) 2021.07.25 MVC모델이란 (0) 2021.07.25 UML만들기-DesignModel&class관계,maven프로젝트 (0) 2021.07.25 게시물상세(model2.ver) (0) 2021.07.25 RequestDispatcher,forward(),게시물등록(model2.ver) (0) 2021.07.25