한번에 여러가지 이벤트가 동시에 처리 되는 것을 transaction 프로그램이라고 한다. 한 이벤트에 에러가 있으면 모든 이벤트가 전부 처리되지 않는 프로그램이다.
package com.sist.dao;
import org.springframework.stereotype.Repository;
import java.util.*;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.sql.*;
@Repository
public class MemberDAO {
private Connection conn;
private PreparedStatement ps;
private final String URL="jdbc:oracle:thin:@localhost:1521:XE";
// 객체 생성시에 호출되는 메소드 지정 => XML(init-method)
@PostConstruct
public void init()
{
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (Exception e) {
}
}
// 객체가 메모리에서 삭제 메소드 지정 => XML(destroy-method)
@PreDestroy
public void close()
{
try
{
if(ps!=null) ps.close();
if(conn!=null) conn.close();
} catch (Exception e) {
}
}
public void getConnection()
{
try
{
conn=DriverManager.getConnection(URL,"hr", "happy");
}catch(Exception ex){}
}
public void disConnection()
{
try
{
if(ps!=null) ps.close();
if(conn!=null) conn.close();
} catch (Exception e) {
}
}
// 기능 설정 (DML 여러개 있는 경우) = 동시에 처리 (트랜잭션)
public void memberInsert()
{
try
{
getConnection();
String sql="INSERT INTO spring_member VALUES(1,'홍길동', '남지')";
ps=conn.prepareStatement(sql);
ps.executeUpdate(); // commit
sql="INSERT INTO spring_member VALUES(1,'심정이', '여자')";
ps=conn.prepareStatement(sql);
ps.executeUpdate(); // catch => rollback
}catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
disConnection();
}
}
// 트랜잭션 처리
public void memberInsert2()
{
try
{
getConnection(); // Before
conn.setAutoCommit(false); // commit을 해제
String sql="INSERT INTO spring_member VALUES(1,'홍길동', '남지')";
ps=conn.prepareStatement(sql);
ps.executeUpdate(); // commit(X)
sql="INSERT INTO spring_member VALUES(1,'심정이', '여자')";
ps=conn.prepareStatement(sql);
ps.executeUpdate(); // commit(X)
conn.commit(); // around
} catch (Exception e) {
e.printStackTrace();
try
{
conn.rollback(); // 전체 취소 afterThrowing
}catch(Exception ex){}
}
finally
{
try
{
conn.setAutoCommit(true); // AfterThrowing
}catch(Exception ex){}
disConnection();
}
}
}
java에서는 sql문장을 실행하면 자동으로 commit이 되기 때문에 autocommit을 해제한다
만약 에러가 생겨서 catch절을 수행하면 거기서 트랜잭션을 취소할 수 있는 rollback() 명령을 내려준다.
트랜잭션 프로그램이 적용될 수 있는 곳은 게시판 삭제 등이 있다.
게시판을 삭제하려면 관련 댓글 정보까지 전부 한번에 삭제처리 되어야하기 때문이다.
그리고 AOP 프로그램
목적은 반복되는 메소드를 모아서 한번에 처리한다 -> 유지보수가 편리해진다, 코드의 효율성이 좋아진다
위 프로그램의 실행결과를 보면 오라클 연결과 해제가 계속해서 반복되는것을 볼 수 있다.
바로 저 부분을 공통으로 묶어 AOP로 처리해줄 수 있다.
일단 AOP를 사용하려면 spring container에 등록을 먼저 해야한다.
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.sist.*"/>
<aop:aspectj-autoproxy/>
</beans>
aop:aspectj-autoproxy를 꼭 써줘야 aop가 사용가능하다
/*
* AOP (횡단지향프로그램) : 분석이 어렵다 => 스프링에서 지원하는 로그파일,트랜잭션 , 보안 (AOP)
*
* public void insert()
* {
* getConnection();
* try
* {
* conn.setAutoCommit(false);
* INSERT문장 실행
* INSERT문장 실행
* conn.commit();
* }catch(Exception ex)
* {
* conn.rollback();
* ex.printStackTrace();
* }
* finally
* {
* conn.setAutoCommit(true)
* disConnection();
* }
*
* }
*
* @Transactional
* public void insert()
* {
* getConnection();
* INSERT문장 실행
* INSERT문장 실행
* disConnection();
* }
*
* 1. JoinPoint
* 어디에서 호출
* BEFORE
* public void display()
* {
* ====> Before
* try
* {
*
* }catch(Exception ex)
* {
*
* }
* }
* AFTER
* public void display()
* {
*
* try
* {
*
* }catch(Exception ex)
* {
*
* }
* finally
* {
* ==> After
* }
* }
* AFTERRETURNING
* public void display()
* {
*
* try
* {
*
* }catch(Exception ex)
* {
*
* }
* finally
* {
* ==> After
* }
*
* return => 정상수행 => return값을 받을 수 있다
* }
* AFTERTHROWING
* public void display()
* {
*
* try
* {
*
* }catch(Exception ex)
* {
* => 에러발생시 처리 => 에러내용을 받아 볼 수 있다
* }
* finally
* {
* ==> After
* }
* }
* AROUND
* public void display()
* {
*
* try
* {
* ==============
* 소수 코딩
* ==============
* }catch(Exception ex)
* {
*
* }
* finally
* {
* ==> After
* }
* }
* 2. PointCut
* 어떤 메소드가 호출될때 적용
* 3. Advice
* JointPoint+PointCut
* 4. Aspect
* Advice여러개를 가지고 있는 클래스
*/
어디서 aop가 실행되는지에 따라 jointpoint가 달라진다.
사용자 정의 메소드 앞에서 실행되면 : before
사용자 정의 메소드 앞에서 실행되면 : after
사용자 정의 메소드 앞뒤에서 실행되면 : around
catch절 안에서 실행되면 (에러 발생시에 실행) : AfterThrowing
pointcut은 어떤 메소드가 호출될때 실행될 것인지를 정해준다.
그리고 jointPoint+pointCut을 합친것을 Advice라고 하고,
여러 Advice를 모아 놓은 클래스를 Aspect라고 한다.
그럼 Aspect 파일을 한 번 보겠다.
package com.sist.aop;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
// 메모리 할당이 아니라 => 공통으로 사용되는 메소드를 모아두는 곳
import com.sist.dao.BoardDAO;
@Aspect
@Component
public class MyAspect {
@Autowired
private BoardDAO dao;
@Before("execution(* com.sist.dao.BoardDAO.aop*(..))")
/*
* * com.sist.dao.BoardDAO.aop*(..)
* ==
* 리턴형 (모든 리턴형)
*/
public void getConnection()
{
dao.getConnection();
}
@After("execution(* com.sist.dao.BoardDAO.aop*(..))")
public void disConnection()
{
dao.disConnection();
}
}
@After - jointPoint
"execution(* com.sist.dao.BoardDAO.aop*(..))" - pointCut
이렇게 나눠서 보면 된다.
그리고 aop를 적용해서 일부러 에러가 나는 소스코드를 작성해봤다
package com.sist.manager;
import org.springframework.stereotype.Component;
@Component
public class MyManager {
public void display()
{
int i=10/0;
System.out.println("i="+i);
}
}
0으로 나누면 당연히 에러를 실행하는게 맞는데, aop에서 경고메세지를 날려줄 수 있다.
package com.sist.aspect;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAspect {
// 에러가 난 경우
@AfterThrowing(value="execution(* com.sist.manager.MyManager.display())", throwing="ex")
public void afterThrowing(Exception ex)
{
System.out.println("AOP에서 감지된 에러:"+ex.getMessage());
}
}
에러가 난 경우 에러메세지를 출력할 수 있도록 만든 코드이다.
'programming > Gukbi' 카테고리의 다른 글
국비 교육 87일차 - 동적쿼리연습, 대댓글 게시판 (0) | 2021.04.30 |
---|---|
국비 교육 86일차 - Mybatis 동적 쿼리 (0) | 2021.04.29 |
국비 교육 84일차 - spring tiles (0) | 2021.04.26 |
국비 교육 83일차 - AJAX 검색 기능 활용 (0) | 2021.04.26 |
국비 교육 82일차 - oracle index 활용 (0) | 2021.04.26 |