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
개발자가 소프트웨어를 개발함에 있어 코드를 구현하는 개발 시간을 줄이고, 코드의 재사용성을 증가 시키기 위해 일련의 클래스 묶음이나 뼈대, 틀을 제공하는 라이브러리를 구현해 놓은 것을 말한다.
개발자가 따라야 하는 가이드를 제공한다.
개발할 수 있는 범위가 정해져 있다.
개발자를 위한 다양한 도구, 플러그인을 지원한다.
장점
-개발 시간을 줄일 수 있다.
-정형화되어 있어 일정 수준 이상의 품질을 기대할 수 있다.
-유지 보수가 쉽다.
단점
-너무 의존하면 개발자들의 능력이 떨어져서 스스로 직접 개발하는 것이 어려워진다.
-습득에 걸리는 시간이 오래 걸린다.
종류
- 영속성 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 인터페이스 타입의 객체를 반환하는 메소드
<?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>
한 가지 기능(함수)마다 일을 잘 수행하는지 확인하며 특정 모듈이 의도된대로 정확히 작동하는지 검증하는 절치이다. 연관 컴포넌트가 개발되지 않더라도 기능별 개발이 완료된 것을 증명할 수 있다.
자바에서는 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);
}
}
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);
}