※ Connection pool
커넥션 풀 객체를 생성하고 관리하는 방법에는
커넥션 풀에서 커넥션 객체 생성하고 관리하는 것이 있다.
- 커넥션 풀에 미리 여분의 커넥션을 만들어 놓고, 사용자의 요청이 있으면
메모리에 이미 만들어져 있는 커넥션을 부여하고, 사용된 커넥션 객체는 다시 커넥션 풀로 회수됨
- 반드시 컨테이너에 1개만 만들어지도록 패턴을 만들어야 함
※트랜잭션
- 논리적인 작업단위
- 여러가지 DML 작업들을 (데이터를 입력하는 DML) 하나의 단위로 묶어둔 것
- 은행에서 계좌 입출금과 같은개념
ex ) A통장에서 출금한 돈이 B통장에 정확히 입금이 확인되면 그때 거래를 성사시킴
- 해당 트랜잭션 내에 있는 모든 DML이 성공해야 해당 트랜잭션이 성공하는 것이고
만약 1개의 DML이라도 실패하면 전체가 실패하게 됨
- 트랜잭션의 시작은 DML이고, 완료하려면 TCL, DCL, DDL이 입력 되면 됨
- Savepoint를 설정하여, 설정한 savepoint까지 트랜잭션 관리 가능
▶ jsp에서 제공하는 트랜잭션 처리에 대한 메서드 : commit() rollback()
- JDBC API의 Connection 객체는 commit(), rollback() 메서드를 제공
COMMIT [WORK] [TO SAVEPOINT savepoint_name];
ROLLBACK [WORK] [TO SAVEPOINT savepoint_name];
= > COMMIT, ROLLBACK 모두 TRANSACTION 처리를 위해 존재
jsp는 기본적으로 Autocommit 으로 쿼리문이 Autocommit에 의해 자동으로 수행된다.
하지만 트랜잭션을 처리할 때는 오토커밋에 의해 자동으로 commit을 사용하면 안된다.
jsp 의 오토커밋이 자동으로 작동되지 못하게 하려면 setAutoCommit(false) 로 지정해야한다 !
※ 게시판만들기
▶ 답변형 게시판 만들기
하나의 글에 대한 답변과 또 연관된 다른 답변들을 하나의 그룹으로 묶어주어야 한다.
▷ 컬럼
[1] groupNo : 하나의 글에 연관된 모든 글들을 하나의 그룹으로 묶어주는 컬럼
- ex ) 16번 글에대한 답글인 19,17,18 은 모두 하나의 groupNo 를 갖는다
[2] step : 글이 몇 번째 단계의 답변인지를 나타내는 컬럼
[3] sortNo : 글의 정렬 순서를 지정해주는 컬럼
SortNo 은 자신이 들어가야 할 위치(SortNo)보다 높은 SortNo 의 글이 이미 존재할 경우,
SortNo 가 높은 글들은 모두 +1을 해주어야 함
Update reboard set SortNo = SortNo + 1
Where GroupNo = 120 and SortNo > 2
▶ 페이징처리
<%
int currentPage=1; //현재 페이지
//페이지 링크를 눌렀을때 처리
if(request.getParameter("currentPage")!=null){
currentPage= Integer.parseInt(request.getParameter("currentPage"));
}
//int totalRecord=17; //총 레코드(행) 수
int pageSize=5; //한 페이지에 보여줄 레코드(행) 수
int totalPage=(int)Math.ceil((float)totalRecord/pageSize); //총 페이지 수
int blockSize=10; //한 블럭에 보여줄 페이지 수
//[1]시작 [10]끝
int firstPage=currentPage-((currentPage-1)%blockSize); //[1], [11], [21],[31]...
int lastPage = firstPage + (blockSize-1); //[10], [20],[30],[40]...
//페이지당 ArrayList에서의 시작 index => 0, 5, 10, 15, 20…
int curPos = (currentPage-1)*pageSize;
//페이지당 글 리스트 시작 번호
int num = totalRecord-(curPos); %
PagingVO 를 생성해야 함
<div class="divPage">
<!-- 페이지 번호 추가 -->
<% if(pageVO.getFirstPage()>1){ %>
<a href="list.jsp?currentPage=<%=pageVO.getFirstPage()-
1%>&category=<%=category%>&keyword=<%=keyword%>">
<img src="../images/first.JPG" border="0">
</a>
<% }//if %>
<%
//[1][2][3][4]...[10]
//[11][12][13][14]...[20]
for(int i=pageVO.getFirstPage(); i<=pageVO.getLastPage();i++){
if(i > pageVO.getTotalPage()) break;
//현재페이지인 경우 링크걸지 말고, 색상 지정
if(i==pageVO.getCurrentPage()){%>
<span style="color:blue;font-weight:bold"><%=i %></span>
<% }else{%>
<a
href="list.jsp?currentPage=<%=i%>&category=<%=category%>&keyword=<%=keyword%>">
[<%=i %>]
</a>
<% }//if
}//for %>
<%if(pageVO.getLastPage()<pageVO.getTotalPage()){ %>
<a
href="list.jsp?currentPage=<%=pageVO.getLastPage()+1%>&category=<%=category%>&keyword=<%=keyword%>"
>
<img src="../images/last.JPG" border="0">
</a>
<%}//if %>
<!-- 페이지 번호 끝 -->
</div>
▶ 삭제하기 - flag 처리
1. 답변이 있는 원본글인 경우에는 레코드를 삭제하지 말고 DelFlag = “Y” 로 update 한다
▽ deleteReboard 저장 프로시저 생성
프로시저 : 특정 기능을 수행하지만 값을 반환하지는 않는 서브프로그램
ex ) pd2테이블에 입력하는 프로시저 pd2_insert
create or replace procedure deleteReboard
(m_no number,
m_step number,
m_groupno number)
is
cnt number;
begin
--원본글인 경우
if m_step = 0 then
--답변글이 존재하는지 체크
select count(*) into cnt from reboard
where groupNo = m_groupno;
--답변글이 존재하는 경우
if cnt >1 then
update reboard set DelFlag = 'Y'
where no = m_no;
else --답변글이 없는 경우
delete reboard where no=m_no;
end if;
else --답변글 자체인 경우
delete reboard where no=m_no;
end if;
commit;
▽ deleteReboard 저장 프로시저 사용
exec deleteReboard(5, 1, 5)
2. list 페이지에서, DelFlag를 조회해 와서 값이 “Y”이 면 제목에 링크 걸지 말고, font color를 회색으로 보여 준다
▶ 조회수 증가
list 에서 글 제목을 click 하면 바로 detail 로 가는것이아니라
countUpdate 를 거쳐 readcount 컬럼의 값을 1 증가시켜준 후 detail 페이지로 넘어간다
list - countUpdate - detail
1. 리스트에서 글제목클릭하면 countUpdate 로 이동
<a href="countUpdate.jsp?no=<%=vo.getNo()%>">
<%=Utility.cutString(vo.getTitle(), 35) %></a>
2. countUpdate 에서 dao 객체 생성하며 메서드 불러옴
메서드가 1이상의 값을 반환하면 detail 페이지로 이동
<body>
<%
//list.jsp에서 제목 클릭하면 get방식으로 이동
//=> http://localhost:9090/herbmall/reBoard/countUpdate.jsp?no=6
//1
String no=request.getParameter("no");
if(no==null || no.isEmpty()){%>
<script type="text/javascript">
alert('잘못된 url입니다.');
location.href="list.jsp";
</script>
<% return;
}
//2
ReBoardDAO dao = new ReBoardDAO();
try{
int cnt=dao.updateCount(Integer.parseInt(no));
//3
if(cnt>0){
response.sendRedirect("detail.jsp?no="+no);
}else{%>
<script type="text/javascript">
alert("조회수 증가 실패!");
history.back();
</script>
<% }
}catch(SQLException e){
e.printStackTrace();
}
%>
</body>
- 해당메서드 : readcount+=1
public int updateCount(int no) throws SQLException {
Connection con=null;
PreparedStatement ps=null;
try {
con=pool.getConnection();
String sql="update reBoard set readcount=readcount+1"
+ " where no=?";
ps=con.prepareStatement(sql);
ps.setInt(1, no);
int cnt=ps.executeUpdate();
System.out.println("조회수 증가 결과 cnt="+cnt+", 매개변수 no="+no);
return cnt;
}finally {
pool.dbClose(ps, con);
}
}
++ 22.06.07 추가
reboard.xml
=> new.gif 를 위한 작업
<select id="selectAll" parameterType="searchVo" resultType="reBoardVo">
select *
from
(
select rownum as RNUM, A.*
from
(
select B.*,(sysdate-regdate)*24 as dataTerm
from reBoard B
<include refid="searchWhere"></include>
order by groupNo desc, sortNo
)A
)
where RNUM>#{firstRecordIndex}
<![CDATA[
and RNUM<=#{firstRecordIndex} + #{recordCountPerPage} ]]>
</select>
이때 생기는 dataTerm 컬럼을 vo 에 넣어줘야 정상작동 됨 !
Spring boot 답변형 게시판 list
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE HTML>
<html lang="ko">
<head>
<title>자료실 글 목록 - 허브몰</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="<c:url value='/css/mainstyle.css'/>" />
<link rel="stylesheet" type="text/css" href="<c:url value='/css/clear.css'/>" />
<link rel="stylesheet" type="text/css" href="<c:url value='/css/formLayout.css'/>" />
<link rel="stylesheet" type="text/css" href="<c:url value='/css/mystyle.css'/>" />
<script type="text/javascript" src="<c:url value='/js/jquery-3.6.0.min.js'/>"></script>
<script type="text/javascript">
$(function(){
$('.divList table.box2 tbody tr').hover(function(){
$(this).css('background','lightblue');
}, function(){
$(this).css('background','');
});
});
//페이지 번호 클릭시 실행할 함수
function pageProc(curPage){
$('input[name=currentPage]').val(curPage);
$('form[name=frmPage]').submit();
}
</script>
<style type="text/css">
body{
padding:5px;
margin:5px;
}
</style>
</head>
<body>
<h2>자료실</h2>
<c:if test="${!empty param.searchKeyword }">
<p>검색어 : ${param.searchKeyword}, ${pagingInfo.totalRecord} 건 검색되었습니다.</p>
</c:if>
<!-- 페이징 처리를 위한 form -->
<form action="<c:url value='/reBoard/list.do'/>"
method="post" name="frmPage">
<input type="text" name="searchKeyword" value="${param.searchKeyword }">
<input type="text" name="searchCondition"
value="${param.searchCondition }">
<input type="text" name="currentPage" >
</form>
<div class="divList">
<table class="box2"
summary="자료실에 관한 표로써, 번호, 제목, 작성자, 작성일, 조회수에 대한 정보를 제공합니다.">
<caption>자료실</caption>
<colgroup>
<col style="width:10%;" />
<col style="width:50%;" />
<col style="width:15%;" />
<col style="width:15%;" />
<col style="width:10%;" />
</colgroup>
<thead>
<tr>
<th scope="col">번호</th>
<th scope="col">제목</th>
<th scope="col">작성자</th>
<th scope="col">작성일</th>
<th scope="col">조회수</th>
</tr>
</thead>
<tbody>
<c:if test="${empty list }">
<tr>
<td colspan="5" class="align_center">해당 글이 존재하지 않습니다.</td>
</tr>
</c:if>
<c:if test="${!empty list }">
<!--게시판 내용 반복문 시작 -->
<c:forEach var="vo" items="${list }">
<tr style="text-align:center">
<td>${vo.no}</td>
<td style="text-align:left">
<c:if test="${vo.delFlag=='Y'}">
<span style="color:gray">삭제된 글입니다.</span>
</c:if>
<c:if test="${vo.delFlag!='Y'}">
<!-- 답변글인 경우 단계별로 화살표 이미지 보여주기 -->
<c:if test="${vo.step>0}">
<c:forEach var="i" begin="1" end="${vo.step}">
</c:forEach>
<img src='<c:url value="/images/re.gif"/>'
alt="화살표 이미지">
</c:if>
<!-- 파일이 첨부된 경우 file 이미지 보여주기 -->
<c:if test="${!empty vo.fileName }">
<img src='<c:url value="/images/file.gif"/>'>
</c:if>
<a href
="<c:url value='/reBoard/countUpdate.do?no=${vo.no}'/>">
<c:if test="${fn: length(vo.title)>30}">
${fn:substring(vo.title,0,30) }...
</c:if>
<c:if test="${fn: length(vo.title)<=30}">
${vo.title }
</c:if>
</a>
<!-- 24시간 이내의 글인 경우 new 이미지 보여주기 -->
<c:if test="${vo.dateTerm<24 }">
<img src="<c:url value='/images/new.gif'/>"
alt="new이미지"/>
</c:if>
</c:if>
</td>
<td>${vo.name}</td>
<td>
<fmt:formatDate value="${vo.regdate}" pattern="yyyy-MM-dd"/>
</td>
<td>${vo.readcount}</td>
</tr>
</c:forEach>
<!--반복처리 끝 -->
</c:if>
</tbody>
</table>
</div>
<div class="divPage">
<!-- 이전블럭으로 이동 -->
<c:if test="${pagingInfo.firstPage>1 }">
<%-- <a href
='<c:url value="/reBoard/list.do?currentPage=${pagingInfo.firstPage-1}&searchCondition=${param.searchCondition}&searchKeyword=${param.searchKeyword}"/>'> --%>
<a href="#" onclick="pageProc(${pagingInfo.firstPage-1})">
<img src='<c:url value="/images/first.JPG"/>'>
</a>
</c:if>
<!-- 페이지 번호 추가 -->
<!-- [1][2][3][4][5][6][7][8][9][10] -->
<c:forEach var="i" begin="${pagingInfo.firstPage }"
end="${pagingInfo.lastPage }">
<c:if test="${i==pagingInfo.currentPage }">
<span style="color: blue;font-weight: bold;font-size: 1em">
${i }</span>
</c:if>
<c:if test="${i!=pagingInfo.currentPage }">
<%-- <a href
='<c:url value="/reBoard/list.do?currentPage=${i}&searchCondition=${param.searchCondition}&searchKeyword=${param.searchKeyword}"/>'> --%>
<a href="#" onclick="pageProc(${i})">
[${i}]
</a>
</c:if>
</c:forEach>
<!-- 페이지 번호 끝 -->
<!-- 다음 블럭으로 이동 -->
<c:if test="${pagingInfo.lastPage < pagingInfo.totalPage }">
<%-- <a href
='<c:url value="/reBoard/list.do?currentPage=${pagingInfo.lastPage+1}&searchCondition=${param.searchCondition}&searchKeyword=${param.searchKeyword}"/>'> --%>
<a href="#" onclick="pageProc(${pagingInfo.lastPage+1})">
<img src='<c:url value="/images/last.JPG"/>'>
</a>
</c:if>
</div>
<div class="divSearch">
<form name="frmSearch" method="post"
action='<c:url value="/reBoard/list.do"/>'>
<select name="searchCondition">
<option value="title"
<c:if test="${param.searchCondition=='title' }">
selected="selected"
</c:if>
>제목</option>
<option value="content"
<c:if test="${param.searchCondition=='content' }">
selected="selected"
</c:if>
>내용</option>
<option value="name"
<c:if test="${param.searchCondition=='name' }">
selected="selected"
</c:if>
>작성자</option>
</select>
<input type="text" name="searchKeyword" title="검색어 입력"
value="${param.searchKeyword}">
<input type="submit" value="검색">
</form>
</div>
<div class="divBtn">
<a href='<c:url value="/reBoard/write.do"/>' >글쓰기</a>
</div>
</body>
</html>
'jsp' 카테고리의 다른 글
[jsp] 답글형게시판 - 파일업로드 (0) | 2022.05.13 |
---|---|
[jsp] 서블릿 Servlet (0) | 2022.05.07 |
[jsp] 인코딩 / 웹,JDBC 프로그래밍 예제 : pd테이블 (0) | 2022.05.04 |
[jsp] 웹어플리케이션 / 내장객체 / HTTP 요청메서드 GET,POST (0) | 2022.05.02 |