ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Camel][Spring] 게시판 만들기 #8. 게시글 조회수 증가 및 트랜잭션 처리
    Spring/게시판 만들기 2020. 6. 28. 21:00

    [Camel][Spring] 게시판 만들기 #8. 게시글 조회수 증가 및 트랜잭션 처리

     

    본 게시판 만들기 프로젝트는 더블에스 Devlog Spring-MVC 를 참조하여 작성했음을 알려드립니다. 또한 개인적인 학습을 목적으로한 포스팅이기 때문에 완벽하지 않을 수 있음을 알려드립니다. 문제점이나 궁금한점은 댓글로 남겨주시면 감사하겠습니다. 프로젝트 생성에 앞서 이번 게시판 만들기 프로젝트는 이클립스를 사용하여 구현하였습니다. 

     

    이번 포스팅에서는 이전에 처리하지 않고 넘어왔던 게시글목록에서의 게시글 조회수 증가 출력과 트랜잭션 처리에 대해 알아보겠습니다. 

     

    1. 트랜잭션

    트랜잭션을 사용하는 경우는 여러 과정을 하나의 행위로 묶을 때 사용하게 됩니다. 여러 단걔를 수행했을 때, 한가지라도 실패하게되면 모든 작업이 취소되는 것입니다. 이렇게 함으로써 데이터의 무결성을 보장할수 있게되는 것입니다. 

    1-1. 트랜잭션의 특징

    트랜잭션의 특징으로는 크게 4가지가 있습니다.

    • 원자성 (Atomicity)
      • 트랜잭션의 연산은 데이터베이스에 모두 반영되거나 모두 반영되지않아야 합니다. 이는 즉 트랜잭션 내의 모든 명령은 완벽히 수행되어야만 의미가 있는 것이며, 모두 완벽하게 수행되지 않는다면 트랜잭션의 전부가 취소됨을 의미합니다.
    • 일관성 (Consistency)
      • 트랜잭션의 수행이 성공적으로 완료되었다면 언제나 일관성있는 데이터베이스 상태로 변환해야합니다. 이는 즉 트랜잭션 수행 전과 트랜잭션 수행 후의 상태가 같아야함을 의미합니다. 
    • 독립성 (Isolation)
      • 동시에 둘 이상의 트랜잭션이 실행되는 경우 어느 하나의 트랜잭선 실행 중에 다른 트랜잭션의 연산이 실행될 수 없는 것을 의미합니다. 즉 수행 중인 트랜잭션이 완전히 완료되어야지만 다름 트랜잭션에서 수행결과를 참조할 수 있게 되는 것입니다.
    • 영속성 (Durability)
      • 성공적으로 완료된 트랜잭션의 결과는 영구적으로 반영됩니다. 

    1-2. 트랜잭션의 원리

    트랜잭션은 2개이 상의 쿼리를 하나의 거넥션으로 묶어 데이터베이스에 전달하고ㅡ 이 과정에서 오류 및 에러가 발생할 경우 자동으로 모든 과정을 원래 상대로 돌려 놓습니다. 이러한 과정을 구현하기 위해서는 트랜잭션은 하나 이상의 쿼리를 처리할 때 동일한 커넥션 객체를 공유하도록 합니다. 

    1-3. Spring에서의 트랜잭션

    Spring에서는 코드 기반의 트랜잭션 처리와 선언적 트랜잭션 처리를 모두 지원하고 있습니다.

     코드 기반의 트랜잭션 처리를 사용하기 위해서는 Spring에서 제공하는 트랜잭션 템플릿 클래스를 사용하는 방법이 있고, 선언적 트랜잭션 처리를 사용하기 위해서는 설정파일, 애노테이션을 이용해서 트랜잭션의 범위 및 규칙을 정의할 수 있습니다.

     

    1-4 @Transactional 애노테이션

    @Transactional

     위와 같이 두가지 방법의 트랜잭션 처리 방법이 있지만 Spring에서는 주로 선언적 트랜잭션 처리를 애용합니다. 그 대표적인 예로 @Transactional 애노테이션이 있습니다. 이 애노테이션은 쿼리문을 처리하는 과정에서 오류 및 에러가 발생할 경우 자동으로 Rollback 처리를 수행합니다. 

     일반적으로 Spring에서는 Service계층(비즈니스 계층)에 @Transactional 애노테이션을 추가하는 방식을 사용합니다. 

     

    2. Spring에서의 트랜잭션 처리를 위한 설정

    이론적 설명을 마치고, 다시 게시판 프로젝트로 돌아와서 우선 pom.xml 파일에 트랜잭션 관련 라이브러리를 추가해주고 , root-context.xml 파일에도 아래와 같은 내용을 추가해줍니다.

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <tx:annotation-driven/>

     

     

     

     

     


    게시글의 댓글에 따른 트랜잭션 처리


     

    3. 게시글 테이블 및 ArticleVO 클래스 수정

    3-1. 게시글 테이블 수정

    게시글 테이블에 댓글의 수를 의미하는 Column을 추가해줍니다. 

    ALTER TABLE tb_article ADD COLUMN reply_cnt int DEFAULT 0;

    3-2. ArticleVO 클래스 수정

    게시글 테이블에 댓글 수 관련 Column을 추가해줬으니 ArticleVO에도 댓글 관련 멤버변수를 추가해줍니다. 

    package com.cameldev.mypage.domain;
    
    import java.sql.Date;
    import java.util.Arrays;
    
    public class ArticleVO {
    
        private Integer article_no;
    
        private String title;
    
        private String content;
    
        private String writer;
    
        private Date regDate;
    
        private int viewCnt;
        
        private int replyCnt;
    
    	public Integer getArticle_no() {
    		return article_no;
    	}
    
    	public void setArticle_no(Integer article_no) {
    		this.article_no = article_no;
    	}
    
    	public String getTitle() {
    		return title;
    	}
    
    	public void setTitle(String title) {
    		this.title = title;
    	}
    
    	public String getContent() {
    		return content;
    	}
    
    	public void setContent(String content) {
    		this.content = content;
    	}
    
    	public String getWriter() {
    		return writer;
    	}
    
    	public void setWriter(String writer) {
    		this.writer = writer;
    	}
    
    	public Date getRegDate() {
    		return regDate;
    	}
    
    	public void setRegDate(Date regDate) {
    		this.regDate = regDate;
    	}
    
    	public int getViewCnt() {
    		return viewCnt;
    	}
    
    	public void setViewCnt(int viewCnt) {
    		this.viewCnt = viewCnt;
    	}
    	
    	public int getReplyCnt() {
    		return replyCnt;
    	}
    
    	public void setReplyCnt(int replyCnt) {
    		this.replyCnt = replyCnt;
    	}
    
    	@Override
    	public String toString() {
    		return "ArticleVO [article_no=" + article_no + 
    						", title="+ title + 
    						", content="+ content + 
    						", writer="+ writer + 
    						", regDate="+ regDate + 
    						", viewCnt="+ viewCnt + 
    						", replyCnt="+ replyCnt + "]" ;
    	}
        
    }

    3-3. articleMapper.xml 수정

    게시글 목록을 출력할 때 댓글의 수를 필요로 하기 때문에 listSearch 부분과 resultMap을 수정해줍니다. 또한 댓글 갯수를 갱신하기 위한 SQL문도 추가해 주겠습니다. 

    <!-- 수정 -->
    <select id="listSearch" resultMap="ArticleResultMap">
        <![CDATA[
        SELECT
            article_no,
            title,
            content,
            writer,
            regdate,
            viewcnt,
            reply_cnt
        FROM tb_article
        WHERE article_no > 0
        ]]>
          <include refid="search"/>
        <![CDATA[
        ORDER BY article_no DESC, reg_date DESC
        LIMIT #{pageStart}, #{perPageNum}
        ]]>
    </select>
    
    <!-- 추가 -->
    <update id="updateReplyCnt">
        UPDATE tb_article
        SET reply_cnt = reply_cnt + #{amount}
        WHERE article_no = #{article_no}
    </update>
    
    <!-- 수정 -->
    <resultMap id="ArticleResultMap" type="ArticleVO">
      <id property="article_no" column="article_no"/>
      <result property="title" column="title" />
      <result property="content" column="content" />
      <result property="writer" column="writer" />
      <result property="regDate" column="regdate" />
      <result property="viewCnt" column="viewcnt" />
      <result property="replyCnt" column="reply_cnt" />
    </resultMap>

     

     

    4. Persistence 계층 수정

    ArticleDAO 인터페이스에 댓글 갯수 갱신 관련 추상메소드를 선언해주고, ArticleDAOImpl 클래스에는 선언해주었던 추상메소드를 오버라이딩하여 메소드를 구현하겠습니다. 

     

     또한, 댓글과 관련되어 있는 처리이기 때문에 게시글 관련 Persistence 계층뿐만아니라 댓글 관련 Persistence 계층또한 수정해 주겠습니다. 

     

    4-1. ArticleDAO 인터페이스 수정

    void updateReplyCnt(Integer article_no, int amount) throws Exception;

    4-2. ArticleDAOImpl 클래스 수정

    @Override
    public void updateReplyCnt(Integer article_no, int amount) throws Exception {
    
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("article_no", article_no);
        paramMap.put("amount", amount);
    
        sqlSession.update(NAMESPACE + ".updateReplyCnt",paramMap);
    }

    4-3. ReplyDAO 인터페이스 수정

    int getArticleNo(Integer reply_no) throws Exception;

    4-4. ReplyDAOImpl 클래스 수정

    @Override
    public int getArticleNo(Integer reply_no) throws Exception {
        return sqlSession.selectOne(NAMESPACE + ".getArticleNo", reply_no);
    }

    4-4. replyMapper.xml 수정

    <select id="getArticleNo" resultType="int">
        SELECT
            article_no
        FROM tb_reply
        WHERE reply_no = #{reply_no}
    </select>

     

     

    5. Service 계층 수정

    Service 계층에서는 새로운 메소드를 추가할 필요없이 댓글 등록 및 삭제를 처리하는 메소드를 아래와 같이 수정해주겠습니다. 이때 앞서 알아보았던 트랜잭션 처리를 해주도록 하겠습니다. 

     

    ReplyServiceImpl 클래스 수정

    private final ReplyDAO replyDAO;
    
    private final ArticleDAO articleDAO;
    
    @Inject
    public ReplyServiceImpl(ReplyDAO replyDAO, ArticleDAO articleDAO) {
        this.replyDAO = replyDAO;
        this.articleDAO = articleDAO;
    }
    
    // 댓글 등록
    @Transactional // 트랜잭션 처리
    @Override
    public void addReply(ReplyVO replyVO) throws Exception {
        replyDAO.create(replyVO); // 댓글 등록
        articleDAO.updateReplyCnt(replyVO.getArticle_no(), 1); // 댓글 갯수 증가
    }
    
    // 댓글 삭제
    @Transactional // 트랜잭션 처리
    @Override
    public void removeReply(Integer reply_no) throws Exception {
        int article_no = replyDAO.getArticleNo(reply_no); // 댓글의 게시물 번호 조회
        replyDAO.delete(reply_no); // 댓글 삭제
        articleDAO.updateReplyCnt(article_no, -1); // 댓글 갯수 감소
    }

     

    6. 게시글 목록 출력 페이지 수정

    댓글의 수는 게시글 제목의 옆에 출력되도록 하기위해서 게시물 제목 출력부분을 아래와 같이 수정해주겠습니다. 

    <td>
        <a href="${path}/article/paging/search/read${pageMaker.makeSearch(pageMaker.criteria.page)}&article_no=${article.article_no}">
                ${article.title}
        </a>
        <span class="badge bg-teal"><i class="fas fa-comment"></i> + ${article.replyCnt}</span>
    </td>

     

     

    7. 게시글 목록 출력 페이지에서의 댓글 갯수 출력 확인

    출력확인 결과 댓글의 갯수가 정상적으로 출력되는 것을 확인할 수 있습니다.

     

     

     

     

     


    게시글의 조회에 따른 트랜잭션 처리


    8. Persistence 계층 수정

    이번에는 ArticleDAO 인터페이스에 조회수 증가 관련 추상메소드를 선언해주고, ArticleDAOImpl 클래스에는 선언해주었던 추상메소드를 오버라이딩하여 메소드를 구현하겠습니다. 

     

    8-1. ArticleDAO 인터페이스 수정

    void updateViewCnt(Integer article_no) throws Exception;

    8-2. ArticleDAOImpl 클래스 수정

    @Override
    public void updateViewCnt(Integer article_no) throws Exception {
        sqlSession.update(NAMESPACE + ".updateViewCnt", article_no);
    }

    8-3. articleMapper.xml 수정

    <update id="updateViewCnt">
        UPDATE tb_article
        SET viewcnt = viewcnt + 1
        WHERE article_no = #{article_no}
    </update>

     

    9. Service 계층 수정

    댓글 갯수 처리때와 마찬가지로 Service 계층에서는 새로운 메소드를 추가할 필요없이 게시글 조회를 처리하는 메소드를 아래와 같이 수정해주겠습니다. 이때도 마찬가지로 트랜잭션 처리를 해주도록 하겠습니다. 

     

    ArticleServiceImpl 클래스 수정

    @Transactional(isolation = Isolation.READ_COMMITTED)
    @Override
    public ArticleVO read(Integer article_no) throws Exception {
        articleDAO.updateViewCnt(article_no);
        return articleDAO.read(article_no);
    }

     

    10. 게시글 목록 출력 페이지에서의 조회수 증가 확인

     

     

     

    11. 포스팅을 마치며

    이번 포스팅에서는 트랙잭션에 대해 설명하고, 조회수 증가처리와 댓글 갯수 출력처리를 구현했습니다. 다음 포스팅에서는 로그인 처리에 대해 포스팅하겠습니다. 

     

     

    다음 포스팅

    2020/06/29 - [Spring/게시판 만들기] - [Camel][Spring] 게시판 만들기 #9. 회원가입, 로그인 기능 구현

     

    [Camel][Spring] 게시판 만들기 #9. 회원가입, 로그인 기능 구현

    [Camel][Spring] 게시판 만들기 #9. 회원가입, 로그인 기능 구현 본 게시판 만들기 프로젝트는 더블에스 Devlog Spring-MVC 를 참조하여 작성했음을 알려드립니다. 또한 개인적인 학습을 목적으로한 포

    cameldev.tistory.com

    12. Reference

    https://doublesprogramming.tistory.com/124

    https://mangkyu.tistory.com/50

     

     

     

    글을 읽으시면서 잘못된 부분이나 궁금하신 사항은 댓글 달아주시면 빠른 시일내에 수정 및 답변하도록 하겠습니다. 

     

    댓글

Camel`s Tistory.