상세 컨텐츠

본문 제목

[Hibernate] Spring 5 - JPA - Setting

JAVA/WEB - Spring

by 개봉박살 2021. 5. 13. 03:21

본문

1. pom.xml

디펜던시 추가

  1-1 JSON 오브젝트 맵핑을위해 Jackson라이브러리 사용

  1-2 Jackson라이브러리가 LocalDateTime클래스를 변환할때 Java 8에서 오류가 발생하기때문에 jsr310 패키지 추가

  1-3 기타 DB통신 드라이버 및 Hibernate구현체 및 JPA 라이브러리 디펜던시 추가

--- 생략 ---
		<!-- JSON library v2.12.2 -->
        <!-- JSON 오브젝트 맵핑 -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>${jackson-version}</version>
		</dependency>

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-annotations</artifactId>
			<version>${jackson-version}</version>
		</dependency>

		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-databind</artifactId>
		    <version>${jackson-version}</version>
		</dependency>
		
        <!-- 자바8에서 LocalDateTime클래스를 JSON타입으로 변환하기위해 필요함 -->
		<dependency>
		    <groupId>com.fasterxml.jackson.datatype</groupId>
		    <artifactId>jackson-datatype-jsr310</artifactId>
		    <version>${jackson-version}</version>
		</dependency>
        
        <!-- JDBC template -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>5.3.5</version>
		</dependency>
		<!-- MySQL DB -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.23</version>
		</dependency>
        
        <!-- Hibernate Dependencys -->
		<!-- 스프링 ORM -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>

		<!-- 스프링 데이터 JPA -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>2.5.0</version>
		</dependency>
		
        <!-- JPA, 하이버네이트 -->
		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-entitymanager</artifactId>
		    <version>5.4.3.Final</version>
		</dependency>
--- 생략 ---

2. appConfig.xml 파일 작성

 2-1 Autowired 어노테이션 탐색 위치 지정

 2-2 DB접속 커넥션 설정(DataSource)

 2-3 JPA 트렌젝션 매니저 설정

 2-4 JPA 엔티티 매니저 설정

 2-5 Hibernate 기타 상세 설정

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="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/data/jpa 
       http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
	
    <!-- Repository 패키지 경로 -->
	<jpa:repositories base-package="com.server.study.repository" />

    <tx:annotation-driven/>

	<!-- Autowired 될 객체 패키지 경로 -->
    <context:component-scan base-package="com.server.study.service, com.server.study.repository"/>

	<!-- DB접속 DataSource 빈생성 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/jpastudy"/>
        <property name="username" value="root"/>
        <property name="password" value="mariadb"/>
    </bean>

	<!-- JPA 트랜젝션 매니저 빈생성 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- Hibernate JPA구현 EntityManager 빈생성 -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- Entity 위치 -->
        <property name="packagesToScan" value="com.server.study.model"/> 
        <property name="jpaVendorAdapter">
            <!-- 하이버네이트 구현체 사용 -->
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
        <!-- 하이버네이트 상세 설정 -->
        <property name="jpaProperties"> 
            <props>
            	<!-- RDB별로 사용하는 SQL문법이 조금씩 다르므로 꼭 알맞게 설정하자 -->
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop> 
                <!-- SQL 로그-->
                <prop key="hibernate.show_sql">true</prop>                   
                <!-- SQL 정렬 -->
                <prop key="hibernate.format_sql">true</prop>                 
                <!-- SQL 코멘트 -->
                <prop key="hibernate.use_sql_comments">true</prop>           
                <!-- 새 버전의 ID 생성 옵션 -->
                <prop key="hibernate.id.new_generator_mappings">true</prop>  
                <!-- DDL 자동 생성(프로젝트가 실행 될 떄 Entity로 사용될 테이블을 drop하니 주의하자) -->
                <!-- <prop key="hibernate.hbm2ddl.auto">create</prop>   -->           
            </props>
        </property>
    </bean>

</beans>

 

3. web.xml

 JPA및 프로젝트 설정

 3-1 appConfig.xml 파일 경로 설정

--- 생략 ---

<servlet>
	<servlet-name>appServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/appServlet/servlet-context.xml,/WEB-INF/spring/appServlet/appConfig.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
--- 생략 ---

 

Sample 

1. Directory 구조

전체 샘플 프로젝트 구조

오류는 신경쓰지 말자(빌어먹을 이클립스)

 

2. 클래스 구성

 2-1 Controller

@RestController
public class HomeController {
	
	@Autowired
	MemberService mService;
	
	@PostMapping(path="/insert")
	public Member insert(@RequestBody Member member) {
		mService.insert(member);
		return member;
	}
	
	@GetMapping(path = "/select")
	public Member select(Member member) {
		Member mem = mService.select(member);
		return mem;
	}
	
	@PatchMapping(path="/update")
	public Member update(@RequestBody Member member) {
		return mService.update(member);
	}
	
	@DeleteMapping(path="delete")
	public Boolean delete(@RequestParam Long id) {
		return mService.delete(id);
	}
}

2-2 Service

 select : PK로 데이터를 1개만 조회해 온다.

 insert : 객체를 전달하여 테이블에 Insert한다.

 update : 

     1. PK값으로 수정할 데이터를 불러온다.

     2. 람다를 통해 데이터를 수정하고 저장한다.( 중요!! )

 delete : PK값으로 데이터를 삭제한다.

@Service
public class MemberService {

	@Autowired
	MemberRepository mRepo;
	
	public Member select(Member member) {
		member = mRepo.findById(member.getId()).get();
		return member;
	}
	
	public void insert(Member member){
		mRepo.save(member);
	}
	
	public Member update(Member member) {
		Optional<Member> db = mRepo.findById(member.getId());
		
		db.ifPresent(selectedMember->{
			selectedMember.setName(member.getName());
			mRepo.save(selectedMember);
		});
		return db.get();
	}

	public Boolean delete(Long id) {
		// TODO Auto-generated method stub
		try {
			mRepo.deleteById(id);
		}catch(Exception e) {
			return false;
		}
		return true;
	}
}

 

3. Repository

JPA에서는 @Repository어노테이션을 사용하지 않는다.

그리고 JpaRepository클래스를 상속받는다.

상속받으며 해당 Repository(저장소 or 테이블)과 영속성을 관리할 객체(Model)와 PK를 제네릭타입으로 지정한다.

public interface MemberRepository extends JpaRepository<Member, Long>{
}

 

4. Model 

 - 샘플코드에서는 코드를 단축하기위해 롬복을 사용하였다.

 - @Entity어노테이션을 통해 영속성을 관리해야하는 객체인것을 선언한다.

 - @Table어노테이션을 통해 DB에 어떤 테이블과 매핑되야할지 설정한다.

 - Insert쿼리가 실행 될때, 컬럼이 auto_increment되는 것을 @GeneratedValue어노테이션을 통해 설정한다.

 - strategy=GenetationType.IDENTITY 를 설정하여 데이터가 유니크한 데이터인것을 알린다.

 - @CreationTimeStamp 어노테이션을 통해 default로 현재시간을 입력한다.

 - @JsonFormat(pattern="yyyy-MM-dd kk:mm:ss")어노테이션을 통해 JSON으로 변환했을때 표현방식을 설정한다.

 - @JsonDeserialize(using = LocalDateTimeDeserializer.class)어노테이션을 통해 LocalDateTime객체를 JSon으로 변환할때 오류가 나지않게 직렬화한다.

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name="member")
public class Member {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY, generator="CUST_SEQ")
	private Long id;
	private String name;
	private String email;
	
	@CreationTimestamp
	@JsonFormat(pattern = "yyyy-MM-dd kk:mm:ss")
	@JsonDeserialize(using = LocalDateTimeDeserializer.class)
	private LocalDateTime create_date;
}

 

Test

스샷을 찍기전에 save를 이미 많이 해서 id가 10까지 증가했다.

 

 

정리하고 보니 설정이 복잡하지 않다.

JPA는 RDB의 데이터를 객체로 다루는 방식이다.

경험을 해보니 단순 조회에서는 혁신적이라고 느껴질 정도로 심플했지만

JOIN이나 복합 검색조건을 구현할 생각을하면 아찔하다...

 

차근차근 해 나가다 보면 답이 보이겠지...

관련글 더보기

댓글 영역