1
ธระยทธ ทองเครอ
ภาควชาวทยาการคอมพวเตอร คณะวทยาศาสตร
มหาวทยาลยขอนแกน
บทท 7
JPA
Java Persistence API
JPAJPA เปนมาตรฐานใน Java EE ทก าหนด (specification) วธการ mapping ระหวาง
object และขอมลในฐานขอมล (ORM: Object/Relation Mapping) แบบอตโนมต
JPA ชวยใหนกพฒนาสามารถจดการกบขอมลใน object เพยงอยางเดยว โดยไมตองใชค าสง SQL ชวยใหนกพฒนาเขยนโคดนอยลง
ไลบรารท implement ตามมาตรฐาน JPA มชอวา "Hibernate"
2
Spring DataSpring Data คอ Framework ส าหรบเขาถงขอมลทครอบคลมทงฐานขอมลแบบ
relational และ non-relational, map-reduce frameworks และบรการบน cloud-based คณสมบตของ Spring Data
การจบค Java Object กบโครงสรางในฐานขอมลแบบอตโนมต สรางและประมวลผล SQL แบบอตโนมตตามทนกพฒนาก าหนด
โมดลหลกของ Spring Data Spring Data Commons สวนแกนหลกของ Spring Data ทกชนด Spring Data JPA ใชสรางโมดลจดการฐานขอมลแบบ relational database Spring Data KeyValue ใชสรางโมดลจดการฐานขอมลแบบ Map-base Spring Data LDAP ใชสรางโมดลจดการฐานขอมลผใช Spring Data MongoDB ใชสรางโมดลจดการฐานขอมลแบบ non-relational ชอ MongoDB
3
Spring Data JPA
4
Spring Data
JPA
Hibernate
JDBC
Database
Spring Data JPA เปนชด Library ทชวยอ านวยความสะดวกในการใชงาน JPA มลกษณะเปน Interface-based programming model กลาวคอ ไมตอง implement โคด แตใชการก าหนด Query จากชอ method ใน interface แทน
Dependency ทใช
5
<!-- ชด Starter ส ำหรบ JPA --><dependency>
<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency><dependency>
<groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId>
</dependency>
<!-- ส ำหรบใชตดตอฐำนขอมล MySQL --><dependency>
<groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- ส ำหรบสวนแสดงผล (JSP, JSTL) --><dependency>
<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId>
</dependency><dependency>
<groupId>javax.servlet</groupId><artifactId>jstl</artifactId>
</dependency>
ไฟล application.properties
6
spring.mvc.view.prefix=/jsp/spring.mvc.view.suffix=.jsp
spring.datasource.url = jdbc:mysql://localhost/mydb?characterEncoding=utf-8spring.datasource.username = rootspring.datasource.password =
spring.jpa.show-sql = truespring.jpa.hibernate.ddl-auto = update
หมายเหต ภาษา SQL แบงค าสงออกเปน 2 สวน1. สวนนยามขอมล (Data Definition Language: DDL) เชน ค าสง create/alter/drop table2. สวนจดการขอมล (Data Manipulation Language: DML) เชน ค าสง select, insert, update, delete
ก าหนดคาส าหรบทตดตอฐานขอมลในไฟล application.properties
ก าหนดใหแสดงค าสง SQL บน consoletrue - แสดง, false - ไมแสดง
ก าหนดใหสรางค าสง DDL แบบอตโนมต เมอเจอ Entity class คาทก าหนดไดประกอบดวย none, validate, update, create, create-drop
ชอฐานขอมล
ระบบจดการขอมลลกคา
7
หนาแสดงรายการลกคาแบบฟอรมเพมขอมล
แบบฟอรมแกไขขอมล
หนาแสดงขอมลลกคาตามรหส
Entity Class (หรอ JavaBean)
8
@Entitypublic class Customer {
@Id@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String firstName;private String lastName;
public Integer getId() {return id;
}public void setId(Integer id) {
this.id = id;}
public String getFirstName() {return firstName;
}public void setFirstName(String firstName) {
this.firstName = firstName;}public String getLastName() {
return lastName;}public void setLastName(String lastName) {
this.lastName = lastName;}
}
Entity Class คอ คลาส JPA ใชเปนตวแทนตารางหนงในฐานขอมล @Id ใชระบวาเปน Primary Key @GeneratedValue ระบวาใหรนคา
Primary คยแบบอตโนมต
Entity Class เปนคลาสทมคณสมบตเชนเดยวกบ JavaBeans แตกตางกนท จะตองมการก าหนด Annotation
การตงชอตวแปรจะตองอยในรปแบบ camelCase สวนชอคอลมนจะอยในรปแบบ snake_case
ชนดขอมลของตวแปรในคลาสควรเปนคลาส เชน ใช Integer แทน int
ตาราง Customer ทจบคกบคลาส Customer
Repository Class (หรอ DAO)
9
@Repositorypublic class CustomerRepository {
@PersistenceContextprivate EntityManager entityManager; // ใชเรยกเมธอดจดการฐานขอมล ทสรางมาใหแลว
public List<Customer> findAll() {Query query = entityManager.createQuery("from Customer"); // สรางค าสง SELECT ขอมลจากตาราง customerreturn query.getResultList(); // ดงรายการผลลพธจากการ Query สงกลบ
}
public Customer findById(Integer id) {return entityManager.find(Customer.class, id); // คนหา Customer ตาม id
}
@Transactionalpublic Customer save(Customer customer) {
entityManager.persist(customer); // insert กรณไมมคา id ใน object หรอ update กรณมคา id ใน object return customer;
}
@Transactionalpublic void delete(Integer id) {
Customer customer = entityManager.find(Customer.class, id); // คนหาตาม id ทตองการลบentityManager.remove(customer); // เรมลบจรง
}}
JPA EntityManager Methods
10
รายละเอยดดท https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html
Controller
11
@Controllerpublic class CustomerController {
// สรำง object Repository ส ำหรบเรยกใชในคลำส@Autowiredprivate CustomerRepository customerRepository;
@GetMapping("/customers") // ใชแสดงขอมลลกคำท งหมดpublic String getCustomerList(Model model) {
List<Customer> customerList = customerRepository.findAll();model.addAttribute("customerList", customerList);return "/list";
}
@GetMapping("/customer/{id}") // ใชแสดงลกคำ 1 คน ตำมรหสpublic String getCustomer(@PathVariable Integer id, Model model) {
Customer customer = customerRepository.findById(id);model.addAttribute("customer", customer);return "/detail";
}
@PostMapping("/customer/create") // ใชเพมขอมลลกคำpublic String create(@ModelAttribute Customer customer,
Model model) { customerRepository.save(customer);return "redirect:/customers";
}
// ใชโหลดขอมลลกคำ 1 คน ตำมรหส แลวสงไปแสดงในฟอรม@GetMapping("/customer/editform/{id}")public String load(@PathVariable Integer id, Model model) {
Customer customer = customerRepository.findById(id);model.addAttribute("customer", customer);return "/edit-form";// สงไปแสดงผลในฟอรมแกไข
}
@PostMapping("/customer/edit") // ใชแกไขขอมลลกคำpublic String update(@ModelAttribute Customer editCustomer, Model model) {
Customer oldCustomer = customerRepository.findById(editCustomer.getId());oldCustomer.setFirstName(editCustomer.getFirstName());oldCustomer.setLastName(editCustomer.getLastName());customerRepository.save(oldCustomer);return "redirect:/customers";// สงไปยง path แสดงขอมลลกคำท งหมด
}
@GetMapping("/customer/delete/{id}") // ใชลบขอมลลกคำตำมรหสpublic String delete(@PathVariable Integer id) {
customerRepository.delete(id);return "redirect:/customers";// สงไปยง path แสดงขอมลลกคำท งหมด
}}
หนาแสดงรายการลกคา
12
Model: CustomerRepository
View: list.jsp
Controller: CustomerController
public List<Customer> findAll() {// สรำง Query ดงขอมลท งหมดจำกตำรำง customerQuery query = entityManager.createQuery("from Customer"); // ดงรำยกำรผลลพธจำกกำร Query สงกลบreturn query.getResultList();
}
@GetMapping("/customers")public String getCustomerList(Model model) {
// เรยกเมธอดจำก RepositortyList<Customer> customerList = customerRepository.findAll();model.addAttribute("customerList", customerList);return "/list";
}
<h2>ขอมลลกคา</h2><table border="1">
<tr><th>รหส</th><th>ชอ</th><th>นามสกล</th><th></th></tr><c:forEach items="${customerList}" var="customer"><tr>
<td>${customer.id}</td><td><a href="/customer/${customer.id}">${customer.firstName}</a></td><td>${customer.lastName}</td><td>
<a href="/customer/editform/${customer.id}">แกไข</a><a href="/customer/delete/${customer.id}">ลบ</a>
</td></tr></c:forEach>
</table>
หนาแสดงขอมลลกคาตามรหส
13
Model: CustomerRepository
View: detail.jsp
Controller: CustomerController
public Customer findById(Integer id) {// คนหำ Customer ตำม idreturn entityManager.find(Customer.class, id);
}
@GetMapping("/customer/{id}")public String getCustomer(@PathVariable Integer id, Model model) {
// ดงขอมลลกคำ 1 คน ตำมรหสCustomer customer = customerRepository.findById(id);model.addAttribute("customer", customer);return "/detail";
}
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%><!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
<h2>ขอมลลกคาหมายเลข ${customer.id}</h2>ชอ: ${customer.firstName}<br>นามสกล: ${customer.lastName}
</body></html>
หนาเพมขอมล
14
Model: CustomerRepository
View: customer-form.html
Controller: CustomerController
@Transactionalpublic Customer save(Customer customer) {
// insert กรณไมมคำ id ใน object หรอ update กรณมคำ id ใน object entityManager.persist(customer); return customer;
}
@PostMapping("/customer/create")public String create(@ModelAttribute Customer customer, Model model) {
customerRepository.save(customer);return "redirect:/customers";
}
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
<form action="/customer/create" method="post">ชอ: <input type="text" name="firstName"><br>สกล: <input type="text" name="lastName"><br>
<input type="submit" value="เพม"></form>
</body></html>
หนาแกไขขอมล
15
Model: CustomerRepository
View: edit-form.jsp
Controller: CustomerController
public Customer findById(Integer id) {// คนหำ Customer ตำม idreturn entityManager.find(Customer.class, id);
}
@Transactionalpublic Customer save(Customer customer) {
// insert กรณไมมคำ id ใน object หรอ update กรณมคำ id ใน object entityManager.persist(customer); return customer;
}
@GetMapping("/customer/editform/{id}")public String load(@PathVariable Integer id, Model model) {
// ดงขอมลลกคำ 1 คน ตำมรหสCustomer customer = customerRepository.findById(id);model.addAttribute("customer", customer);return "/edit-form";// สงไปแสดงผลในฟอรมแกไข
}
@PostMapping("/customer/edit") public String update(@ModelAttribute Customer editCustomer, Model model) {
// แกไขขอมลลกคำCustomer oldCustomer = customerRepository.findById(editCustomer.getId());oldCustomer.setFirstName(editCustomer.getFirstName());oldCustomer.setLastName(editCustomer.getLastName());customerRepository.save(oldCustomer);return "redirect:/customers";// สงไปยงหนำแสดงรำยกำรลกคำ
}
<form action="/customer/edit" method="post"><input type="hidden" name="id"
value="${customer.id}">ชอ: <input type="text" name="firstName"
value="${customer.firstName}"><br>สกล: <input type="text" name="lastName"
value="${customer.lastName}"><br><input type="submit" value="แกไข">
</form>
การลบขอมล
16
Model: CustomerRepository
View: list.jsp
Controller: CustomerController
@Transactionalpublic void delete(Integer id) {
// คนหำตำม id ทตองกำรลบCustomer customer = entityManager.find(Customer.class, id); entityManager.remove(customer); // เร มลบจรง
}
@GetMapping("/customer/delete/{id}") public String delete(@PathVariable Integer id) {
customerRepository.delete(id);
// สงไปยง path แสดงขอมลลกคำท งหมดreturn "redirect:/customers";
}
<h2>ขอมลลกคา</h2><table border="1">
<tr><th>รหส</th><th>ชอ</th><th>นามสกล</th><th></th></tr><c:forEach items="${customerList}" var="customer"><tr>
<td>${customer.id}</td><td><a href="/customer/${customer.id}">${customer.firstName}</a></td><td>${customer.lastName}</td><td>
<a href="/customer/editform/${customer.id}">แกไข</a><a href="/customer/delete/${customer.id}">ลบ</a>
</td></tr></c:forEach>
</table>
Spring JPA Name Query
17
public Employee findByLastName(String lastName) {
Query query = entityManager.createQuery("from Employee e where e.lastName = :LAST_NAME");
query.setParameter("LAST_NAME", lastName);
List resultList = query.getResultList();
return resultList.isEmpty() ? null : (Employee) resultList.get(0);
}
การนยามค าสง SQL ทนอกเหนอจากเมธอดท JPA ไดใหมา ใชรปแบบดงตวอยาง ซงเปนการก าหนดเงอนไข โดยไมระบวาตองการคอลมนใด ซงจะไดขอมลทกคอลมนเกบลงใน object
Spring JPA Native Query
18
public List<Employee> findAllByNativeQuery() {
Query nativeQuery = entityManager.createNativeQuery("select id, first_name, last_name
from employee", Employee.class);
return nativeQuery.getResultList();
}
หากตองการนยามค าสง SQL เองทงหมด ทนอกเหนอจากเมธอดท JPA ก าหนด ใชรปแบบดงตวอยาง