iT邦幫忙

2021 iThome 鐵人賽

DAY 13
1

JPA,全名為Java Persistence API,是Sun 官方提出的Java 持久化規範,它為Java 開發人員提供了一種物件/關聯映射工具來管理Java 應用中的關係實體物件,它的出現主要是為了簡化現有的持久化開發工作和整合ORM 技術

Spring Data JPA 是Spring 在ORM 框架、JPA 規範的基礎上封裝了一套JPA 應用框架,可使開發者用極簡的程式碼即可實現對資料庫的訪問和操作

需要注意的是Spring Data JPA 新增與更新操作都是使用save() 方法進行,JPA 會透過主鍵去查詢是否存在,不存在就INSERT,存在就是UPDATE,其中,JPA 只能判斷INSERT 或是UPDATE並不能判斷出是否更新部分欄位所以沒有被賦值的欄位都會被覆蓋為NULL

實作

新增依賴

<!-- JPA -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

設定JPA 基本配置

  • spring.jpa.hibernate.ddl-auto :
    • create : 每次載入Hibernate 時,會刪除上次生成的資料表,再根據Model 類別重新生成資料表。

    • craete-drop : 每次載入Hibernate 時都根據Model 類別生成資料表,但sessionFactory 一關閉就自動刪除資料表。

    • update : 第一次載入Hibernate 時根據Model 類別生成資料表,之後載入Hibernate 時根據Model 類別更新資料表,即使資料表結構改變,但不會刪除以前的欄位。
      要注意的是,當部署到伺服器後,不會馬上建立資料表,要等第一次應用時才會建立

    • validate : 每次載入Hibernate 時驗證建立資料表,只會和資料庫中的資料表進行比較,不會建立新的資料表,但會插入新值。

    • none : 無動作。

  • spring.jpa.show-sql : 是否在Console 顯示執行的SQL 語句。
# JPA 設定
spring.jpa.hibernate.ddl-auto=update

# 顯示SQL 語句
spring.jpa.show-sql=true

啟用JPA 自動賦值

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class SpringBootDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootDemoApplication.class, args);
	}

}

調整實體類

  • @Entity : 宣告為實體類。
  • @Table : 對應資料表名稱。
  • @Id : 設定為PRIMARY KEY。
  • @GeneratedValue : 設定該Column 生成方式。
    • GenerationType.AUTO : 自動產生。
    • GenerationType.IDENTITY : 資料庫維護。
  • @Column : 對應資料表欄位名稱。
package com.example.demo.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@Entity
@Table(name = "member_account")
public class MemberAccount extends Base {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "ID")
	private String id;

	@Column(name = "USERNAME", unique = true)
	private String username;

	@Column(name = "PASSWORD")
	private String password;

	@Column(name = "SALT")
	private String salt;

}
  • @MappedSuperclass : 宣告為實體類的父類別,它並不是完整的實體類,所以不會映射到資料表,但它的屬性會映射到它的子類別資料表中,可用於設定相同欄位。
  • @EntityListeners(AuditingEntityListener.class) : 監聽器,自動賦值創建時間、修改時間
  • @CreateBy : 設定為建立者,當實體被INSERT 時會預設值。
  • @CreatedDate : 設定為建立時間,當實體被INSERT 時會預設值。
  • @Temporal(TemporalType.TIMESTAMP) : 宣告該Column 儲存到資料表時的時間精度,該註解僅適用於被宣告為java.util.DATE 或java.util.Calendar 的屬性。
    • TemporalType.DATE : 日期。
    • TemporalType.TIME : 時間。
    • TemporalType.TIMESTAMP : 日期和時間。
  • @LastModifiedBy : 設定為修改者,當實體被UPDATE 時會預設值。
  • @LastModifiedDate : 設定為修改時間,當實體被UPDATE 時會預設值。
package com.example.demo.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Base {

	@CreatedBy
	@Column(name = "CREATE_BY")
	private String create_by;

	@CreatedDate
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "CREATE_TIME")
	private Date create_time;

	@LastModifiedBy
	@Column(name = "UPDATE_BY")
	private String update_by;

	@LastModifiedDate
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "UPDATE_TIME")
	private Date update_time;

}

建立持久層接口

package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.demo.entity.MemberAccount;

public interface MemberAccountRepository extends JpaRepository<MemberAccount, Long> {

	public MemberAccount findByUsername(String username);

}

測試功能

package com.example.demo.repository;

import java.util.UUID;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.example.demo.entity.MemberAccount;

@SpringBootTest
public class MemberAccountRepositoryTest {

	@Autowired
	private MemberAccountRepository memberAccountRepository;

	@Test
	public void insert() {
		MemberAccount memberAccount = new MemberAccount();
		memberAccount.setUsername("username@email.com");
		memberAccount.setPassword("password");

		String salt = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");
		memberAccount.setSalt(salt);
		memberAccount.setCreate_by(memberAccount.getUsername());
		memberAccount.setUpdate_by(memberAccount.getUsername());

		memberAccountRepository.save(memberAccount);
		System.out.println(memberAccount.getId());
	}

	@Test
	public void findByUsername() {
		String username = "username@email.com";
		MemberAccount memberAccount = memberAccountRepository.findByUsername(username);
		if(memberAccount != null) System.out.println(memberAccount.toString());
	}

	@Test
	public void update() {
		String username = "username@email.com";
		MemberAccount memberAccount = memberAccountRepository.findByUsername(username);
		memberAccount.setPassword("123456");

		memberAccountRepository.save(memberAccount);
	}

}

Github

使用JPA 建立持久層及其測試方法

參考網站

Java持久化API
Spring Data JPA
Spring Data JPA : Auditing with @CreatedBy, @CreatedDate, @LastModifiedBy and @LastModifiedDate


上一篇
Day 12 - Spring Boot & MyBatis
下一篇
Day 14 - Spring Boot & Thymeleaf
系列文
誤打誤撞學了Spring Boot 還當了後端工程師30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言