본문 바로가기

수업 정리

62일차 수업 정리(Spring - Transaction, Hibernate, MyBatis)

**Spring에서의 Transaction 사용

1. Spring에서의 Transaction 사용을 위한 설정

    => TransactionManager 클래스의 bean을 생성

    => 연동하는 프레임 워크에 따라 다르게 생성

    => Spring JDBC와 MyBatis를 사용할 때는 동일한 방식으로 생성

        - DataSourceTransactionManager 클래스의 bean 생성, 이 때 dataSource 프로퍼티에 DataSource 빈 주입

    => Hibernate는 위와는 다른 방식으로 생성

        - Hibernate는 트랜잭션 사용이 필수

 

2. 적용

    => 데이터베이스 작업을 수행하는 메소드 위에 @Transactional을 추가하는 방법

    => xml 파일에 tx:advice 와 tx:method 태그를 이용하여 설정하는 방식

 

3. 트랜잭션 적용

    => Service에 적용

 

**트랜잭션 실습

1. Simple Spring Maven Project 생성

 

2. 필요한 의존성 라이브러리를 pom.xml 파일에 작성

    => Oracle, Spring-JDBC

  1) Oracle을 위한 Repository 생성

<repositories>
	<repository>
		<id>oracle</id>
		<name>ORACLE JDBC Repository</name>
		<url>http://maven.jahia.org/maven2</url>
	</repository>
</repositories>

  2) Oracle, Spring의 의존성을 dependencies에 추가

<!-- 오라클 -->
<dependency>
	<groupId>com.oracle</groupId>
	<artifactId>ojdbc7</artifactId>
	<version>12.1.0.2</version>
</dependency>

<!-- 스프링에서 데이터베이스 사용을 위한 의존성 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>${spring-framework.version}</version>
</dependency>

 

3. SpringBeanConfiguration 파일생성, DB 접속정보를 저장하는 DataSource 클래스의 Bean을 추가하는 코드를 작성

    => Spring MVC Project이면 파일을 생성할 필요없고 제공되는 파일에 코드를 작성

<!-- Oracle -->
<bean 
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
	id="dataSource">
	<property name="driverClassName" 
		value="oracle.jdbc.driver.OracleDriver"/>
	<property name="url"
value="jdbc:oracle:thin:@192.168.0.200:1521:xe"/>
	<property name="username" value="system"/>
	<property name="password" value="********" />
</bean>

 

4. main메소드를 소유한 클래스를 src(src/main/java) 디렉토리에 생성하고 데이터베이스 접속을 테스트

public static void main(String[] args) {
	try {
		//스프링 설정 파일의 경로를 설정
		GenericXmlApplicationContext context = 
				new GenericXmlApplicationContext("applicationContext.xml");
		
		//데이터베이스 접속 정보 가져오기
		DataSource ds = context.getBean(DataSource.class);
		Connection con = ds.getConnection();
		System.out.println(con);
        
		context.close();
	}catch (Exception e) {
		System.out.println(e.getMessage());
		e.printStackTrace();
	}
}

 

5. 트랜잭션 처리를 테스트할 DAO 클래스 생성하고 작성

    => hibernate.dao.TransactionDAO

@Repository
public class TransactionDAO {
	//Spring JDBC 에서 제공하는 데이터 삽입 클래스의 변수
	@Autowired
	private SimpleJdbcInsert template;
	
	public void insert() {
		//테이블 이름 설정
		template.withTableName("GOODS");
		//삽입할 데이터 생성
		Map<String, Object> map = 
			new HashMap<String, Object>();
		map.put("code", 20);
		map.put("name", "고구마");
		map.put("regdate", new Date());
		
		//동일한 데이터를 2번 삽입하므로 2번째 삽입할 때
		//기본키 중복 예외 발생
		template.execute(map);
		template.execute(map);
	}
}

 

6. applicationContext.xml 파일에 SimpleJdbcInsert 클래스의 bean을 생성해주는 코드와 DAO클래스의 bean을 자동생성해주는 코드를 작성

  1) context 네임스페이스 추가

 

  2) bean을 자동생성하기 위한 패키지 등록

<!-- SimpleJdbcInsert bean -->
<bean id="template"
	class="org.springframework.jdbc.core.simple.SimpleJdbcInsert">
	<constructor-arg>
		<ref bean="dataSource" />
	</constructor-arg>
</bean>

 

  3) bean을 자동 생성하기 위한 패키지를 설정

<!-- bean을 자동 생성하기 위한 패키지 등록 -->
<context:annotation-config/>
<context:component-scan base-package="hibernate"/>

 

7. main 메소드를 소유한 클래스에서 DAO 클래스의 bean을 가져와서 메소드를 호출하는 코드를 작성하고 실행

//DAO 인스턴스를 가져와서 삽입하는 메소드 호출
TransactionDAO dao = context.getBean(TransactionDAO.class);
dao.insert();

 

8. 결과 확인

    => 트랜잭션을 적용하지 않았기 때문에 첫번째 삽입문장은 성공, 두번째 삽입문장은 실패

        - Auto Commit이 적용되어 첫번째 삽입문장은 데이터베이스에 반영

 

**트랜잭션 적용

1. applicationContext.xml 파일에 tx 네임스페이스를 추가

 

2. applicationContext.xml 파일에 TransactionManager 클래스의 bean을 생성하여 등록하는 코드 추가

    => 데이터베이스 연동 프레임워크에 따라 달라짐

<!-- Spring JDBC나 MyBatis 에서의 트랜잭션처리를 위한 클래스의 bean -->
<bean id="transactionManager" 
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

 

3. DAO 메소드 상단에 @Transactional을 추가하고 실행

 

4. main 메소드를 실행하고 결과 확인

 

5. @Transactional이 적용된 메소드에서 예외 발생시 모든 DB작업이 취소됨

 

**ORM(Object Relationshop Mapper)

    => 관계형 데이터베이스의 테이블의 하나의 행을 하나의 객체와 매핑시켜 사용하는 데이터베이스 프레임워크

        - 이때 사용되는 DTO 클래스나 Map 클래스로부터 만들어진 객체

    => 최근의 프로그래밍 언어에서는 데이터베이스 연동을 대부분 ORM방식을 이용하도록 권장

    => Java에서는 JPA, Apple의 Core Data, MS의 LINQ 등이 ORM 사용하는 대표적인 경우

    => SQL을 사용해도 되고, 자신들만의 문법으로 만들어진 쿼리문을 사용하기도 함

 

**Hibernate

    => Java ORM Framework

    => Java 진영에서 나중에 JPA라고하는 ORM 표준 Spec을 발표하고 실제 구현은 대부분 Hibernate로 함

1. SQL Mapper인 MyBatis(iBatis)와의 비교

    => Hibernate는 데이터베이스 구조를 알아야하기때문에 학습하는 것이 어렵지만 성능이 우수(Solution 개발에 이용)

        - 데이터베이스를 새로 구축하는 경우 종종 이용

    => MyBatis는 학습이 쉽지만 성능은 Hibernate에 비해 떨어질 가능성이 높아 SI에 주로 이용됨

        - 기존의 데이터베이스를 활용하는 경우에 종종 이용

 

2. Hibernate 구성요소

  1) Configuration : 데이터베이스 테이블과 클래스 매핑 설정

  2) SessionFactory : Configuration를 이용하여 생성하는 객체로 Session객체를 생성하여 DB사용(Connection 개념)

  3) Session : SessionFactory로 부터 만들어지는 객체로 실제 DB작업을 수행하며 가벼운 객체(PreparedStatement 개념)

    => 가볍기 때문에 필요할 때 생성하고 사용이 끝나면 소멸

  4) Transaction

  5) Query : SQL 또는 HQL(하이버네이트에서만 사용하는 쿼리)

    => SQL : 관계형 데이터베이스마다 문법이 다름

    => HQL : 모든 관계형 데이터베이스에 동일한 문법을 적용

    => 최근에는 서비스의 변화가 심하기 때문에 확장성을 고려하여 프로그래밍하는 것을 권장

  6) Criteria : Query문법과는 다른 형태의 질의중 하나로 Query를 직접 사용하지 않고 메소드를 호출하는 형태로 생성

 

3. 자료형 매핑

  1) Number(숫자), int : int, java.lang.Integer

  2) number(숫자1, 숫자2), float, double : double, java.lang.Double

  3) boolean, yes/no, true/false : boolean, java.lang.Boolean

  4) Date : java.sql.Date, java.util.Date

  5) Time : java.sql.Time, java.util.Date

  6) Timestamp : java.sql.Timestamp

  7) char, varchar(varchar2), clob, text, String : java.lang.String

  8) blob : java.sql.Blob

    => 모든 자료형은 java.lang.String과 매핑이 가능

        - 실제로는 String으로 가져와서 형변환 하는 구조

 

4. 하이버네이트 매핑 파일 작성 방법

    => id를 primary key와 매핑, property를 이용하여 나머지 컬럼을 매핑

 

    => 컬럼명 작성시 Oracle은 대문자 MySQL은 소문자를 사용

        - DTO 클래스가 아니라 Map 연동시 중요

    => Sequence를 사용하는 경우

 

5. SessionFactory를 생성하기 위한 bean 설정

 

6. 질의

  1) SQL

  2) HQL

  3) Criteria

 

7. Session의 메소드

  1) save(Object object) : 데이터 삽입

  2) update(Object object) : 기본키 컬럼을 가지고 where절을 만들어 나머지 수정

  3) delete(Object object) : 기본키 컬럼을 가지고 삭제

  4) get(class 이름, 조건) : 조건에 맞는 데이터를 찾아오는 메소드

 

  5) createSQLQuery(String sql) : SQL 실행 가능한 객체를 생성

 

8. 필요 의존성

    => 데이터베이스, Spring-jdbc, spring-orm, hibernate

 

**Hibernate 실습

1. 연동할 테이블을 생성 - Oracle

 

2. 프로젝트에 의존성을 설정

    => 연동할 데이터베이스, spring-jdbc, spring-orm, hibernate

  1) hibernate 버전 설정 - properties에서 변경

<!-- Hibernate / JPA -->
<hibernate.version>5.4.2.Final</hibernate.version>

 

  2) 사용할 데이터의 의존성 추가

    => oracle은 repositories 와 dependency를 같이 추가
    =>mysql은 dependency 만 추가

<repositories>
	<repository>
		<id>oracle</id>
		<name>ORACLE JDBC Repository</name>
		<url>http://maven.jahia.org/maven2</url>
	</repository>
</repositories>

<!-- 오라클 -->
<dependency>
	<groupId>com.oracle</groupId>
	<artifactId>ojdbc7</artifactId>
	<version>12.1.0.2</version>
</dependency>

 

  3) spring-jdbc 의존성 설정

<!-- 스프링에서 데이터베이스 사용을 위한 의존성 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>${spring-framework.version}</version>
</dependency>

  4) spring-orm 의존성 설정

<!-- 스프링에서 JPA(Hibernate)를 사용하는 경우 필요한 의존성-->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-orm</artifactId>
	<version>${spring-framework.version}</version>
</dependency>

  5) hibernate는 Spring project에서는 기본적으로 의존성이 설정되어 있어 앞에서처럼 버전만 변경하면 됨

 

3. Spring 설정 파일에 접속할 데이터베이스 정보를 저장할 DataSource Bean을 생성하고 테스트

    => applicationContext.xml 파일에 작성

<!-- Oracle -->
<bean 
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
	id="dataSource">
	<property name="driverClassName" 
		value="oracle.jdbc.driver.OracleDriver"/>
	<property name="url"
		value="jdbc:oracle:thin:@192.168.0.200:1521:xe"/>
	<property name="username" value="system"/>
	<property name="password" value="********" />
</bean>

 

4. 테이블과 매핑할 DTO 클래스를 생성

    => 이름은 하이버네이트 설정파일에서 매핑하기 때문에 자료형에 유의하면서 생성

    => hibernate.domain.item

    => 내 소스에는 @Data로 처리

 

5. 하이버네이트 설정 파일을 생성

    => 테이블과 클래스를 매핑

    => dao.item.hbm.xml(하이버네이트 매핑파일)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="hibernate.domain">
	<class name="item" table="item">
		<id name="code" column="code"></id>
		<property name="name" column="name" />
		<property name="manufacture" column="manufacture" />
		<property name="price" column="price" />
		<property name="builtdate" column="builtdate" />
	</class>
</hibernate-mapping>

 

6. Spring 설정파일에 hibernate 사용을 위한 bean을 설정

    => context와 tx 네임스페이스를 추가

<!-- bean을 자동 생성하기 위한 패키지 등록 -->
<context:annotation-config/>
<context:component-scan base-package="hibernate"/>
	
<!-- 하이버네이트 사용을 위한 bean 설정 -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
	<!-- 접속할 데이터베이스 정보 -->
	<property name="dataSource" ref="dataSource" />
	<!-- 매핑 파일 정보 설정-->
	<property name="mappingResources">
		<list>
			<value>dao/item.hbm.xml</value>
		</list>
	</property>
	<!-- 데이터베이스 종류 -->
	<property name="hibernateProperties">
		<value>
		hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
		</value>
	</property>
</bean>	
	
<!-- 하이버네이트 트랜잭션 매니저 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean 
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
	
<!-- 트랜잭션 처리를 어노테이션으로 하도록 설정 -->
<tx:annotation-driven/>

 

7. main 메소드에서 테스트

     => SessionFactory를 주입받아서 출력

//하이버네이트 설정 확인
SessionFactory sessionFactory = context.getBean(SessionFactory.class);
System.out.println(sessionFactory);

    => 설정파일의 경로가 틀리거나 하면 예외가 발생

 

8. Hibernate 사용하는 DAO 클래스를 생성해서 작업을 수행하는 메소드를 작성

    => SessionFactory를 주입받아서 사용

    => Hibernate를 사용할 때는 반드시 트랜잭션을 사용해야 함

    => Service에 트랜잭션을 적용

package hibernate.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import hibernate.domain.Item;

@Repository
public class ItemDAO {
	@Autowired
	//하이버 네이트 사용 객체
	private SessionFactory sessionFactory;
	
	//데이터 삽입
	@Transactional
	public void insert(int code, String name, String manufacture, int price) {
		Item item = new Item();
		item.setCode(code);
		item.setName(name);
		item.setManufacture(manufacture);
		item.setPrice(price);
		item.setBuiltdate(new Date());
		
		//데이터 삽입
		sessionFactory.getCurrentSession().save(item);
	}
	
	//데이터 수정
	//기본키를 조건으로 해서 나머지 항목을 수정
	//없는 기본키를 대입하면 아무일도 하지 않음
	@Transactional
	public void update() {
		Item item = new Item();
		item.setCode(3);
		item.setName("포도");
		item.setManufacture("음성");
		item.setPrice(2000);
		item.setBuiltdate(new Date());
		
		//데이터 삽입
		sessionFactory.getCurrentSession().update(item);
	}
	
	//데이터 삭제
	//기본키 항목외 아무것도 필요 없음
	//기본키를 조건으로 삭제
	@Transactional
	public void delete() {
		Item item = new Item();
		item.setCode(3);
			
		//데이터 삽입
		sessionFactory.getCurrentSession().delete(item);
	}
	
	//전체 데이터 가져오기
	@Transactional
	public void list() {
		//List<Item> list = (List<Item>)sessionFactory.getCurrentSession().createCriteria(Item.class).list();
		List<Item> list = (List<Item>)sessionFactory.getCurrentSession().createSQLQuery("select * from item").addEntity(Item.class).list();
		for(Item item : list)
			System.out.println(item);
	}
	
	//기본키를 가지고 데이터 1개 가져오기
	@Transactional
	public void getItem() {
		//Criteria 사용
		Item item = sessionFactory.getCurrentSession().get(Item.class, 1);
		System.out.println(item);
	}
}

 

9. main 메소드에서 확인

 

 

**Oracle로 작업한 것을 MySQL로 변환

1. MySQL에 테이블 생성

 

2. pom.xml 파일에 MySQL 의존성을 추가

<!-- MySQL -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

3. DataSource 변경

<!-- MySQL 사용을 위한 설정 -->
<bean
	class="org.springframework.jdbc.datasource.DriverManagerDataSource"
	id="dataSource">
	<!-- 데이터 베이스 종류 : MySQL -->
	<property name="driverClassName"
		value="com.mysql.jdbc.Driver" />
	<!-- 연결할 데이터베이스 URL -->
	<property name="url"
		value="jdbc:mysql://localhost:3306/myproject?useUnicode=true&amp;characterEncoding=utf8" />
	<property name="username" value="root" />
	<property name="password" value="900826" />
</bean>

 

4. Framework 별로 할일

  1) MyBatis : mapper 파일에서 쿼리를 수정

 

  2) Hibernate : Spring 설정 파일에서 데이터베이스 종류만 변경하면 됨

<!-- 데이터베이스 종류 -->
<property name="hibernateProperties">
	<value>
		<!-- 오라클
		hibernate.dialect=org.hibernate.dialect.Oracle10gDialect -->
		<!-- MySQL -->
		hibernate.dialect=org.hibernate.dialect.MySQLDialect
	</value>
</property>

 

**DataBase의 언어 또는 기능

1. 언어

    => DDL : Create, Alter, Drop, Truncate

    => DML

        - DQL : Select

        - DML : Insert, Delete, Update - Transaction 처리 대상

    => DCL

        - DCL : Grant, Revoke

        - TCL : Commit, Rollback, SavePoint

 

2. 기능

    => 정의 기능 : DBA(분석 및 설계)의 작업

    => 조작 기능 : Programming Developer 또는 User

    => 제어 기능 : DBA(운영 - System Management)의 작업

 

**DataBase 연동

1. JDK가 제공하는 JDBC 만을 이용해서 연동

 

2. Java Web Application을 만들며 DB 접속 정보를 context.xml 파일에 작성, web.xml이 정보를 읽고 사용

    => Connection Pool을 이용하는 방법

    => 연결과 해제를 직접하지 않고 미리 만들어진 Connection을 빌려쓰는 개념

 

3. Spring-MyBatis를 이용

    => SQL을 xml이나 인터페이스에 작성하고 자바코드에서 SQL을 호출하여 사용

    => SQL과 자바코드가 분리

    => 작업이 쉽고, DB 연결이나 파라미터 매핑, 결과 매핑 등의 작업이 필요없어 개발시간이 단축됨

    => SI에서 주로 이용

 

4. Spring-Hibernate를 이용

    => SQL 없이 테이블과 클래스(인스턴스)를 매핑시켜 사용하는 방식

    => 데이터베이스가 변경되더라도 수정할 부분이 거의 없음

    => MyBatis보다 성능이 좋은 경우가 많음

    => 데이터베이스에 대한 이해가 필요하므로 앞의 방법들보다 어려울 수 있음

 

**소프트웨어 개발 과정

1. 분석(요구사항 정의 - 무엇을 어떻게 언제까지 할 것인지) 

 

2. 설계

  1) 개념적 설계 : 도식화

  2) 논리적 설계 : 컴퓨터가 이해할 수 있도록 변환(자료형 등)

  3) 물리적 설계 : 실제 구현할 내용을 설계(create 등)

 

    - 저장소

    - 서버 애플리케이션

    - 클라이언트 애플리케이션(PC Application, Web Browser, Android, iOS 등)

 

    => 저장소 <-> 서버 애플리케이션 <-> 클라이언트 애플리케이션

    => 클라이언트 애플리케이션은 로컬 저장소에는 직접 연동하지만 외부 저장소에는 직접연동하지 않음

 

3. 구현

  1) 저장소 구현

  2) 저장소와 서버 애플리케이션 연동

  3) 서버 애플리케이션과 클라이언트 애플리케이션이 연동

    => 1번, 2번 작업중에 View는 동시 제작이 가능

    => 서버 애플리케이션의 구현 방법은 Socket Server를 만드는 방법과 Web Server를 만드는 방법이 있음

        - 성능은 Socket Server가 좋으나 구현이 어렵고, Web Server는 구현이 쉽지만 성능이 떨어짐

    => 여러종류의 클라이언트에 각각의 서버를 구현하지 않고 서비스하려면 뷰가 아닌 데이터를 만들어 넘겨주어야 함

        - 이러한 방식을 Restful or REST API 라고 함

        - 이때 가장 많이 사용되는 데이터 포맷이 json 

    => 서버 애플리케이션 구현시 가장 중요한 것은 사용자가 요청시 저장소에 요청을 수행하고 결과를 넘겨주는 것

    => 클라이언트에서 가장 중요한 것은 서버의 데이터를 가져와서 원하는 형태로 가공(Parsing) 및 보여주는 것

        - 이때 오프라인 상태에서 보여줄수 있도록 할 것인지 그리고 트래픽을 얼마나 줄일것인지 여부를 고민해야 함

 

4. 테스트

  1) 디버깅 : White box, Black box 테스트

  2) 검증 : 요구사항과 일치하는 지 테스트, 알파 테스트, 베타 테스트

 

5. 인수나 이행, 배포

 

6. 유지보수