Spring
[Spring] SqlSession, 트랜잭션
삶_
2022. 10. 4. 09:41
RootApplicationContext
- 먼저 실행됨
- <context-param> 내에 있는 xml 파일들이 먼저 읽힘
- bean 들이 들어있음. 서로 참고 가능.
WebApplicationContext
- RootApplicationContext 다음 실행됨
- DispatcherServlet
- <load-on-startup>1<..
- ----servlet.xml 파일들 인식
- bean들이 들어있음. 서로 참고 가능.
mybatis 연결
SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- typeAliases : 객체들 별칭 정해놓는 곳 -->
<!-- 재사용 가능성이 높은 VO의 별칭 정해놓기 -->
<typeAliases>
<typeAlias type="com.spring.ex01.MemberVO" alias="memberVO" />
</typeAliases>
<!-- environments : DB에 연결할 설정 정보들 -->
<!-- 여러개의 environments 설정 가능하다는 뜻 -->
<!-- default="아이디" : 기본으로 연결할 설정 정보 아이디 -->
<environments default="development">
<!-- 설정 정보 시작 -->
<environment id="development">
<!-- 트랜잭션 제어를 누가 할것인가 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 실제 DB 접속에 관한 정보 -->
<!-- type : 커넥션을 사용할건지에 대한 여부 -->
<!-- POOLED : 최초 Connection객체를 생성 시, 그 정보를 풀 영역에 저장.(이후 재사용 가능) -->
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"></property>
<property name="username" value="scott"></property>
<property name="password" value="tiger"></property>
</dataSource>
</environment>
</environments>
<!-- DB에 사용되는 쿼리문을 담은 mapper 파일 등록 -->
<mappers>
<mapper resource="mybatis/mapper/member.xml" />
</mappers>
</configuration>
member.xml
<mapper>
<!-- property : get메서드 이름 -->
<resultMap id="memResult" type="memberVO">
<result property="id" column="id" />
<result property="pwd" column="pwd" />
<result property="name" column="name" />
<result property="email" column="email" />
<result property="joinDate" column="joinDate" />
</resultMap>
<select id="selectAllMemberList" resultMap="memResult">
<!-- ![CDATA[문장]] : 태그로 오해하지 말라는 뜻. SQL 문의 일부라는 뜻으로 알려주기 위해 작성. -->
<![CDATA[
select * from t_member order by joinDate desc
]]>
</select>
<!-- parameterType : 아래 SQL문 호출시 전달되는 매개변수의 데이터 타입 지정 -->
<!-- 예시 : ...selectOne("mapper.member.selectMemberById", id) 로 호출했을 때 -->
<select id="selectMemberById" resultMap="memResult" parameterType="String">
<![CDATA[
select * from t_member
where id = #{id}
]]>
</select>
</mapper>
SqlSession 의 메서드
- selectList(query_id) : id에 대한 select 문 실행, 여러 레코드를 List로 반환
- selectList(query_id, 조건) : id에 대한 select 문 실행, 사용되는 조건도 전달
- selectOne(query_id) : id에 대한 select 문 실행, 지정 타입으로 한개의 레코드 반환
- selectOne(query_id, 조건) : id에 대한 select 문 실행, 사용되는 조건도 전달.
- insert(query_id, obj) : id에 대한 insert문을 실행. obj 객체의 값을 테이블에 추가
- update(query_id, obj) : obj 객체의 값을 조건문의 수정 값으로 사용. id에 대한 update문 실행
- delete(query_id, obj) : obj 객체의 값을 조건문의 수정 값으로 사용. id에 대한 delete문 실행
동적 SQL 문 만들기
<if>
<where>
<if test="조건식">
추가할 구문
</if>
</where>
이런 식이고,
<select id="searchMember" parameterType="memberVO" resultMap="memResult">
<![CDATA[
select * from t_member
]]>
<!-- SQL 문의 where 절을 의미 -->
<where>
<!-- name이 공백, null이 아닐 때 -->
<if test="name != '' and name != null">
name = #{name}
</if>
<!-- email이 공백, null이 아닐 때 -->
<if test="email != '' and email != null">
email = #{email}
</if>
</where>
order by joinDate desc
</select>
<choose>
<!-- 자바의 switch문 같은 것 -->
<choose>
<when test="조건식">
구문...
</when>
<when test="조건식">
구문...
</when>
..
<!-- 아래는 생략 가능 -->
<!-- 그 외 -->
<otherwise>
구문...
</otherwise>
</choose>
<foreach>
<!-- 한번에 여러개 데이터를 처리할 때 -->
<!-- 설명 시작
collection : 전달받은 인자값. array와 list 값을 전달 가능.
index : foreach문이 반복될 때 마다 1씩 증가. 접근하는 값의 위치를 나타냄
item : 반복문이 실행될 때마다 collection 속성에 지정된 값에 접근하여 차례대로 사용
open : 해당 구문이 시작될 때 붙힐 기호
close : 해당 구문이 끝날 때 붙일 기호
separator : 한번이상 반복될 때, 반복되는 사이에 지정한 기호 추가
설명 끝 -->
<foreach item="item" collection="list" index="index" open="(" close=")" separator=",">
#{item}
</foreach>
<!-- 여러명 insert 할 때 -->
<!-- before -->
<insert id="foreachInsert" parameterType="java.util.Map">
INSERT INTO t_member (id, pwd, name, email)
VALUES
<foreach item="item" collection="list">
(#{item.id},
#{item.pwd},
#{item.name},
#{item.email}
)
</foreach>
</insert>
<!-- after -->
<insert id="foreachInsert" parameterType="java.util.Map">
<!-- 반복 작업시, INSERT ALL 사용 -->
<foreach item="item" collection="list" open="INSERT ALL" separator=" "
close="SELECT * FROM DUAL">
INTO t_member (id, pwd, name, email)
VALUES
(#{item.id},
#{item.pwd},
#{item.name},
#{item.email}
)
</foreach>
</insert>
트랜잭션
- 여러개의 DML 명령문을 하나의 논리적인 작업 단위로 묶어서 관리하는 것
- SQL 명령문이 정상 처리 → 모든 작업 결과를 DB에 영구 반영
- 하나라도 잘못된 것 발견 → 모두 취소됨
스프링의 트랜잭션 속성들
- propagation : 트랜잭션 전파 규칙 설정
- REQUIRED
- 트랜잭션 필요. 진행 중인 트랜잭션이 있는 경우, 해당 트랜잭션 사용
- 트랜잭션이 없으면 새로운 트랜잭션 생성.
- 디폴트 값임.
- REQUIRED
- isolation : 트랜잭션 격리 레벨 설정
- readonly : 읽기 전용 여부 설정
- rollbackFor : 트랜잭션을 롤백할 예외 타입 설정
- norollbackFor : 트랜잭션을 롤백하지 않을 예외 타입 설정
- timeout : 트랜잭션 타임아웃 시간 설정
트랜잭션 활용
- 보통 sql문이 들어간 메서드를 실행하면 변경된 사항이 그대로 남아있지만,
- 트랜잭션을 이용하면 중간에 변경 후 사이트 오류 발생시
- 다시 원본 값으로 돌아오게 만든다
// TestService 클래스의 모든 메서드에 트랜잭션을 적용함
@Transactional(propagation=Propagation.REQUIRED)
public class TestService() {
private TestDAO dao;
public void setDao (TestDAo dao){
this.dao = dao;
}
public void testMethod() throws Exception {
// 아래는 sql 문(update)이라고 가정
dao.updateSql1();
dao.updateSql2();
}
}
스프링 애너테이션 제공 클래스
- DefaultAnnotationHandlerMapping : 클래스 레벨에서 @RequestMapping 을 처리
- AnnotationMethodHandlerAdapter : 메서드 레벨에서 @RequestMapping 을 처리
context:component-scan
- <context:component-scan base-package=”패키지 이름”>
- 애너테이션
- @Controller : 스프링 컨테이너가 component-scan에 의해 지정한 클래스를 컨트롤러 빈으로 자동 변환
- 클래스 이름이 TestController 라면
- <bean id=’testController’ class=’TestController’> 와 의미가 같음
- @Service : 위와 같고 서비스 빈으로 자동 변환
- @Repository : 위와 같고 DAO 빈으로 자동 변환
- @Component : 위와 같고 빈으로 자동 변환
- @Controller : 스프링 컨테이너가 component-scan에 의해 지정한 클래스를 컨트롤러 빈으로 자동 변환
참고
자바 웹을 다루는 기술