티스토리 뷰

1.    트랜잭션의 종류

-      1 ) 로컬 트랜잭션 ( Local TX )

-       : 무조건 Connection 1개로 DML 작업 수행

-      2 ) 전역 트랜잭션 ( Global TX )

-       : 동시에 여러 개의 Connection을 사용 ( 1개 이상의 DB )

-      + 전역 트랜잭션의 경우, 자동으로 커밋 / 롤백 시켜주는 트랜잭션 관리자(TX Manager)WAS 안에 있다.

-      + 2단계 커밋 / 롤백을 거치게 된다.

 

2.    Driver SPY 사용법

-      1 ) 정식 라이브러리 명칭 : log4jbc

-      2 ) pom.xml 파일에 dependency(의존성) 추가

-      <dependency>

-                  <groupId>org.bgee.log4jdbc-log4j2</groupId>

-                  <artifactId>log4jdbc-log4j2-jdbc4</artifactId>

-                  <version>1.16</version>

-      </dependency>

-      3 ) JDBC URL에 단어 하나 추가 : jdbc:log4jdbc:oracle:… (***)

-      4 ) log4j2.xml 설정파일(lombok @Log4j2의 설정)Driver Spy(log4jdbc) 로깅설정 추가

-      <logger name="log4jdbc.log4j2" level="info" additivity="false">

-      <MarkerFilter marker="LOG4JDBC_JDBC" onMatch="DENY" onMismatch="NEUTRAL"/>

-        <appender-ref ref="Console"/>

-      </logger>

-      5 ) 평소대로 JDBC api를 사용한 프로그램 수행하면, JDBC Driver의 상세내역이 출력된다.

 

3.    TDD ( Test – Driven Development )

-      테스트 주도 개발

 

4.    EDD ( Event – Driven Development )

-      이벤트 주도 개발

 

5.    Junit 4.x Test Framework 사용법

-      1 ) pojo 기반의 테스트 클래스 생성

-      + (Plain Old Java Object, 상속/구현도 하지 않는 아주 평범한 클래스)

-      2 ) 반드시 매개변수가 없는 기본 생성자를 가지고 있어야 한다.

-      3 ) 아래의 3가지 어노테이션을 이용해서, 테스트 골격 코드를 생성

-      + @Before  -> public 접근제한자를 가진 메소드로 구현

-       + @Test    -> public 접근제한자를 가진 메소드로 구현

-       + @After   -> public 접근제한자를 가진 메소드로 구현

 

6.    Junit 5.x Test Framework 사용법

-      1 ) pojo 기반의 테스트 클래스 생성

-      + (Plain Old Java Object, 상속/구현도 하지 않는 아주 평범한 클래스)

-      2 ) 반드시 매개변수가 없는 기본 생성자를 가지고 있어야 한다.

-      3 ) 아래의 다수 어노테이션을 이용해서, 테스트 골격 코드를 생성

-      + @TestInstance / @TestMethodOrder : 테스트 클래스 선언부에 붙임

-      + @BeforeAll / @AfterAll : 1회성 전역적인 사전처리 메소드에 붙임

-      + @BeforeEach / @AfterEach : 매 테스트 메소드 수행 전, "사전처리" 메소드에 붙임

-      + @Disabled / @Test / @DisplayName / @Timeout / @Order : 테스트 메소드에 붙이는 어노테이션

-      4 ) 위 테스트 클래스에서 만드는 모든 Lifecyle 메소드나 Test 메소드의 return type "void"

 


[ 1. Driver SPY : jdbcURL 수정 ]

 

package org.zerock.myapp;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class JDBCSPYExample1 { // JDBC Driver SPY
	
	// Driver Spy를 사용하기 위해서는 jdbcUrl를 수정해야 한다.
	static final String jdbcUrl = "jdbc:log4jdbc:oracle:thin:@db0000000_high?TNS_ADMIN=C:/opt/OracleCloudWallet/ATP";
	// Driver Spy에 해당하는 log4jdbc를 추가해줘야 한다.
	
	static final String user = "hr";
	static final String pass = "Oracle000000";
	
	public static void main(String[] args) {
		
		String sql = "INSERT INTO departments(department_id, DEPARTMENT_NAME) VALUES(?, ?)";
		// 추가하는 sql문 
		// sql문은 ;을 포함해서는 안된다.
		
		try {
			
			Connection conn = DriverManager.getConnection(jdbcUrl, user, pass);
			conn.setAutoCommit(false);
			// Connection 객체는 기본적으로 Auto Commit을 해준다.
			// conn.setAutoCommit(false);로 자동 커밋을 해제시켜줄 수도 있다.
			
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, 900);
			pstmt.setString(2, "영화 900");
			
			int affectedLines = 0;
			
			try ( conn; pstmt; ){
				affectedLines = pstmt.executeUpdate(); // 영향을 받은 라인의 수를 알려준다.
				log.info("+ affectedLines : {}", affectedLines);
				// 하나만 생성되었기 때문에 affectedLines 값이 1로 나온다.
				
				conn.commit();
			} catch (SQLException e) {
				conn.rollback();
				throw e;
			} // try - with - resources
			
			// 비지니스 로직 수행
			
		} catch (Exception e) {
			e.printStackTrace();
		} // try - catch
		
	} // end main

} // end class

[ 2. Driver SPY 2 : jdbcURL 수정 ]

 

package org.zerock.myapp;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.zerock.myapp.domain.Employee;

import lombok.Cleanup;
import lombok.extern.log4j.Log4j2;

@Log4j2
public class JDBCSPYExample2 {
	
	// Driver Spy를 사용하기 위해서는 jdbcUrl를 수정해야 한다.
	static final String jdbcUrl = "jdbc:log4jdbc:oracle:thin:@db00000_high?TNS_ADMIN=C:/opt/OracleCloudWallet/ATP";
	// Driver Spy에 해당하는 log4jdbc를 추가해줘야 한다.
	
	static final String user = "hr";
	static final String pass = "Oracle00000";
	
	public static void main(String[] args) {
		
		try {
			
			Connection conn = DriverManager.getConnection(jdbcUrl, user, pass);
			
			String sql = new StringBuffer().
					append("SELECT employee_id, last_name, hire_date, salary, department_id ").
					append("FROM employees ").
					append("WHERE salary > ? ").
					append("ORDER BY salary DESC").toString(); // (****)
			
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, "7000");
			
			ResultSet rs = pstmt.executeQuery(); // 실행
			
			@Cleanup("clear")
			List<Employee> employees = new ArrayList<>();
			
			try ( conn; pstmt; rs; ){
				
				while ( rs.next() ) {
					
					String employeeId = rs.getString("EMPLOYEE_ID");
					String lastName = rs.getString("last_name");
					String hireDate = rs.getString("HIRE_DATE");
					String salary = rs.getString("SALARY");
					String departmentId = rs.getString("DEPARTMENT_ID");

					// 적절한 자료구조를 만들어 저장 - VO(Value Object)
					Employee emp = new Employee( employeeId, lastName, hireDate, salary, departmentId );
					
					employees.add(emp); // ArrayList에 원소 추가하기
					
				} // while
				
			} //try -with - resources ( try()안에 지정되어 있는 자원을 블록이 끝나면 자동으로 해제시켜준다. )
			
			employees.forEach( e -> log.info(e) ); // forEach(*****)
			
		} catch(SQLException e) {
			e.printStackTrace();
		} // try - catch ( try블록 내에서 발생한 예외를 catch에 지정해 주어 예외를 추적하게 한다. )
		
	} // main

} // end class

[ 3. JUnit 4.x대 Frame Work ]

 

package org.zerock.myapp;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Objects;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;

/**
 * JUnit 4.x 테스트 소스 골격 코드를 배우자!
 */

@Log4j2
@NoArgsConstructor
public class AppTest {
	
	//===============================================
	// @NoArgsConstructor로 자동으로 생성자 생성
	//===============================================
	
	private String jdbcUrl;
	private String user;
	private String pass;
	private Connection conn;
	
	//===============================================
	
//	@Before
	public void before() {
		log.trace("before() invoked.");
		
		// + 사전처리할 코드 ex. jdbcURL, DB 계정, DB 암호
		
		this.jdbcUrl = "jdbc:log4jdbc:oracle:thin:@db00000_high?TNS_ADMIN=C:/opt/OracleCloudWallet/ATP";
		this.user = "hr";
		this.pass = "Oracle000000";
		
	} // before
	
	//===============================================
	
//	@Test(timeout = 100)
	public void contextLoads1() throws SQLException {
		log.trace("contextLoads1() invoked.");
		
		conn = DriverManager.getConnection(jdbcUrl, user, pass);
	} // contextLoads
	
	// + @Test는 timeout 속성을 주어, 블록 내의 코드실행시간을 총 몇 밀리세컨드까지 기다릴지 정할 수 있다.
	// + 이때 준비시간은 제외된다.
	
	//===============================================
	
//	@Test
	public void contextLoads2() {
		log.trace("contextLoads2() invoked.");
	} // contextLoads2
	
	//===============================================
	
//	@After
	public void tearDown() throws SQLException {
		log.trace("tearDown() invoked.");
		
		// + 사후처리할 코드 ex. 자원 해제
		
		// 1번째 방법
		assert this.conn != null;
		
		// 2번째 방법
		Objects.requireNonNull(this.conn);
		
		// 3번째 방법
//		assertNotNull(this.conn);
		
		// 4번째 방법 ( 알려주는 것이 없기에 추천하지 않는다. )
		if(this.conn != null)
		
		conn.close();
		
	} // tearDown
	
	//===============================================
	
	// + @Befor / @Test / @After는 public이어야 한다.
	// + @Befor / @Test / @After는 매개변수가 없다.
	// + @Befor / @After는 사전처리와 사후처리가 없을 경우, 없앨 수 있다.
	// + @Test 메소드는 test가 이름 앞에 붙여야 했는데, 현재 버전에서는 붙이지 않아도 가능하다.
	// + @Test는 여러개 생성이 가능하다.
	// + 4.x 버전에서는 비포와 에프터가 매 테스트 메소드마다 초기화된다.
	
	//===============================================
	
} // end class

[ 4. JUnit 5.x대 Frame Work ] (****)

 

package org.zerock.myapp;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;

/**
 * JUnit 5.x 테스트 소스 골격 코드를 배우자! ( Stub Class )
 */

@Log4j2
@NoArgsConstructor
//==========================================================

@TestInstance(Lifecycle.PER_CLASS)
// @TestInstance는 라이프사이클을 지정해줘야 한다. (***)

//==========================================================

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
// @TestMethodOrder는 테스트 메소드가 수행되는 순서를 지정해 준다. (***)
// 속성으로 value 속성을 지정해 줘야 한다.

//==========================================================

public class AppTest2 {
	
	private String jdbcUrl;
	private String user;
	private String pass;
	private Connection conn;
	
	//==========================================================
	
	@BeforeAll
	void beforeAll() {
		log.trace("beforeAll() invoked.");
		
		this.jdbcUrl = "jdbc:log4jdbc:oracle:thin:@db000000_high?TNS_ADMIN=C:/opt/OracleCloudWallet/ATP";
		this.user = "hr";
		this.pass = "Oracle0000";
	} // beforeAll
	
	// + beforeAll과 eachAll은 전역적인 의미의 사전 / 사후 처리이기 때문에
	// + @Test 메소드가 여러개여도 1번씩만 진행이 된다.
	
	//==========================================================
	
	@BeforeEach
	void beforeEach() {
		log.trace("beforeEach() invoked.");
	} // beforeEach
	
	// + beforeEach와 afterEach는 매 테스트 메소드마다 사전 / 사후에 진행이 된다.
	
	//==========================================================
	
	@AfterAll
	void afterAll() {
		log.trace("afterAll() invoked.");
	} // afterAll
	
	@AfterEach
	void afterEach() throws SQLException {
		log.trace("afterEach() invoked.");	
		
		conn.close();
	} // afterEach
	
	//==========================================================
	
//	@Disabled
	@Test 
	@Order(2) // 실행되는 순서를 변경할 수 있다.
	@DisplayName("<<<< contextLoads1 >>>>") // 실행시킬때 나타나는 이름을 지정해 준다.
	@Timeout(value=2000, unit=TimeUnit.MILLISECONDS)
	void contextLoads1() throws SQLException {
		log.trace("contextLoads1() invoked.");
		
		conn = DriverManager.getConnection(jdbcUrl, user, pass);
		assertNotNull(conn);
	} // contextLoads1
	
	@Test 
	@Order(3) // 실행되는 순서를 변경할 수 있다.
	@DisplayName("<<<< contextLoads2 >>>>") // 실행시킬때 나타나는 이름을 지정해 준다.
	@Timeout(value=2000, unit=TimeUnit.MILLISECONDS)
	void contextLoads2() throws SQLException {
		log.trace("contextLoads2() invoked.");
		
		conn = DriverManager.getConnection(jdbcUrl, user, pass);
		assertNotNull(conn);
	} // contextLoads2
	
	//==========================================================
	
//	@Disabled // @Disabled는 비활성화시킨다.
	@Test 
	@Order(1) // 실행되는 순서를 변경할 수 있다.
	@DisplayName("<<<< contextLoads3 >>>>") // 실행시킬때 나타나는 이름을 지정해 준다.
	@Timeout(value=3000, unit=TimeUnit.MILLISECONDS)
	void contextLoads3() throws SQLException {
		log.trace("contextLoads3() invoked.");
		
		conn = DriverManager.getConnection(jdbcUrl, user, pass);
		assertNotNull(conn);
	} // contextLoads3
	
	
} // end class
728x90

'KH 정보교육원 [ Java ]' 카테고리의 다른 글

KH 85일차 - Servlet 2 (****)  (0) 2022.06.29
KH 84일차 - Servlet 생성 (****)  (0) 2022.06.28
KH 82일차 - WAS  (0) 2022.06.24
KH 81일차 - JDBC 2 (*****)  (0) 2022.06.23
KH 80일차 - JDBC 1 ( Target DB에 연결 )  (0) 2022.06.22
댓글
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
최근에 올라온 글
Total
Today
Yesterday
공지사항