๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŒฟ Spring

[Spring Boot/RESTful] JPA ์‚ฌ์šฉ / H2 database(+sql ๋ฒ„์ „ ์˜ค๋ฅ˜)

by nitronium102 2022. 2. 19.

JPA

  • Java Persistence API
  • ์ž๋ฐ” ORM ๊ธฐ์ˆ ์— ๋Œ€ํ•œ API ํ‘œ์ค€ ๋ช…์„ธ(Object Relationship Mapping)
  • ์ž๋ฐ” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ •์˜ํ•œ ์ธํ„ฐํŽ˜์ด์Šค
  • → ๋ฉ”์†Œ๋“œ ์„ ์–ธ๋ฌธ๋งŒ ์กด์žฌ. ์šฐ๋ฆฌ๋Š” ๊ตฌํ˜„์ฒด๋ฅผ ๊ฐ€์ง€๊ณ  ๊ฐœ๋ฐœ์„ ํ•ด์•ผ ํ•œ๋‹ค ⇒ Hibernate
  • EntityManager๋ฅผ ํ†ตํ•ด CRUD ์ฒ˜๋ฆฌ

Hibernate

  • JPA์˜ ๊ตฌํ˜„์ฒด, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ⇒ JPA์˜ EntityManager๋ฅผ ๊ตฌํ˜„
  • ๊ฐ์ฒด ๊ด€๊ณ„ ๋งคํ•‘ ํ”„๋ ˆ์ž„์›Œํฌ
  • ์ƒ์‚ฐ์„ฑ, ์œ ์ง€๋ณด์ˆ˜, ๋น„์ข…์†์„ฑ

Spring Data JPA

  • Spring Module
  • JPA๋ฅผ ์ถ”์ƒํ™”ํ•œ Repository ์ธํ„ฐํŽ˜์ด์Šค ์ œ๊ณต
  • ์ธํ„ฐํŽ˜์ด์Šค ์„ ์–ธ ๋งŒ์œผ๋กœ๋„ Spring์—์„œ ์ œ๊ณตํ•˜๋Š” CRUD ๊ธฐ๋Šฅ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

 

1. dependency ์ถ”๊ฐ€

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope> // ์˜์กด ๊ด€๊ณ„๊ฐ€ ์ปดํŒŒ์ผ ์‹œ ํ•„์š”ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์‹คํ–‰ํ•  ๋•Œ ํ•„์š”ํ•จ
</dependency>
# jpa
spring:
  jpa:
    show-sql: true
  h2:
    console:
      enabled: true
datasource:
    url: jdbc:h2:mem:testdb // h2 1.4.200 ์ด์ƒ์—์„œ๋Š” ๋ช…์‹œํ•ด์ค˜์•ผ ํ•จ

h2 console bean์ด ๋“ฑ๋ก๋์Œ์„ ํ™•์ธ

 

2. h2 console ๋กœ๊ทธ์ธ

localhost8088/h2-console → spring security์—์„œ ์„ค์ •ํ•œ ์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅํ•˜๊ณ  ์ง„์ž….

ํ•˜์ง€๋งŒ ์ด๊ฒŒ ๊ท€์ฐฎ๋‹ค๋ฉด spring security ๊ธฐ๋Šฅ์„ ์‚ญ์ œํ•ด๋„ ๋œ๋‹ค -> dependency, SpringConfig.class ์‚ญ์ œ

mem(memory) : ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๊ธฐ๋™๋˜๋Š” ๋™์•ˆ์—๋งŒ ์œ ์ง€๋˜๋Š” db

๊ทธ๋ฆฌ๊ณ  ์„œ๋ฒ„๋ฅผ ๊ตฌ๋™์‹œ์ผœ๋ณด๋ฉด hibernate์—์„œ ์„ฑ๊ณต์ ์œผ๋กœ table์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

(application.yml์— jpa : show-sql: trueํ•œ ๊ฒฝ์šฐ๋งŒ ๋ณด์ž„)

 

3. ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…

์˜ˆ์‹œ์šฉ์œผ๋กœ /resource/data.sql์„ ๋งŒ๋“ค์–ด ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

insert into user values(1, sysdate(), 'User1', 'test1111', '701010-1111111');
insert into user values(2, sysdate(), 'User2', 'test2222', '801010-1111111');
insert into user values(3, sysdate(), 'User3', 'test3333', '901010-1111111');

hibernate - sql ๋ฒ„์ „ ์—๋Ÿฌ

๊ทธ๋Ÿฐ๋ฐ ์–˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค! ์ฐพ์•„๋ณด๋‹ˆ Spring Boot 2.5๋ฒ„์ „๋ถ€ํ„ฐ hibernate์™€ sql ๊ฐ„์˜ ์ˆœ์œ„๊ฐ€ ๋ฐ”๋€Œ์–ด sql ํŒŒ์ผ์ด ๋จผ์ € ์‹คํ–‰๋œ๋‹ค๊ณ  ํ•œ๋‹ค. sql์€ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š”๋ฐ table์€ ์—†์œผ๋‹ˆ ๋‹น์—ฐํžˆ ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค......์ž‘๋…„์— ์‚ฐ ๊ฐ•์˜๋ผ ๋ฒ„์ „ ์˜ค๋ฅ˜๊ฐ€ ์ฐธ ๋งŽ๋‹ค^^

application.yml ํŒŒ์ผ์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

defer-datasource-initialization: true

๊ทผ๋ฐ ํ•˜๋Š” ๊น€์— ๊ทธ๋ƒฅ ๋“œ๋ผ์ด๋ฒ„๋„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ด๊ฒƒ์ €๊ฒƒ ๋„ฃ์—ˆ๋‹ค. 

jpa:
    show-sql: true
    generate-ddl: true
    hibernate:
      ddl-auto: create
    defer-datasource-initialization: true
  h2:
    console:
      enabled: true
      settings:
        web-allow-others: true
        path: /h2-console
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb

 

4. Entity ์„ค์ •

[interfaceUserRepository]
@Repository
public interfaceUserRepository extends JpaRepository<User, Integer> {
	//์–ด๋– ํ•œ Entity๋ฅผ ๋‹ค๋ฃฐ ๊ฒƒ์ธ๊ฐ€,ํ•ด๋‹น entity์˜ ๊ธฐ๋ณธ ํ‚ค ํƒ€์ž…
}
[Controller]
@GetMapping("/users/{id}")
public EntityModel<User> retrieveUser(@PathVariable int id){
	Optional<User> user = userRepository.findById(id);
	if (!user.isPresent())
		throw new UserNotFoundException(String.format("ID[%s] not found", id));

	// HATEOAS ์‚ฌ์šฉ
	EntityModel<User> entityModel = EntityModel.of(user.get());
	WebMvcLinkBuilder linkTo = linkTo(methodOn(this.getClass()).retreiveAllUsers());
	entityModel.add(linkTo.withRel("all-users"));

	return entityModel;
}

 

5. H2 Console ์‚ฌ์šฉ์„ ์œ„ํ•œ SecurityConfig ํŒŒ์ผ ์ˆ˜์ •

๊ธฐ๋ณธ์ ์œผ๋กœ spring security๋Š” ๋ชจ๋“  ์š”์ฒญ์„ ๋ชจ๋‘ ๋ง‰๋Š”๋‹ค! ๊ทผ๋ฐ ์šฐ๋ฆฌ๋Š” h2 console์— ์ ‘๊ทผํ•ด์•ผ ํ•˜๋‹ˆ๊นŒ ํ•ด๋‹น ์ฝ˜์†”์—์„œ ์˜ค๋Š” ์š”์ฒญ์€ ์—ด์–ด๋‘์ž.

@Override
protected void configure(HttpSecurity http) throws Exception {
	http.authorizeRequests().antMatchers("/h2-console/**").permitAll();
	http.csrf().disable();
	http.headers().frameOptions().disable();
}

 

6. Post Entity์™€ User Entity ์ƒ์„ฑ ๋ฐ ๊ด€๊ณ„ ์„ค์ •

ํ•˜๋‚˜์˜ ์œ ์ €๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ post๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋†“๊ณ  ๊ด€๋ จ๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Post {

	@Id
	@GeneratedValue
	private Integer id;

	private String description;

	// User : Post -> 1 : (0~N)
	// Main : Sub -> Parent : Child
	@ManyToOne(fetch = FetchType.LAZY)
	// ์ง€์—ฐ ๋กœ๋”ฉ : ์‚ฌ์šฉ์ž ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ๋ฅผ ํ•  ๋•Œ POST ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋กœ๋”ฉ๋˜๋Š” ๊ฒƒ x
	// post entity๊ฐ€ ์กฐํšŒ๋  ๋•Œ user entity๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ฒƒ!
	@JsonIgnore
	private User user;

}
@Data
@AllArgsConstructor
@NoArgsConstructor // ๋””ํดํŠธ ์ƒ์„ฑ์ž ์ƒ์„ฑ
@ApiModel(description = "์‚ฌ์šฉ์ž ์ƒ์„ธ ์ •๋ณด๋ฅผ ์œ„ํ•œ ๋„๋ฉ”์ธ ๊ฐ์ฒด")
@Entity
public class User {
  	
    ...
    
	@OneToMany(mappedBy = "user")
	private List<Post> posts;
}

๋Œ“๊ธ€