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
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
withorderId
- 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.