DAO
클래스를 없애자.DAO
를 인터페이스화 시키고, 이를 Spring Framework에게 mapper.xml
파일과 연동하도록 설정하여 SQL문과 Application을 분리했다.resultMap
을 통해 VO
를 조립할 수 있습니다.JOIN
을 가능하게 할 수 있습니다. ( 2중, 3중.. N중 조인 )@Query
혹은 createQuery()
를 직접 사용해야할 수도 있다.MyBatis
는 DAO
를 없앴다면, Hibernate
는 VO
를 없앤다.hibernate.cfg.xml
) = mybatis-context.xml
Entity
파일 ( UserVO.java
)Hibernate
의 SessionFactory
설정에는 setter
로 가득차있다.SessionFactory Bean
설정 및 조립 시, Spring Context
가 수정자 주입을 해준다.Hibernate
의 방언(Dialect)Oracle10gDialect
, Oracle11gDialect
와 같이 방언 설정 가능hibernate.hbm2ddl.auto
: 스키마 자동 생성 ( CREATE, CREATE-DROP, NONE .. )Java의 Date 타입과 DB의 TIMESTAMP 타입은 다르게,
JPA Entity 컬럼 위에 Temporal.TIMESTAMP
이렇게 넣어주어야 한다.
정산/결제 쪽에서는 Date
타입 자체가 중요하지만,
일반적인 서비스에서는 날짜는 보여주기 용도이기에, String
으로 담아도 된다.
MyBatis는 Mapper를 사용한 인터페이스로 DB 테이블에 접근하여 사용하지만, Hibernate는 SQL 스키마를 자동 생성하고 객체에 대한 접근으로 DB 테이블에 접근합니다. ( DDL, DML의 자동화 )
Hibernate는 1차 캐시와 2차 캐시를 사용하여 DB 접근 횟수를 줄일 수 있습니다.
JpaRepository
를 상속하여 I/F화 시켜서 DAO 클래스가 없어진 것은 Spring Data JPA
의 도움을 받아 가능합니다.
SessionFactory
로 부터 Session을 받아와서 쿼리를 수행합니다.
@Autowired
priavte SessionFactory sessionFactory;
...
@Transactional
public Lit<UserEntity> getAll() {
// Hibernate Criteria API 사용 방식 - 컴파일 시점에 에러 검사
// return sessionFactory.getCurrentSession()
// .createCriteria(UserEntity.class).list();
// HQL (Hibernate Query Language) 사용 방식 - 런타임 시점에 검사
return sessionFactory.getCurrentSession()
.createQuery("from UserEntity").list();
}
<!-- JPA API -->
<dependency>
<groupId> javax.persistence </groupId>
<artifactId> javax.persistence-api </artifactId>
<version>2.2</version>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId> org.springframework.data</groupId>
<artifactId> spring-data-jpa </artifactId>
<version>1.7.0.RELEASE</version>
</dependency>
pom.xml 상태
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
">
<!-- ******************************** ROOT CONTEXT [START] ********************************* -->
<!-- ===============================[어노테이션 기반으로 동작]================================== -->
<!-- 어노테이션 기반 -->
<mvc:annotation-driven />
<!-- 적용 대상 패키지 -->
<context:component-scan base-package="com.lec11.orm.jpa" />
<!-- datasource : 프로퍼티 파일을 사용한 형태 -->
<context:property-placeholder location="classpath:oracle.properties" />
<bean id="MY_tomcat_ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${lec.driver}" />
<property name="url" value="${lec.url}" />
<property name="username" value="${lec.username}" />
<property name="password" value="${lec.userpw}" />
</bean>
<!-- JPA 설정 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="MY_tomcat_ds" />
<property name="packagesToScan" value="com.lec11.orm.jpa.entity" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- JPA 레포지토리 설정 -->
<jpa:repositories base-package="com.lec11.orm.jpa" />
<!-- 트랜잭션 매니저 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- ******************************** ROOT CONTEXT [END] ********************************* -->
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
/WEB-INF/web.xml
에 DispatcherServlet
의 초기화 매개변수로 lec11-servlet-context.xml
을 넣어줍니다.<!-- web.xml -->
<servlet>
<servlet-name>SPRING_SERVLET</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/lec11-servlet.context.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SPRING_SERVLET</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
SessionFactory
에서 EntityManager
로 변경AS-IS) 기존 Hibernate SessionFactory 설정
<!-- Hibernate SqlSessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="MY_tomcat_ds"/>
<property name="packagesToScan" value="com.lec10.orm.hibernate.entity"/>
<property name="hibernateProperties">
<props>
...// Hibernate 관련 설정
TO-BE) JPA의 EntityManager 설정
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="MY_tomcat_ds" />
<property name="packagesToScan" value="com.lec11.orm.jpa.entity"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
... // Hibernate 관련 설정
org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
persistence.xml
이란 이름으로 존재해야 한다.mybatis-context.xml
, Hibernate에서의 hibernate.cfg.xml
으로 영속성 관련 설정을 한 것과 마찬가지로, JPA 에도 persistence.xml
이 존재한다.<!-- persistence.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="my-persistence-unit">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- 엔티티 클래스 패키지를 지정 -->
<class>com.lec11.orm.jpa.UserEntity</class>
<!-- 데이터베이스 연결 설정 -->
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<property name="javax.persistence.jdbc.user" value="it"/>
<property name="javax.persistence.jdbc.password" value="0000"/>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<!-- Hibernate 설정 -->
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.hbm2ddl.auto" value="none"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
peresistence-unit
: 응용 프로그램의 EntityManager
인스턴스에 의해 관리되는 모든 엔티티 클래스의 집합을 정의합니다.
JPA
도 VO
=Entity
객체와 테이블을 매핑하기 위한 다양한 설정 정보가 필요합니다.
이를 위해 persistence.xml
파일을 설정 파일로 사용헙나더,
persistence.xml
의 위치는 src/java/resources/META-INF
내에 존재해야 함, <persistence>
를 루트 요소로 사용합니다.영속성 유닛(persistence-unit)
과 관련한 다양한 정보가 설정됩니다.EntityManagerFactory
객체에 사용됨.JPA
를 이용하여 DB 연동
을 구현하기 위해서는 EntityManager
객체가 필요함.
EntityManager
를 얻으려면, EntityManager
객체를 생성하기 위한 EntityManagerFactory
객체가 필요합니다. EntityManagerFactory
객체를 생성할 때 설정으로 PersistenceUnit
이 사용됨.
Spring 과 연동하여 JPA를 사용할 수도 있겠지만, JPA 자체만으로 Java 코드에 연동하여 DB에 접근할 수 있습니다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit");
EntityManager em = emf.createEntityManager();
if( em != null )
System.out.println("em ok");
em.getTransaction().begin();
UserEntity user = em.find(UserEntity.class, 1L);
em.close();
emf.close();
물론 단일 조회 연산이기에 트랜잭션은 필요없지만, 예시를 위해 em.getTransaction()
을 사용했습니다.
CriteriaBuilder
와 CriteriaQuery
라는 문법을 사용하여 코드로 쿼리를 생성할 수 있습니다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<UserEntity> query = builder.createQuery(UserEntity.class);
Root<UserEntity> root = query.from(UserEntity.class);
Predicate userIdPredicate = builder.equal(root.get("userId"), "admin");
Predicate userPwPredicate = builder.equal(root.get("userPw"), "0000");
query.where(builder.and(userIdPredicate, userPwPredicate));
UserEntity entity = null;
try {
entity = em2.createQuery(query).getSingleResult();
if (entity != null) {
System.out.println("로그인 성공: " + entity);
}
} catch (Exception e) { //결과가 없을 경우 NoResultException을 발생
System.out.println("로그인 실패");
}
// Transaction 커밋 및 엔티티 매니저 종료
em2.getTransaction().commit();
em2.close();
emf2.close();
//select count(1) from users3;
userRepository.count();
//delete from users3 where userSeq= ?
userRepository.delete(Long id);
//delete from users3 where userId= ? and userPw=? and userName=?
userRepository.delete(UserEntity entity);
//delete from users3;
userRepository.deleteAll();
//select * from users3 wehre userSeq=?
userRepository.exists(Long id);
//select * from users3;
userRepository.findAll()
//sub.. sub.. sub..select * from users3 where~~~ rnum between 1 and 10;
userRepository.findAll(Pageable);
//select * from users3 order by userName asc, userSeq desc;
userRepository.findAll(Sort)
//select * from users3 where userSeq=?
userRepository.findOne(Long id);
userRepository.getOne(Long id);
//insert into users3 (...)
//update users3 set (...)
userRepository.save(UserEntity entity);
@Query
, createQuery()
메서드를 통해 쿼리를 생성할 수 있습니다.IDENTITY
전략주문 코드
SEQUENCE
전략게시물 번호