스코프(Scope) 와 생명주기(Lifecycle)

SqlSessionFactoryBuilder

SqlSessionFactory 를 생성한 후 유지할 필요는 없다. 그러므로 SqlSessionFactoryBuilder 인스턴스의 가장 좋은 스코프는 메소드 스코프(메소드 지역변수)이다.

SqlSessionFactory

한번 만든뒤 SqlSessionFactory는 애플리케이션을 실행하는 동안 존재해야만 한다. 그래서 삭제하거나 재생성할 필요가 없다.가장 간단한 방법은 싱글턴 패턴이나 static 싱글턴 패턴을 사용하는 것이다.

singleton : 오로지 하나의 객체만 만들어지는 것을 보장

SqlSession

각각의 쓰레드는 자체적으로 SqlSession인스턴스를 가져야 한다.  = 어떤 동작을 할 때마다 sqlSession 인스턴스가 필요하다.

가장 좋은 스코프는 요청 또는 메소드 스코프이다. = 하나의 기능 단위, 혹은 메소드 스코프

 

싱글톤 패턴

우선 static 영역에 단 하나의 공간만을 할당 받는다. 그리고 try- catch 문 밖에 조건을 달아서 , 생성 후 처음에 null일 때만 설정 파일을 읽어와서 sqlSessionFactory를 만들게 한다. 

public class Template {
	
	public static SqlSessionFactory sqlSessionFactory; //static 영역에 단 하나의 공간만을 할당 받음

	public static SqlSession getSqlSession() {  
		// 어떤 기능이 시작될 때, service 레이어 쪽에서 호출을 해서 어떤 동작을 수행하는 동안 이 객체를 사용하고 끝나면 반환한다.
		
		if(sqlSessionFactory == null) { //처음엔 널이니까 그 때 
	
		try {
			
			String resource = "com/greedy/section01/xmlconfig/mybatis-config.xml";
			InputStream inputStream = Resources.getResourceAsStream(resource);

			sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 
			// 설정 파일을 읽어와서 그걸 기반으로 한 sqlsessionFactory를 만든다.
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
		SqlSession sqlSession = sqlSessionFactory.openSession(false);
		
		return sqlSession;
	
	}
	
}

 

오류: 기본 클래스 com.greedy.section01.xmlconfig.Application을(를) 로드하는 중 LinkageError가 발생했습니다.

java.lang.UnsupportedClassVersionError: -  has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0

해결방안: jdk 버전 맞춰주기

window - preferences - java - compiler - compiler compliance level 수정

 

 

'LECTURE > JDBC & Mybatis' 카테고리의 다른 글

Framework & My batis  (0) 2023.01.26
JDBC - tests 맛보기  (0) 2023.01.25
JDBC 1  (0) 2023.01.25

Framework

개발자가 소프트웨어를 개발함에 있어 코드를 구현하는 개발 시간을 줄이고, 코드의 재사용성을 증가 시키기 위해 일련의 클래스 묶음이나 뼈대, 틀을 제공하는 라이브러리를 구현해 놓은 것을 말한다.

  1. 개발자가 따라야 하는 가이드를 제공한다.
  2. 개발할 수 있는 범위가 정해져 있다.
  3. 개발자를 위한 다양한 도구, 플러그인을 지원한다.

장점

-개발 시간을 줄일 수 있다.

-정형화되어 있어 일정 수준 이상의 품질을 기대할 수 있다.

-유지 보수가 쉽다.

단점

-너무 의존하면 개발자들의 능력이 떨어져서 스스로 직접 개발하는 것이 어려워진다.

-습득에 걸리는 시간이 오래 걸린다.

 

종류

- 영속성 Framework

데이터가 계속해서 저장되기에 영속성

데이터의 저장, 조회, 변경, 삭제를 다루는 클래스 및 설정 파일들을 라이브러리화하여 구현한 프레 임워크

ex) Mybatis, Hibernate → JPA

- 자바 Framework

Java EE 를 통한 웹 어플리케이션 개발에 초점을 맞추어 필요한 요소들을 모듈화하여 제공하는 프 레임워크

ex) Spring Framework, 전자정부표준-Spring, Struts

- 화면 구현 Framework

Front-End를 보다 쉽게 구현할 수 있게 틀을 제공 하는 프레임워크

ex) BootStrap, Foundation, MDL

- 기능 및 지원 Framework

특정 기능이나 업무 수행에 도움을 줄 수 있는 기 능을 제공하는 프레임워크

ex) Log4j, JUnit 5, ANT

 

Mybatis

데이터의 입력, 조회, 수정, 삭제(CRUD)를 보다 편하게 하기 위해 xml 로 구조화한 Mapper 설정 파일을 통해서 JDBC를 구현한 영속성 프레임워크

-> 설정 방법을 학습한다. 

 

JAVA코드 버전

1.접속 정보(driver, url, user, password)를 변수로 선언한다.

2.DB 접속 환경 설정 -> mybatis jar 파일, ojdbc jar 파일을 라이브러리 classpath 설정

Environment environment =
			new Environment("dev"							//환경 정보 이름
						   , new JdbcTransactionFactory()	//트랜잭션 매니저의 종류 결정
						   , new PooledDataSource(DRIVER, URL, USER, PASSWORD));

트랜잭션 매니저 종류

1)JdbcTransactionFactory  : 수동 커밋

2)ManagedTransactionFactory : 자동 커밋 

데이터 소스 전달

1)PooledDataSource : Connection Pool 사용 -> 연결 객체를 만들어 놓으므로 속도가 빨라진다.

2)UnPooledDataSource : Connection Pool 미사용 

 

3.생성한 환경 설정 정보를 가지고 마이바티스 설정 객체 생성

Configuration configuration = new Configuration(environment);

 

* Mapper 인터페이스 작성 - my batis에서 수행하고자 하는 구문들

예시 - 현재 시간 출력

import org.apache.ibatis.annotations.Select;

public interface Mapper {
	
	@Select("SELECT SYSDATE FROM DUAL")
	java.util.Date selectSysdate();
	
}

 

4. 설정 객체에 매퍼 등록

configuration.addMapper(Mapper.class);

 

5. SqlSessionFactory 생성

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

1)SqlSessionFactory : SqlSession 객체를 생성하기 위한 팩토리 역할을 수행하는 인터페이스

2)SqlSessionFactoryBuilder : SqlSessionFactory 인터페이스 타입의 하위 구현 객체를 생성하기 위한 빌드 역할을 수행하는 클래스

3)build() : 설정에 대한 정보를 담고 있는 Configuration 타입의 객체 혹은 외부 설정 파일(xml)과 연결된 스트림을 매개변수로 전달하면 SqlSessionFactory 인터페이스 타입의 객체를 반환하는 메소드

 

6. sqlSession 생성 -> mapper에 있는 여러 구문들을 실행할 수 있다.

SqlSession sqlSession = sqlSessionFactory.openSession(false);

openSession() : SqlSession 인터페이스 타입의 객체를 반환하는 메소드, boolean 타입을 인자로 전달

false : Connection 인터페이스 타입 객체로 DML 수행 수 auto commit에 대한 옵션을 false로 지정(권장사항)

true: Connection 인터페이스 타입 객체로 DML 수행 수 auto commit에 대한 옵션을 true로 지정

 

getMapper() : Configuration에 등록 된 매퍼를 동일 타입에 대해 반환하는 메소드

		Mapper mapper = sqlSession.getMapper(Mapper.class);

		/* Mapper 인터페이스에 작성 된 메소드를 호출하여 쿼리 실행 */
		java.util.Date date = mapper.selectSysdate();
		
		System.out.println(date);
		
		/* close() : SqlSession 객체 반납 */
		sqlSession.close();
		
	}

 

xml 파일 버전

 

https://mybatis.org/mybatis-3/ko/getting-started.html

 

MyBatis – 마이바티스 3 | 시작하기

 

mybatis.org

 

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>            // xml 파일 공통 부분
<!DOCTYPE configuration                            // 이 문서의 정의 및 설정
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
  
<configuration>  // 설정
  <environments default="dev">  // 기본 환경
    <environment id="dev"> // 여러 환경이 있을 수 있다.
    <!-- JDBC와 MANAGED 둘 중 하나 선택 가능
    	 JDBC : 수동커밋, MANAGED : 자동커밋 -->
      <transactionManager type="JDBC"/> // 수동커밋
      <!-- POOLED와 UNPOOLED 선택 가능
      	   POOLED : 커넥션 풀 사용, UNPOOLED : 커넷션풀 미사용 -->
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

 

- mapper.xml 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
<mapper namespace="org.mybatis.example.BlogMapper"> 
  <select id="selectSysdate" resultType="java.util.Date">
    SELECT
    	   SYSDATE
      FROM DUAL
  </select>
</mapper>

 

public class Application {

	public static void main(String[] args) {
		
		String resource = "com/ ~~ mybatis-config.xml";
		
		try {
			
			InputStream inputStream = Resources.getResourceAsStream(resource); // resource를 stream 타입으로 읽어오겠다
			SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			
			SqlSession sqlSession = sqlSessionFactory.openSession(false);
			
            //sqlSession은 여러 기능을 가지고 있다. sysdate하나만 조회할 것이기에 .selectOne
			java.util.Date date = sqlSession.selectOne("mapper.selectSysdate"); // xml 파일의 namespace.select id
			System.out.println(date);
			
			sqlSession.close(); 
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

 

'LECTURE > JDBC & Mybatis' 카테고리의 다른 글

Mybatis Template  (0) 2023.01.26
JDBC - tests 맛보기  (0) 2023.01.25
JDBC 1  (0) 2023.01.25

테스트 시나리오

애플리케이션의 테스트 되어야 할 기능이나 특징을 한 문장으로 기술한 것

1. Calculator 인스턴스 생성이 잘 되는지 테스트

Calculator calc = new Calculator();

if(calc != null) {
 System.out.println("인스턴스 생성 성공");
 } else {
  System.out.println("인스턴스 생성 실패");
  }

 

2. sumTwoNumber 메소드가 정상 기능하는지 테스트

2-1. 4와 5를 전달하면 합계가 9가 되는지 확인

int result1 = calc.sumTwoNumber(4, 5);
		
		if(result1 == 9) {
			System.out.println("4와 5를 더하면 합계가 9인지 확인");
		} else {
			System.out.println("4와 5를 더하면 합계가 9인지 확인 실패");
		}

2-2. 6과 7을 전달하면 합계가 13이 되는지 확인

int result2 = calc.sumTwoNumber(6, 7);
		
		if(result2 == 13) {
			System.out.println("6와 7를 더하면 합계가 13인지 확인");
		} else {
			System.out.println("6와 7를 더하면 합계가 13인지 확인 실패");
		}

 

3. 위의 테스트 결과가 모두 통과되면 해당 클래스의 메소드는 신뢰성있는 메소드임을 확인

if(result1 == 9 && result2 == 13) {
			System.out.println("테스트 성공! 나는야 천재 개발자~~");
		} else {
			System.out.println("테스트 실패! 메소드를 다시 확인해주세요...");
		}

 

 

프레임워크를 이용하여 테스트 코드를 작성

테스트 클래스명으로 테스트할 클래스명에 Tests를 붙이는 게 보편적이다.

단위 테스트(unit test) 

한 가지 기능(함수)마다 일을 잘 수행하는지 확인하며 특정 모듈이 의도된대로 정확히 작동하는지 검증하는 절치이다. 연관 컴포넌트가 개발되지 않더라도 기능별 개발이 완료된 것을 증명할 수 있다. 

자바에서는 junit을 활용한다.

 

JUnit 추가 방법 : project의 propertise - java - build path - add library - JUnit 5 추가

 

JUnit 5 annotiation

@BeforeAll : 모든 @Test 메소드 실행 전에 한번만 수행한다.

@BeforeEach : @Test 메소드 실행 전에 매번 수행한다.

@BeforeEach
	public void setup() {
		System.out.println("calculator 인스턴스 생성");
		calc = new Calculator();

@Test : 테스트하고 싶은 단위별로 붙여서 메소드를 만든다.

import 할 때 더 최신버전 코드인 jupiter 패키지를 선택한다.

테스트 메소드 같은 경우 배포용이 아니기 때문에 알아보기 좋게 한글을 섞어서 적는 경우가 종종 있다.

@Test
	public void testSumTwoNumber_4와_5를_전달하면_합계가_9가_계산되는지_확인() {
		System.out.println("2-1 테스트 동작");
		int result = calc.sumTwoNumber(4, 5);
		
		assertEquals(9, result);
	}

1) 테스트 메소드를 실행하여 성공 확인

2) 틀렸을 경우 확인

 

	@Test
	@Disabled	// 테스트 하고 싶지 않은 경우 무시하도록 작성하는 annotiaion
	public void testSumTwoNumber_6과_7을_전달하면_합계가_13이_되는지_확인() {
		System.out.println("2-2 테스트 동작");
		int result = calc.sumTwoNumber(6, 7);
		
		assertEquals(13, result, 1); // 세번째 인자는 오차범위. 1까지는 오차범위를 허용하겠다.
	}

 

테스트 코드를 확인하는 assert 메소드들

assertArrayEquals(a,b) : 배열 a와 b가 일치함을 확인
assertEquals(a,b) : 객체 a와 b의 값이 일치함을 확인
assertSame(a,b) : 객체 a와 b가 같은 객체임을 확인
assertTrue(a) : a가 참인지 확인
assertNotNull(a) : a 객체가 null이 아님을 확인 

 

DAOTests

public class OrderDAOTests {
	
    //orderDAO객체를 필드에 선언해야 한다.
	private OrderDAO orderDAO;
	private Connection conn;
	private OrderDTO order;
	
   
	@BeforeEach
	public void setup() {
		orderDAO = new OrderDAO();  // test를 위한 객체는 test코드를 준비할 수 있는 별도의 setup메소드를 만들어서 처리한다. 
		conn = getConnection();  //select 카테고리는 db와의 연결, setup에선 Connection객체도 미리 만들어야 한다.
		
		order = new OrderDTO();
		order.setDate("23/01/25");
		order.setTime("11:35:20");
		order.setTotalOrderPrice(30000);
	}
	
	@Test
	public void testSelectAllCategory() {
		List<CategoryDTO> categoryList = orderDAO.selectAllCategory(conn); //생성 위해 conn전달
		
		assertNotNull(categoryList);  //null인지 확인
		for(CategoryDTO category : categoryList) {  //구체적인 정보는 출력
			System.out.println(category);
		}
	}
	
	@Test
	public void testInsertOrder() {
		int result = orderDAO.insertOrder(conn, order);
        /* orderDTO는 사용자가 입력한 값에 따라 수행되기 때문에 여기서 생성되지 않으므로 
        가데이터, order에 대한 객체를 하나 만들어서 사용한다. */
		
		assertEquals(1, result);
	}

}

 

 

 

 

'LECTURE > JDBC & Mybatis' 카테고리의 다른 글

Mybatis Template  (0) 2023.01.26
Framework & My batis  (0) 2023.01.26
JDBC 1  (0) 2023.01.25

JDBC(Java DataBase Connectivity)란?

자바에서 데이터베이스에 접근할 수 있게 해주는 Programming API

JDBC 사용 클래스

- DriverManager

데이터 원본에 JDBC드라이버를 통하여 커넥션을 만드는 역할

Class.forName() 메소드를 통해 싱성되며 반드시 예외처리를 해야 함

직접 인스턴스 생성이 불가능하고 getConnection() 메소드를 사용하여 인스턴스 생성 가능

- Connection

특정 데이터 원본과 연결 된 커넥션을 나타냄

Statement 인스턴스를 생성할 때도 Connection 인스턴스를 사용하여 createStatement() 메소드를 호출하여 생성

SQL 문장을 실행시키기 전에 우선 Connecton 인스턴스가 있어야 함

- Statement

Connection 클래스의 createStatement() 메소드를 호출하여 얻어짐

생성된 Statement 인스턴스로 SQL 질의문을 String에 담에 인자로 전달하여 executeQuery() 메소드를 호출하여 SQL 질의 수행

try {
	String query = "SELECT ID, LAST_NAME FROM EMP";
        stmt = conn.createStatement();
        rset = stmt.executeQuery(query);
 } catch (SQLException e) {
 			e.printStackTrace();
 }

 

- preparedStatement

Connection 클래스의 preparedStatement() 메소드를 사용하여 인스턴스 생성

SQL 질의문을 위치홀더 (placeholder)인 ?로 표현되는 String으로 정의

PreparedStatement는 위치홀더라는 개념에 해당되는 인수가 많아서 특정 값만 바꾸어 여러 번 실행해야 할 때 유용

(Statement는 SQL문장을 매번 컴파일 하지만 PreparedStatement는 한번만 컴파일하므로 실행 속도가 빠름)

try {
	String query = "INSERT INTO MEMBER VALUES(?,?)";
	pstmt = conn.preparedStatement(query);
	pstmt.setString(1, id);
	pstmt.setString(2, password);
} catch (SQLException e) {
	e.printStackTrace();
}

 

- ResultSet

SELECT 문을 사용한 질의 성공 시 ResultSet을 반환

SQL 질의문에 의해 생성된 테이블을 담고 있으며 커서(cursor)로 특정 행에 대한 참조 조작

 

JDBC 코딩 절차

- DriverManager에 해당 DBMS Driver 등록

public static void main(String[] args) {
		
		/* DB 접속을 위한 Connection 인스턴스 생성
		 * 나중에 finally 블럭에서 사용하기 위해 try 블럭 밖에 미리 레퍼런스 변수를 선언함 */
		Connection conn = null;
		
		try {
			/* 1. 사용할 드라이버 등록 */
			Class.forName("oracle.jdbc.driver.OracleDriver");

 

- 해당 Driver로부터 Connection instance획득

		/* 2. DriverManager를 이용해 Connection 객체 생성 */
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "C##EMPLOYEE", "EMPLOYEE");
			
			System.out.println(conn);
			
		} catch (ClassNotFoundException e) {
			// 드라이버 클래스명에 오타가 있거나 라이브러리가 추가 되지 않았을 경우
			// 해당 클래스를 찾지 못했다는 exception 발생 가능
			e.printStackTrace();
		} catch (SQLException e) {
			// url, user, password 등이 올바르게 입력되지 않아서 연결 할 수 없으면 
			// exception 발생 가능
			e.printStackTrace();
		} finally {
			if(conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}

 

- 해당 Driver로부터 Connection instance 획득

	/* 1. Connection 생성 */
		Connection conn = getConnection();
		
		Statement stmt = null;
		ResultSet rset = null;
		
		try {
			/* 2. Statement 생성 */
			stmt = conn.createStatement();
			
			String empId = "207";
			String query = "SELECT EMP_ID, EMP_NAME FROM EMPLOYEE WHERE EMP_ID = '" + empId + "'";
			System.out.println(query);
			
			/* 3. executeQuery()로 쿼리문 실행하고 결과를 ResultSet으로 반환 */
			rset = stmt.executeQuery(query);
			
			/* 4. ResultSet에 담긴 결과 값을 컬럼 이름을 이용해서 꺼내오기 */
			if(rset.next()) {
				System.out.println(rset.getString(1) + ", " + rset.getString(2));
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			/* 5. 사용한 자원 반납 */
			close(rset);
			close(stmt);
			close(conn);
		}

- Statement에서 제공하는 메소드를 사용하여 SQL문 실행

 

		Connection conn = getConnection();

		PreparedStatement pstmt = null;
		ResultSet rset = null;
		
		try {
			
			/* PreparedStatement 객체는 생성 시에 sql 구문을 미리 전달한다. */
			pstmt = conn.prepareStatement("SELECT EMP_ID, EMP_NAME FROM EMPLOYEE");
			/* 쿼리 실행을 요청할 때는 sql 구문을 전달하지 않는다. */
			rset = pstmt.executeQuery();
			
			while(rset.next()) {
				System.out.println(rset.getString("EMP_ID") + ", " + rset.getString("EMP_NAME"));
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			close(rset);
			close(pstmt);
			close(conn);
		}

'LECTURE > JDBC & Mybatis' 카테고리의 다른 글

Mybatis Template  (0) 2023.01.26
Framework & My batis  (0) 2023.01.26
JDBC - tests 맛보기  (0) 2023.01.25

+ Recent posts