Post

ORM, JPA, Pagination, Dirty Checking

โœ… ORM

๐Ÿ‘Ž๐Ÿป ๊ธฐ์กด ์ฝ”๋“œ์˜ ํ•œ๊ณ„: SQL์„ JAVA์•ˆ์— ์‚ฝ์ž…ํ•ด์•ผ ํ•˜๊ณ , rowMapper๋„ฃ์–ด์•ผ ํ–ˆ์Œ

ORM: Object Relational Mapping
maps java object and RDB
makes object into a DB table

์˜์†ํ™”: ORM์„ ์ ์šฉํ•œ Entity๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์„ ๊ฐ์ฒด์˜ table ์˜์†ํ™”๋ผ๊ณ  ํ•œ๋‹ค.

  • Hibernate
  • EclipseLink
  • DataNucleus

โœ… JPA

Screenshot 2024-08-06 at 11 51 55

JPA: Java Persistence API
developer does not write SQL himself, JPA API will manage and save DB
ํ•œ๋งˆ๋””๋กœ ์ž๋ฐ”์˜ ORM
JPA operates between Java application and JDBC

โ˜‘๏ธ JPA ๋‚ด๋ถ€ ๊ตฌ์„ฑ ์š”์†Œ

โœ”๏ธ Entity Transaction
โœ”๏ธ Entity Manager ๋“ฑ์žฅ

โ˜‘๏ธ Hibernate

Hibernate: JPA ๊ตฌํ˜„์ฒด

โœ… ๊ณ ๋… JPA ๊ตฌํ˜„

JPA Entity ์กฐ๊ฑด

  • no args constructor
  • getter/setter
  • private field

    table ๋ช…์‹œ๋ฅผ ํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//๊ธฐ์กด ItemEntity
@Getter
@Setter
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString
@Builder
public class ItemEntity {
    private Integer id;
    private String name;
    private String type;
    private Integer price;
    private Integer storeId;
    private Integer stock;
    private String cpu;
    private String capacity;

    public ItemEntity(Integer id, String name, String type, Integer price, String cpu, String capacity) {
        this.id = id;
        this.name = name;
        this.type = type;
        this.price = price;
        this.storeId = null;
        this.stock = 0;
        this.cpu = cpu;
        this.capacity = capacity;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//jpa ์ ์šฉ
@Getter
@Setter
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString
@Builder
@Entity
@Table(name= "item")
public class ItemEntity {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name= "id")
    private Integer id;
    @Column(name= "name", length= 50, nullable = false, unique = true)
    private String name;
    @Column(name= "type", length= 20, nullable = false)
    private String type;
    @Column(name= "price")
    private Integer price;
    @Column(name= "store_id")
    private Integer storeId;
    @Column(name= "stock", columnDefinition = "default 0 CHECK(stock) >= 0")
    private Integer stock;
    @Column(name= "cpu", length = 30)
    private String cpu;
    @Column(name= "capacity", length = 30)
    private String capacity;

    public ItemEntity(Integer id, String name, String type, Integer price, String cpu, String capacity) {
        this.id = id;
        this.name = name;
        this.type = type;
        this.price = price;
        this.storeId = null;
        this.stock= 0;
        this.cpu = cpu;
        this.capacity = capacity;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//jpa๊ตฌํ˜„ ์ „
@Getter
@Setter
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString
@Builder

public class StoreSalesEntity {
    private Integer id;
    private String storeName;
    private Integer amount;
}
//jpa ๊ตฌํ˜„ ํ›„
@Getter
@Setter
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString
@Builder
@Entity
@Table(name= "store_sales")
public class StoreSalesEntity {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name= "id")
    private Integer id;
    @Column(name= "store_name", length = 30)
    private String storeName;
    @Column(name= "amount", nullable = false, columnDefinition = "DEFAULT 0 CHECK(amount) =0")
    private Integer amount;
}

โœ… JPA ์‚ฌ์šฉํ•ด์„œ method ์ž๋™์œผ๋กœ ๋งŒ๋“ค๊ธฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//controller
 //jpa์‚ฌ์šฉํ•ด์„œ type์œผ๋กœ item์ฐพ๊ธฐ
    @GetMapping("/items-types")
    public List<Item> findItemByTypes(@RequestParam("type") List<String> types){
        List<Item> items= itemService.findItemsByTypes(types);
        return items;
    }

//service
//jpa์‚ฌ์šฉํ•ด์„œ type์œผ๋กœ item์ฐพ๊ธฐ

    public List<Item> findItemsByTypes(List<String> types) {
        List<ItemEntity> itemEntities= electronicStoreItemJpaRepository.findItemEntitiesByTypeIn(types);
        return itemEntities.stream().map(ItemMapper.INSTANCE::itemEntityToItem).collect(Collectors.toList());
    }

//ElectronicStoreItemJpaRepository
@Repository
public interface ElectronicStoreItemJpaRepository extends JpaRepository<ItemEntity, Integer> { //id์˜ type
    List<ItemEntity> findItemEntitiesByTypeIn(List<String> types);
}

โœ… JPA Pagination

ํŽ˜์ด์ง€ ๋‚˜๋ˆ ์ฃผ๋Š” ๊ธฐ๋Šฅ

๋ชจ๋“  ์•„์ดํ…œ Pagination

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//controller
//pagination
    @GetMapping("/items-page")
    public Page<Item> findItemsPagination(Pageable pageable){
        return itemService.findAllWithPageable(pageable);
    }

//service
    public Page<Item> findAllWithPageable(Pageable pageable) {
        Page<ItemEntity> itemEntities= electronicStoreItemJpaRepository.findAll(pageable);
        return itemEntities.map(ItemMapper.INSTANCE::itemEntityToItem);
    }

//ElectronicStoreItemJpaRepository
public interface ElectronicStoreItemJpaRepository extends JpaRepository<ItemEntity, Integer> { //id์˜ type
    Page<ItemEntity> findAll(Pageable pageable);
}

์กฐ๊ฑด์ด ์žˆ๋Š” Pagination

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//controller
//pagination
    @GetMapping("/items-page")
    public Page<Item> findItemsPagination(@RequestParam("type") List<String> types, Pageable pageable){
        return itemService.findAllWithPageable(types, pageable);
    }
//service
    public Page<Item> findAllWithPageable(List<String> types, Pageable pageable) {
        Page<ItemEntity> itemEntities= electronicStoreItemJpaRepository.findAllByTypeIn(types, pageable);
        return itemEntities.map(ItemMapper.INSTANCE::itemEntityToItem);
    }

    public interface ElectronicStoreItemJpaRepository extends JpaRepository<ItemEntity, Integer> { //id์˜ type
    Page<ItemEntity> findAllByTypeIn(List<String> types, Pageable pageable);
}

โœ… Dirty Checking

Within a transaction when entity is altered,
automatically save DB with altered value

1
2
3
4
5
6
7
8
@Transactional
public void cancelOrder(Long orderId) {
    //์ฃผ๋ฌธ ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ
    Order order = orderRepository.findOne(orderId);

    //์ฃผ๋ฌธ ์ทจ์†Œ
    order.cancel();
}
  • start Transaction
  • find order entity with orderId
  • update order entity with canceled value
  • commit transaction

There is no explicit update code, but dirty checking will manage update.

  • dirty checking = ๋ณ€๊ฒฝ ๊ฐ์ง€
  • Realizing change in entity โžก๏ธ Apply to DB
This post is licensed under CC BY 4.0 by the author.