Jam's story
[Spring] 스프링 트랜잭션 격리성 본문
[스프링 전파방식 Propagation]
springTransaction04
method(){}
- insert
- update
중첩 트랜잭션 처리될 때 전파방식이 의미있다.
- 전파방식을 테스트
- insertAndPointUpOfMember()
- 새글쓰기 insert()
- 포인트증가
- insertAndPointUpOfMember()
한 일
- insert 수정
propagation
- required 현재 진행중인 트랜잭션이 있으면 해당 트랜잭션을 사용하고 없으면 새로운 트랜잭션을 생성한다.
- requires_new 항상 새로운 트랜잭션을 시작한다.
오류메세지
<context:component-scan base-package="newlecture, controllers" />
스프링 트랜잭션 격리 레벨
체크 제약조건 삭제
유일성 제약조건 삭제
sql
SELECT *
FROM user_constraints
WHERE table_name ='MEMBER';
WHERE table_name ='NOTICES';
ALTER TABLE MEMBER
DROP constraint CK_MEMBER_POINT;
ALTER TABLE Notices
DROP constraint UK_NOTICE_TITLE;
격리성
서로 동시에 같은자원에 접근하면 트랜잭션 처리를 어떻게 해야하나?
➡️격리레벨(수준)을 지정해줘야한다.
- 트랜잭션 처리과정에 두 개 이상의 트랜잭션이 동시에 공유자원에 접근하게 되면
- 예) 멀티스레드 (동기화처리)
- 임계영역 장금(Lock)
- 기다려 (wait) - notifyAll()
- 트랜잭션의 동시성에 따른 문제점
- hitUp() 메서드: 조회수를 증가하는 메서드
- getHit() 메서드: 조회수를 읽어와서 반환하는 메서드
- 위의 2가지 메서드가 동시에 실행된다고 가정.
- 용어
- Dirty Read 상황: 잘못된 데이터를 읽어간 상황
- A 트랜잭션 hitUp() 조회수 증가
- B 트랜잭션 getHit() 조회수 읽어
- Non-Repeatable Read 상황: 반복적으로 읽었는데 값이 매번 달라지는 경우
- Phantom Read 상황
- 여러 개의 행 (레코드) 를 한번에 읽어오는 과정 (작업) 을 반복하는 경우
- A 트랜잭션이 똑같은작업(Emp테이블에서 연봉 top 10을 읽어오기)을 여러번 하는데 , B트랜잭션이 king=5000삭제 (or 500으로 수정= 가장작은 sal)-> 처음 레코드 값과 나중의 레코드 값이 다르게 된다.
- Dirty Read 상황: 잘못된 데이터를 읽어간 상황
- 트랜잭션 격리 레벨
- DEFAULT: 기본설정 (DBMS 의 격리성 수준)
- READ_COMMITED: 커밋이 된 경우에만 READ 실행.
- Dirty READ 상황 X, non-repeatable read 상황 O
- READ_UNCOMMITED: 커밋이 되지 않은경우에도 read 실행가능
- dirty read 상황 O, non-repeatable read 상황
- REPEATABLE_READ: 특정 행을 잠그고 작업을 진행. 두 상황 모두 일어나지 않는다.
- SERIALIZABLE: 모든 행 (테이블 전체) 를 잠그고 작업을 진행.
- 팬텀리드상황 X
- hitUp() / getHit() 추가/수정.
- CustomerController - noticeDetail() 상세보기 수정
1️⃣트랜잭션 격리성을 테스트 하기 위한 용도 메소드 추가
public void hitUp(String seq);
public int getHit(String seq);
2️⃣NLNoticeDao.java
@Override
public void hitUp(String seq) {
String sql="UPDATE notice"
+ " SET hit=hit+1"
+ " WHERE seq=:seq";
MapSqlParameterSource paramSource=new MapSqlParameterSource();
paramSource.addValue("seq", seq);
this.jdbcTemplate.update(sql, paramSource);
}
@Override
public int getHit(String seq) {
String sql="SELECT hit "
+ " FROM NOTICE"
+ " WHERE seq=:seq";
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("seq", seq);
int hit = this.jdbcTemplate.queryForInt(sql, paramMap);
System.out.printf("<< getHit.hit = %d\n", hit);
return hit;
}
강제로 Dirty Read 상황 발생시키기
CustomerController-noticeDetail()
@RequestMapping("noticeDetail.htm")
public String noticeDetail(
Model model
, HttpSession session
, String seq //?seq=1
) throws Exception {
//스레드 2개 생성해서 처리하기
//조회수를 읽어오는 스레드
//0,5초 쉬기때문에 그다음메소드가 먼저 실행돈다.
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
noticeDao.getHit(seq); //0.5초 후에 조회수를 읽어가는 코딩
}//run
}, "getHit_Thread").start();
//조회수를 증가시키는 스레드
new Thread(new Runnable() {
@Override
public void run() {}//run
}, "hitup_Thread").start();
//조회수 증가
this.noticeDao.hitUp(seq);
Notice notice=this.noticeDao.getNotice(seq);
model.addAttribute("notice", notice);
return "noticeDetail.jsp";
}
더티리드 만들기
NLNoticeDao.java
@Override
//@Transactional(isolation=Isolation.READ_COMMITTED)
@Transactional(isolation=Isolation.READ_UNCOMMITTED) //더티리드
public int getHit(String seq) {
String sql="SELECT hit "
+ " FROM NOTICE"
+ " WHERE seq=:seq";
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("seq", seq);
int hit = this.jdbcTemplate.queryForInt(sql, paramMap);
System.out.printf("<< getHit.hit = %d\n", hit);
return hit;
}
오후시간
springTiles 프로젝트 생성
1.격리수준- 설정코딩수정
CustomerController.noticeDetali()수정
NLNoticeDao.hitUp() 수정
2.스프링타일즈
1)페이지 모듈화(집중화)
페이지 마다 공통적인 영역을 모듈화해서 공통적으로 참조할 수 있도록 하는 방법
2)JSP 프로젝트 -@include 지시자, <jsp:include>액션태그
layout폴더
ㄴTOP
ㄴBottom
ㄴAside
다운로드
http://archive.apache.org/dist/tiles/v2.2.2/
압축풀어서 라이브러리 추가하기
webapp 폴더
ㄴ inc 폴더 - 모든 웹 페이지에서 공통적인 영역
ㄴ header.jsp
ㄴ footer.jsp
ㄴ layout.jsp
ㄴ. joinus 폴더
ㄴ inc 폴더
ㄴ visual.jsp
ㄴ aside.jsp
ㄴ layout.jsp
ㄴ. customer 폴더
ㄴ inc 폴더 - 모든 웹 페이지에서 공통적인 영역
ㄴ visual.jsp
ㄴ aside.jsp
ㄴ layout.jsp
tiles-defs.xml
타일붙이듯이 타일처럼 붙이겟다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<tiles-definitions>
<!-- <definition name="myapp.homepage" template="/layouts/classic.jsp">
<put-attribute name="title" value="Tiles tutorial homepage" />
<put-attribute name="header" value="/tiles/banner.jsp" />
<put-attribute name="menu" value="/tiles/common_menu.jsp" />
<put-attribute name="body" value="/tiles/home_body.jsp" />
<put-attribute name="footer" value="/tiles/credits.jsp" />
</definition> -->
<definition>
</definition>
</tiles-definitions>
컨트롤러
마지막에 수정 return "costomer.notice"; //스프링 타일즈 뷰리절브
@RequestMapping("notice.htm")
public String notices(
// ?page=1&field=title&query=hh
@RequestParam( value = "page", defaultValue = "1" ) int page
, @RequestParam( value = "field", defaultValue = "title" ) String field
, @RequestParam( value = "query", defaultValue = "" ) String query
, Model model
) throws Exception {
List<Notice> list= this.noticeDao.getNotices( page, field, query);
model.addAttribute("list", list);
model.addAttribute("test", "Hello, Spring MVC World!");
return "costomer.notice"; //스프링 타일즈 뷰리절브
} // notices
dispatcher-servlet.xml
스프링타일즈 사용하기 위해 필요한 빈 객체
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- dispatcher-servlet.xml -->
<context:component-scan base-package="newlecture, controllers"></context:component-scan>
<!-- p439 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="-1"></property>
</bean>
<!-- p524 @transactional 어노테이션 -->
<tx:annotation-driven
transaction-manager="transactionManager"
mode="proxy"
proxy-target-class="false"
/>
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions" value="/WEB-INF/tiles-defs.xml"></property>
</bean>
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"></property>
</bean>
<!-- ViewResolver 등록 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
</beans>
'Spring' 카테고리의 다른 글
[Spring] 스프링시큐리티 - 로그인 (0) | 2022.07.21 |
---|---|
[Spring] 스프링 레거시 프로젝트 4.0버전 (0) | 2022.07.20 |
[Spring] 트랜잭션 (0) | 2022.07.18 |
[Spring] NamedParameterJdbcTemplate (0) | 2022.07.18 |
[Spring] JDBC (0) | 2022.07.17 |