Basic Spring Part 4 - Connect SQL Database
ผมเขียนเกี่ยวกับ Spring ไว้หลายตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ Spring ตอนต่างๆได้เลย
- Basic Spring Part 1 - Spring framework & Dependency Injection
- Basic Spring Part 2 - Create Project & Start Web Application
- Basic Spring Part 3 - Dependency injection ใน Spring framework
- Basic Spring Part 4 - Connect SQL Database
สำหรับตอนนี้เราจะมาพูดถึงการต่อ Database กับนะครับว่าจะต่อ Database ยังไงต้องทำอะไรบ้าง สำหรับตอนนี้อาจจะใช้ Database อันนี้ผมแนะนำให้ใช้ Docker สร้าง Container ที่เป็น MySQL Database มาใช้งานนะครับ (เพราะง่าย) โดยวิธีการสร้างนั้นตาม Link นี้ไปเลย หรือใครไม่ถนัดก็สามารถ Install ตัว Mysql Server ได้เลยครับ
ในส่วนของ Code นั้นสามารถไปดูได้ที่ Github ได้เลย
Init Project
ทำการเข้า Web : https://start.spring.io/ จากนั้นทำการเลือกตามภาพด้านล่างและกด Generate
โดยตัวที่เราเพิ่มคือ Spring jpa data ซึ่งเป็น Lib ที่ทำให้เราเชื่อมต่อกับ SQL Database ได้ จากนั้นทำการเปิดด้วย IDE จากนั้นลองทำการ Start server ดูก็จะพบว่า Error ดังภาพซึ่งเกิดจากเราไม่ได้ทำการ Config ค่าในการเชื่อมต่อ Database
ดังนั้นจึงทำการ Config ก่อน โดยการ Config นั้นจะต้องทำที่ไฟล์ : src/main/resources/application.properties โดยต้องเพิ่ม properties ดังต่อไปนี้
1 | # ตรงนี้คือ jdbc url คือ url ไปหาตัว database ซึ่ง database ของผมอยู่ที่ 192.168.56.101 port 3306 ซึ่งจะไม่เหมือนกับเครื่องของคุณแน่นอน |
เมื่อตั้งค่าเสร็จให้ลองทำการ Start server อีกครั้ง
ซึ่งจะพบว่า Error ใหม่ซึ่งเกี่ยวกับการหา Driver ไม่เจอซึ่งสามารถแก้ไขได้จากการเพิ่ม Dependency ที่เป็น Driver ของ mysql โดยไปเพิ่มที่ไฟล์ : pom.xml
1 | <dependency> |
จากนั้นลองทำการ Start server อีกครั้ง ซึ่งคราวนี้จะพบว่าสามารถ Start server สำเร็จแล้ว
สร้าง Map Class กับ Table
ตัว Lib ที่เราใช้เชื่อมต่อกับ Database นั้นเราจะใช้ Lib : JPA โดย Concept ของ JPA คือเป็นตัวกลางที่จะแปลง Java Class ให้กลายเป็นข้อมูลที่จะไปอยู่ใน Table โดยตัว Lib จะแปลงข้อมูลเป็นคำสั่ง SQL ซึ่ง
ข้อดี
- ง่ายในการเก็บข้อมูลไม่ต้องเขียน SQL เอง แค่ Set ค่าลงใส่ Object จากนั้นสั่ง Save ก็เป็นการ Insert หรือ Update ได้เลย เช่นกัน เวลาค้นหาข้อมูลก็จะดึงข้อมูลออกมาจาก Database มาใส่ใน Object ให้สามารถใช้งานได้เลย
- สามารถเปลี่ยนตัว SQL Database เป็นยี่ห้ออื่นก็ได้ทันที เช่น สามารถเปลี่ยนจาก MYSQL เป็น MARIADB ได้เลยเพียงเปลี่ยน Config ไม่ต้องทำการแก้ Code เลย
ข้อเสีย
- ไม่ยืดหยุ่นเท่าจัดการแบบ Native Query เพราะ JPA ต้องการความเป็นสามารถใช้ได้ทุก DB จึงไม่สามารถใช้ Function ที่เฉพาะเจาะจงกับ DB นั้นได้ (ทำได้แต่เปลี่ยน DB ต้องแก้ Code)
- เวลาดึงข้อมูลนั้นจะดึงทุก Field ใน Table นั้นออกมาเพื่อ Map กับ Class ว่าง่ายๆมัน SELECT * เอา Field ที่ไม่ได้อยากใช้ออกมาด้วย ทำให้สิ้นเปลือง (สามารถดึงเฉพาะ Field ได้แต่ต้องสร้าง Class ใหม่)
Entity
Class ที่ใช้ Map กับตัว Table นั้นเราจะเรียกมันว่า Entity โดยเราจะลองสร้าง Class ที่ชื่อว่า People เก็บข้อมูลเกี่ยวกับบุคคล ดัง Code ข้างล่าง
1 | package test.spring.webdb.entity; |
1 |
|
@Entity ส่วนนี้เป็นการบอกว่า Class นี้เป็น Entity
@Table เป็นการบอกว่า Enttiy นี้เชื่อมกับ Table ที่ชื่อ people
1 |
|
@Id ส่วนนี้บอกว่า Attribute นี้จะเป็น Primary key
@Column ส่วนนี้เป็นการบอกว่า Attribute นี้ผูกกับ Column ที่ชื่อ ID
Repository
Repository เป็น Service ที่เราใช้เชื่อมต่อกับ Database
1 | package test.spring.webdb.repository; |
1 | public interface PeopleRepository extends JpaRepository<People, String> |
ตรง JpaRepository<People, String> เป็นการบอกว่า Repository นี้จะใช้กับ Entity : People โดยมี Primary key เป็น type : String
ลองใช้งาน
1 | package test.spring.webdb.controller; |
เราจะทำการสร้าง object : people แล้วทำการ save ค่าลง Database โดยใช้ peopleRepository ซึ่ง peopleRepository นั้นมาจากการ Inject เข้ามาโดยตัว Spring จะทำการสร้าง Object ให้เราโดยอัตโนมัติ คราวนี้เรามาลอง Start server และยิง Request ดูครับ ซึ่งจะพบว่า Error ซึ่งเกิดขึ้นเพราะเราไม่ได้สร้าง Table ไว้
ซึ่งวิธีแก้นั้นไม่ยากเราสามารถไปสร้าง Table เอง หรือ ให้ตัว spring ทำการสร้างได้โดยไปทำการ Config เพิ่มที่ application.properties
1 | spring.jpa.hibernate.ddl-auto=update |
โดยตัว config นี้จะทำการ Update ตัวโครงสร้าง table ให้อัตโนมัติแนะนำให้ใช้ช่วง dev อย่างเดียว
จากนั้นลองทำการ Start server อีกครั้งแล้วลองยิง Request จะเห็นว่าไม่ Error แล้ว ซึ่งเมื่อไป check ใน Database ก็จะเห็นว่ามีข้อมูลแล้วดังภาพ
มา Insert เข้าไปจริง แต่เราอยากเห็นคำสั่ง SQL อะ จะได้มั่นใจว่ามันทำงานถูกต้อง ตรงส่วนนี้ก็สามารถ Config ได้ครับ โดยเพิ่ม config ที่ application.properties
1 | spring.jpa.properties.hibernate.show_sql=true |
ซึ่งเมื่อลองยิง Request ใหม่จะเห็นว่ามี SQL Query โผล่ขึ้นมาให้เห็นแล้ว ตรงนี้อาจจะงงว่าทำไมมี SELECT ด้วย คือไม่ต้องตกใจครับตัว JPA เขาต้องการเช็คก่อนว่าเคยมี Object นี้อยู่ใน Table ไหม เขาเลยต้องทำการ SELECT ด้วย ID ก่อนเพื่อหาว่ามีไหม ถ้าไม่มีเขาจะสร้าง SQL INSERT แต่ถ้ามีเขาจะสร้าง SQL UPDATE แทน
SELECT ด้วยเงื่อนไขต่างๆ
ตอนนี้เราสามารถเก็บข้อมูลลง Database ได้แล้ว คราวนี้เรามาลอง SELECT ข้อมูลกันดูบ้าง โดยอย่างแรกเพิ่มข้อมูลลง database กันก่อน
1 | insert into people (ID, FULL_NAME, AGE, ADDRESS) values ('3aec3c1d-ffa5-4775-8528-80f8b99bc6e5', 'Thorstein Betchley', 36, '9 Springs Road'); |
Build in method
ตัว Spring มี Build in method ที่ใช้ในการค้นหาอยู่แล้วตัวอย่างเช่น findById() , findAll() ตรงนี้สามารถใช้ได้เลยไม่ต้องทำการเขียนเพิ่มเอง
สร้างเงื่อนไขโดยการใช้ชื่อ Method
ถ้า Advance ขึ้นมาหน่อยเราอยากข้อมูลด้วย Field ต่างๆด้วยเงื่อนไขเท่ากับ มากกว่าน้อยกว่า เราก็สามารถสร้างโดยการตั้งชื่อ method โดยมีรายละเอียดดังนี้ Link เช่น ถ้าอยากค้นหาด้วยเงื่อนไขอายุมากกว่า x และชื่อขึ้นต้นด้วย y ก็จะสามารถเขียนชื่อ Method ได้แบบนี้
1 | public interface PeopleRepository extends JpaRepository<People, String> { |
คราวนี้ลองไปทดลองใช้งานที่ Controller
1 |
|
ซึ่งเมื่อลองใช้งานแล้วจะได้ผลลัพธ์ดังภาพด้านล่าง
อยากเขียน Query เองไม่อยากสร้างจากชื่อ Method
ในบางกรณีที่ Query มีความซับซ้อนมากๆ หรือ SELECT หลายๆ Field ตัว Spring ก็เปิดโอกาสให้เราเขียน Query นั้นเองโดยใช้ @Query โดย Syntax ที่ใช้ในการเขียนนั้นจะใช้ Syntax JPQL โดยถ้าเราจะใช้เงื่อนไขเดียวกับ Query ก่อนหน้านี้เราสามารถเขียนได้ดังนี้
1 | public interface PeopleRepository extends JpaRepository<People, String> { |
คราวนี้ทดลองใช้งานที่ Controller
1 |
|
ซึ่งเมื่อทดลองยิงแล้วจะได้ผลลัพธ์ดังภาพด้านล่าง
ทำ Order และ Pagination ยังไง
คือการดึงข้อมูลนั้นเราคงไม่ดึงข้อมูลทั้งหมดที่ตรงเงื่อนไขกลับไปแน่นอนเพราะมันเปลืองแถมไม่แน่ว่าคน Select เขาไม่ได้สนใจข้อมูลหลังๆด้วย ลองนึกภาพการ Search ของ Google ดูครับ เขาจะแสดงผลการ Search เป็นหน้าๆ เพื่อลดการส่งข้อมูลไปกลับระหว่าง Client กับ Server โดยตัว Spring สามารถทำได้โดย
1 | Page<People> findByAgeGreaterThanAndFullNameStartingWith(Integer age, String fullName, Pageable pageable); |
จะเห็นว่าเราทำการเพิ่ม parameter อีกตัวคือ Pageable ซึ่งเป็นตัวแปรที่เป็นการบอกว่าจะ Order ด้วยอะไร จะเอาข้อมูล Page ไหน แล้วแต่ละ Page มีขนาดเท่าไหร่ โดยตัวอย่างการใช้งานจะเป็นแบบนี้
1 |
|
โดยตัวอย่างนั้นเราจะดึงข้อมูล Page แรก (เริ่มที่ 0) และ Page มีขนาด 2 โดยเรียงแบบมากไปน้อยด้วยค่า age ซึ่งจะได้ผลลัพธ์เป็น
สรุป
สำหรับตอนนี้พูดถึงการเชื่อมต่อ Database ว่าทำยังไง ต้องสร้าง Entity ต้องสร้าง Repository ซึ่งด้วยความรู้ประมาณนี้ก็สามารถเขียน Web application server กันได้แล้ว ในส่วนของตอนถัดไปนั้นขอคิดดูก่อนว่าจะเขียนอะไรเพราะทั้ง 4 ตอนก็ครอบคลุมการเขียน Web application server แล้ว ไม่แน่อาจจะไปเขียนเรื่องอื่นเลยก็ได้ สุดท้ายก็ฝากติดตาม Page Normal Programmer ของผมด้วย
เพลงประกอบการเขียน Blog
เพลงเกี่ยวก้อยของวง Wisdom ลองไปฟังดูครับ