1 FoodDelivery DB ์„ค๊ณ„

1๏ธโƒฃ ํ…Œ์ด๋ธ”์„ค๊ณ„

๐Ÿ’ก Member

(Long)id(String)memberName
1mallang
2quokka

๐Ÿ’ก Food

(Long)id(String)foodName(int)price
1๋งค์šด๊ฐˆ๋น„์ฐœ30,000
2๋ง๊ณ ๋น™์ˆ˜10,000

2๏ธโƒฃ ์—ฐ๊ด€๊ด€๊ณ„ ํ…Œ์ด๋ธ”์„ค๊ณ„

  • โ‘  Member ํ…Œ์ด๋ธ”์— ์ฃผ๋ฌธ์ •๋ณด ๋„ฃ์œผ๋ฉด โ†’ Member ๋ฐ์ดํ„ฐ ์ค‘๋ณต ๐Ÿšจ

  • โ‘ก Food ํ…Œ์ด๋ธ”์— ์ฃผ๋ฌธ์ •๋ณด ๋„ฃ์œผ๋ฉด โ†’ Food ๋ฐ์ดํ„ฐ ์ค‘๋ณต ๐Ÿšจ

  • โ‘ข Orders๋งŒ์„ ๋‹ค๋ฃจ๋Š” ํ…Œ์ด๋ธ” ์ถ”๊ฐ€ โ—๏ธ

๐Ÿ’ก Orders

(Long)idMember_idFood_idTime
1112023.07.24 22:00
2122023.07.24 23:00

2 FoodDelivery JPA์—ฐ๊ด€๊ด€๊ณ„

๐Ÿ“Œ JPA์—ฐ๊ด€๊ด€๊ณ„ : Entity ํด๋ž˜์Šค ํ•„๋“œ ์œ„ โ†’ ์—ฐ๊ด€๊ด€๊ณ„ Annotation ์„ค์ • โ†’ ํ˜•์„ฑ์™„๋ฃŒ

์—ฐ๊ด€๊ด€๊ณ„AnnotationEntitycontent
1 : N (์ผ๋Œ€๋‹ค)@OneToManyOrders(1) : Food(N)๋ฐฐ๋‹ฌ์ฃผ๋ฌธ 1๊ฐœ์— N๊ฐœ ์Œ์‹ ์„ ํƒ๊ฐ€๋Šฅ
N : 1 (๋‹ค๋Œ€์ผ)@ManyToOneOwner(N) : Restaurant(1)์‚ฌ์žฅ N๋ช…์ด 1๊ฐœ์˜ ์Œ์‹์  ์†Œ์œ ๊ฐ€๋Šฅ
1 : 1 (์ผ๋Œ€์ผ)@OneToOneOrders(1) : Coupon(1)๋ฐฐ๋‹ฌ์ฃผ๋ฌธ 1๊ฑด์— ์ฟ ํฐ 1๊ฐœ๋งŒ ์ ์šฉ๊ฐ€๋Šฅ
N : M (๋‹ค๋Œ€๋‹ค)@ManyToManyMember(N) : Restaurant(M)๊ณ ๊ฐ์€ ์Œ์‹์  ์—ฌ๋Ÿฌ๊ฐœ ์ฐœ๊ธฐ๋Šฅ, ์Œ์‹์ ์€ ๊ณ ๊ฐ ์—ฌ๋Ÿฌ๋ช…์—๊ฒŒ ์ฐœ๊ธฐ๋Šฅ

3 ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

1๏ธโƒฃ Project Metadata


๊ตฌ๋ถ„์—ญํ• 
Group๊ธฐ์—…์˜ ๋„๋ฉ”์ธ ๋ช… (๋’ค๋ถ€ํ„ฐ ์•ž์œผ๋กœ ์”€)
๊ฐœ์ธํ”„๋กœ์ ํŠธ โ†’ ์ž์œ ๋กญ๊ฒŒ ์„ค์ •๊ฐ€๋Šฅ
Artifact๋นŒ๋“œ๋œ ๊ฒฐ๊ณผ๋ฌผ์˜ ์ด๋ฆ„
Package NameํŒจํ‚ค์ง€๋ช…
Packaging[๋ฐฐํฌํ˜•ํƒœ]
โ‘  jar
- Java ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ”„๋กœ์ ํŠธ๋ฅผ ์••์ถ•ํ•œ ํŒŒ์ผ
- class + ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌํŒŒ์ผ
- JRE๋งŒ ์žˆ์–ด๋„ ์‹คํ–‰๊ฐ€๋Šฅ

โ‘ก war
- Servlet, Jsp ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ๋Š” ์›น์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์••์ถ•ํ•œ ํŒŒ์ผ
- ์›นํ”„๋กœ์ ํŠธ โ†’ jsp, html, javascript ํฌํ•จ
- ์›น์„œ๋ฒ„๋‚˜ was๊ฐ€ ํ•„์š”ํ•จ

โžก๏ธ ์›นํ™”๋ฉด์ด ํ•„์š”ํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ war๋กœ ํŒจํ‚ค์ง•,
api ์„œ๋ฒ„์‚ฌ์šฉ์€ ํ”„๋กœ์ ํŠธ๋กœ๋งŒ ๋™์ž‘ํ•˜๋ฉด ๋˜๊ธฐ๋•Œ๋ฌธ์— jar๋กœ ํŒจํ‚ค์ง•
Java, SpringBoot ๋ฒ„์ „- โ‘  SpringBoot 3.XX โ†’ Java 17 ์ด์ƒ ์‚ฌ์šฉ
- โ‘ก SpringBoot 2.XX โ†’ Java 11 ์‚ฌ์šฉ

โžก๏ธ SNAPSHOT, M1์€ ์ •์‹๋ฒ„์ „ โŒ

2๏ธโƒฃ Project ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

  • Entity, Repository ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ

    • ๊ณ„์ธตํ˜•๊ตฌ์กฐ
    • ํ”„๋กœ์ ํŠธ ์ดํ•ด๋„๊ฐ€ ๋‚ฎ์•„๋„ ์ „์ฒด์ ์ธ ๊ตฌ์กฐํŒŒ์•… ์‰ฝ๊ฒŒ๊ฐ€๋Šฅ
  • 1๊ฐœ์˜ Entity โ†’ 1๊ฐœ์˜ Repository

  • .gitignore โ†’ ๋ฏผ๊ฐ์ •๋ณด ๋ณดํ˜ธ๋ฅผ ์œ„ํ•ด src/ ํ•˜์œ„ํŒŒ์ผ๋งŒ pushํ•จ


4 Entity ์„ค๊ณ„

1๏ธโƒฃ Member.java

@Getter
@Entity
@NoArgsConstructor // class ๋ชจ๋“ ํ•„๋“œ -> ๊ธฐ๋ณธ์ƒ์„ฑ์ž ์ž๋™์ถ”๊ฐ€
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // PK์ƒ์„ฑ -> DB์— ์œ„์ž„์ „๋žต
    private Long id;

    @Column(nullable = false)
    private String memberName;

    // JPA ์—ฐ๊ด€๊ด€๊ณ„์„ค์ •
    // ์ผ๋Œ€๋‹ค -> ์—ฐ๊ด€๊ด€๊ณ„์ฃผ์ธ : member, ์ฆ‰์‹œ๋กœ๋”ฉ EAGER์‚ฌ์šฉ
    // ์ฆ‰์‹œ๋กœ๋”ฉ : member + order(์—ฐ๊ด€๊ด€๊ณ„ํ…Œ์ด๋ธ”) ํ•จ๊ป˜์กฐํšŒ
    // ์ง€์—ฐ๋กœ๋”ฉ : member๋งŒ ์กฐํšŒ, ์—ฐ๊ด€๊ด€๊ณ„ํ…Œ์ด๋ธ” ์กฐํšŒ๋Š” ๋ฏธ๋ฃธ
    @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
    private List<Orders> orders = new ArrayList<>();

    // ์ƒ์„ฑ์ž
    public Member(String memberName) {
        this.memberName = memberName;
    }
}

2๏ธโƒฃ Food.java

@Getter
@Entity
@NoArgsConstructor
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String foodName;

    @Column(nullable = false)
    private int price;

    // JPA ์—ฐ๊ด€๊ด€๊ณ„์„ค์ •
    @OneToMany(mappedBy = "food", fetch = FetchType.EAGER)
    private List<Orders> orders = new ArrayList<>();

    public Food(String foodName, int price) {
        this.foodName = foodName;
        this.price = price;
    }
}

3๏ธโƒฃ Orders.java

@Getter
@Entity
@NoArgsConstructor // class ๋ชจ๋“ ํ•„๋“œ -> ๊ธฐ๋ณธ์ƒ์„ฑ์ž ์ž๋™์ถ”๊ฐ€
public class Orders {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // PK์ƒ์„ฑ -> DB์— ์œ„์ž„์ „๋žต
    private Long id;

    // JPA ์—ฐ๊ด€๊ด€๊ณ„์„ค์ •
    // ๋‹ค๋Œ€์ผ -> ์—ฐ๊ด€๊ด€๊ณ„์ฃผ์ธ : member, Member Entity PK๋กœ ์—ฐ๊ฒฐ
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;

    @ManyToOne
    @JoinColumn(name = "food_id")
    private Food food;

    // ์ƒ์„ฑ์ž
    public Orders(Member member, Food food) {
        this.member = member;
        this.food = food;
    }
}

5 Repository ์„ค๊ณ„

1๏ธโƒฃ MemberRepository.java

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

// ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ -> JpaRepository<Entityํด๋ž˜์Šค, PKํƒ€์ž…> ์ƒ์†์‹œํ‚ด
// ๊ธฐ๋ณธ์ ์ธ CRUD ๋ฉ”์„œ๋“œ๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋จ

2๏ธโƒฃ FoodRepository.java

public interface FoodRepository extends JpaRepository<Food, Long> {
}

3๏ธโƒฃ OrdersRepository.java

public interface OrdersRepository extends JpaRepository<Orders, Long> {
}

6 H2 console ์—ฐ๊ฒฐ

1๏ธโƒฃ application.properties

# H2 ์—ฐ๊ฒฐ
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:db
spring.datasource.username=mallang
spring.datasource.password=
  • username์€ ๋ณธ์ธ ์žฌ๋Ÿ‰์— ๋งž๊ฒŒ ์„ค์ •๊ฐ€๋Šฅ

  • build.gradle > dependencies โ†’ runtimeOnly 'com.h2database:h2' ์„ค์ •๋˜์–ด์žˆ๋Š”์ง€ ํ™•์ธ

2๏ธโƒฃ H2 console ๋„์šฐ๊ธฐ

  • โ‘  IntelliJ RUN

  • โ‘ก ํฌ๋กฌ > localhost:8080/h2-console ์ ‘์†

  • โ‘ข ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์กฐ ํ™•์ธ



7 ApplicationRunner ์„ค๊ณ„

@Component // ๊ฐœ๋ฐœ์ž ์ƒ์„ฑ class -> SpringBean ๋“ฑ๋ก
@RequiredArgsConstructor // final, @Notnull ํ•„๋“œ -> ์ƒ์„ฑ์ž ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์คŒ
public class Restaurant implements ApplicationRunner {

    private final MemberRepository memberRepository;
    private final FoodRepository foodRepository;
    private final OrdersRepository ordersRepository;

    @Override
    public void run(ApplicationArguments arguments) throws Exception {
        List<Food> foods = new ArrayList<>();
        Food food1 = new Food("ํ›„๋ผ์ด๋“œ", 10000);
        foods.add(food1);
        Food food2 = new Food("์–‘๋…์น˜ํ‚จ", 12000);
        foods.add(food2);
        Food food3 = new Food("๋ฐ˜๋ฐ˜์น˜ํ‚จ", 13000);
        foods.add(food3);
        Food food4 = new Food("๊ณ ๊ตฌ๋งˆํ”ผ์ž", 9000);
        foods.add(food4);
        Food food5 = new Food("์•„๋ณด์นด๋„ํ”ผ์ž", 110000);
        foods.add(food5);

        foodRepository.saveAll(foods);

        System.out.println("==================================================================");
        // FoodRepository -> ๊ฐ์ฒด๋ฅผ ์ „๋ถ€ ์ฝ์–ด์˜ด -> ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด FoodName๋งŒ get
        List<Food> findFoods = foodRepository.findAll();
        for (Food findFood : findFoods) {
            System.out.println("findFood = " + findFood.getFoodName());
        }


        List<Member> members = new ArrayList<>();
        Member member1 = new Member("๋ง๋ž‘์ด");
        members.add(member1);
        Member member2 = new Member("์ฟผ์นด");
        members.add(member2);

        memberRepository.saveAll(members);

        System.out.println("==================================================================");
        // MemberRepository -> ๊ฐ์ฒด๋ฅผ ์ „๋ถ€ ์ฝ์–ด์˜ด -> ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด MemberName๋งŒ get
        System.out.println("Member ๋ฐ์ดํ„ฐ");
        List<Member> findMembers = memberRepository.findAll();
        for (Member findMember : findMembers) {
            System.out.println("findMember = " + findMember.getMemberName());
        }


        List<Orders> ordersList = new ArrayList<>();
        // Java List -> ์ˆœ์„œ๋ณด์žฅ๋จ -> Entity ์ˆœ์„œ์— ๋งž์ถฐ ์ดˆ๊ธฐ๊ฐ’ ๋„ฃ์–ด์ฃผ๊ธฐ
        Orders orders1 = new Orders(findMembers.get(0), findFoods.get(0));
        ordersList.add(orders1);
        Orders orders2 = new Orders(findMembers.get(1), findFoods.get(3));
        ordersList.add(orders2);
        Orders orders3 = new Orders(findMembers.get(1), findFoods.get(4));
        ordersList.add(orders3);
        Orders orders4 = new Orders(findMembers.get(0), findFoods.get(2));
        ordersList.add(orders4);
        Orders orders5 = new Orders(findMembers.get(0), findFoods.get(2));
        ordersList.add(orders5);
        Orders orders6 = new Orders(findMembers.get(1), findFoods.get(1));
        ordersList.add(orders6);
        Orders orders7 = new Orders(findMembers.get(0), findFoods.get(1));
        ordersList.add(orders7);
        Orders orders8 = new Orders(findMembers.get(1), findFoods.get(3));
        ordersList.add(orders8);

        ordersRepository.saveAll(ordersList);

        System.out.println("==================================================================");
        int num = 1;

        System.out.println("Orders ๋ฐ์ดํ„ฐ");
        List<Orders> orderList = ordersRepository.findAll();
        for (Orders orders : orderList) {
            System.out.println(num);
            System.out.println("์ฃผ๋ฌธ์ž = " + orders.getMember().getMemberName());
            System.out.println("์ฃผ๋ฌธ์Œ์‹ = " + orders.getFood().getFoodName());
            num++;
        }

        System.out.println("==================================================================");
        System.out.println("๋ง๋ž‘์ด๊ฐ€ ์ฃผ๋ฌธํ•œ ์Œ์‹");
        Member mallang = memberRepository.findById(1L).orElseThrow(
                () -> new RuntimeException("์—†์Œ")
        );

        num = 1;

        for (Orders orders : mallang.getOrders()) {
            System.out.println(num);
            System.out.println("์ฃผ๋ฌธ์Œ์‹ = " + orders.getFood().getFoodName());
            System.out.println("์ฃผ๋ฌธ์Œ์‹๊ฐ€๊ฒฉ = " + orders.getFood().getPrice());
            num++;
        }

        System.out.println("==================================================================");

        System.out.println("์•„๋ณด์นด๋„ํ”ผ์ž ์ฃผ๋ฌธ์ž");
        Food abocado = foodRepository.findById(5L).orElseThrow(
                () -> new RuntimeException("์—†์Œ")
        );

        for (Orders orders : abocado.getOrders()) {
            System.out.println("์ฃผ๋ฌธ์ž = " + orders.getMember().getMemberName());
        }
    }
}

8 ์ƒ์†์„ ํ†ตํ•œ ์ƒ์„ฑ ๋ฐ ์ˆ˜์ •์‹œ๊ฐ„ ์„ค๊ณ„

1๏ธโƒฃ Timestamped.java

@Getter
// ๊ณตํ†ต Mapping ์ •๋ณด๊ฐ€ ์กด์žฌํ• ๋•Œ ์‚ฌ์šฉ
// ๋ถ€๋ชจํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๋Š” ์ž์‹ํด๋ž˜์Šค์—๊ฒŒ ๋งตํ•‘์ •๋ณด๋งŒ ์ œ๊ณตํ•˜๊ณ  ์‹ถ์„ ๋•Œ
// Entity๋Š” Entity๋งŒ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์žˆ๊ธฐ๋•Œ๋ฌธ์—, ํด๋ž˜์Šค๋ฅผ Entity์— ์ƒ์†์‹œํ‚ค๊ธฐ์œ„ํ•œ ๋ฐฉ๋ฒ•
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Timestamped {
    // ์ƒ์„ฑ์‹œ๊ฐ„
    @CreatedDate
    // Entity ์ˆ˜์ • ์‹œ, ํ•ด๋‹น ํ•„๋“œ ์ˆ˜์ •์„ ๋ง‰์Œ -> ์ฝ๊ธฐ์ „์šฉ
    @Column(updatable = false)
    private LocalDateTime createdAt;

    // ์ˆ˜์ •์‹œ๊ฐ„
    @LastModifiedDate
    @Column(updatable = true) // ๊ธฐ๋ณธ๊ฐ’์ด๋ผ ์ƒ๋žต๊ฐ€๋Šฅ
    private LocalDateTime modifiedAt;
}

2๏ธโƒฃ Timestamped ํด๋ž˜์Šค ์ƒ์†

public class Orders extends Timestamped {โ€ขโ€ขโ€ข}

3๏ธโƒฃ FoodDeliveryApplication.java ์–ด๋…ธํ…Œ์ด์…˜

@EnableJpaAuditing // Timestamped ํด๋ž˜์Šค์‚ฌ์šฉ์„ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜
@SpringBootApplication
public class FoodDeliveryApplication {โ€ขโ€ขโ€ข}

๐Ÿ“ GitHub ๋ฐ”๋กœ๊ฐ€๊ธฐ


Outro

๐Ÿ“Œ Spring Data JPA : JPA๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•ด Spring์—์„œ Wrappingํ•œ ๊ฒƒ

  • JPA ์‚ฌ์šฉ ์‹œ, ํ•„์ˆ˜์ ์ด์ง€๋งŒ ์˜ˆ์ƒ๊ฐ€๋Šฅํ•˜๊ณ  ๋ฐ˜๋ณต์ ์ธ ์ฝ”๋“œ โ†’ Spring Data JPA๊ฐ€ ๋Œ€์‹ ์ž‘์„ฑ

  • Repository์— interface๋งŒ ์ž‘์„ฑ โ†’ ํ•„์š”ํ•œ ๊ตฌํ˜„์€ Spring์ด ๋Œ€์‹ ํ•จ

profile
๐ŸฑSunyeon-Jeong, mallang developer๐Ÿฐ

0๊ฐœ์˜ ๋Œ“๊ธ€