詳解SpringBoot?JPA常用注解的使用方法
1. 簡(jiǎn)介
Jpa 是一套ORM 的規(guī)范
hibernate 不就是一個(gè) ORM 框架也提供了對(duì)于 JPA 的實(shí)現(xiàn)
JPA(Java Persistence API):java 持久化 API
2. 常用注解
2.1 @Entity
標(biāo)注當(dāng)前類為實(shí)體類,將映射到指定的數(shù)據(jù)庫(kù)表中
@Entity public class Users { }
2.2 @Table
一般與 @Entity 注解一起使用,如果數(shù)據(jù)庫(kù)表名和類名一致時(shí)不使用 @Table 注解也是可以的,
否則需要使用 @Table 注解來(lái)指定表名
@Entity @Table(name="t_users") public class Users { }
2.3 @Id 、@GeneratedValue、@SequenceGenerator、@Column
2.3.1 @Id
用于將實(shí)體類的屬性映射為主鍵
2.3.2 @GeneratedValue
指定主鍵生成策略
package javax.persistence; /** * 策略類型 */ public enum GenerationType { /** * 通過表產(chǎn)生主鍵,框架借由表模擬序列產(chǎn)生主鍵,使用該策略可以使應(yīng)用更易于數(shù)據(jù)庫(kù)移植 */ TABLE, /** * 通過序列產(chǎn)生主鍵,通過 @SequenceGenerator 注解指定序列名 * MySql 不支持這種方式 * Oracle 支持 */ SEQUENCE, /** * 采用數(shù)據(jù)庫(kù) ID自增長(zhǎng)的方式來(lái)自增主鍵字段 * Oracle 不支持這種方式; */ IDENTITY, /** * 缺省值,JPA 根據(jù)數(shù)據(jù)庫(kù)自動(dòng)選擇 */ AUTO; private GenerationType() { } }
2.3.3 @SequenceGenerator
2.3.4 @Column
當(dāng)實(shí)體類屬性名和數(shù)據(jù)庫(kù)列名不一致時(shí)必須要使用此注解
@Entity @Table(name="t_users") public class Users { @Id @Column(name = "user_id") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") @SequenceGenerator(name = "user_seq", sequenceName = "user_seq") private Long userId; }
2.4 @Transient
表示當(dāng)前屬性無(wú)需映射到數(shù)據(jù)庫(kù)中
2.5 @Temproal
主要針對(duì) Date 類型的屬性使用,可以通過該注解指定時(shí)間的精度
@Entity @Table(name="t_users") public class Users { @Temporal(TemporalType.DATE) private Date time1; @Temporal(TemporalType.TIME) private Date time2; @Temporal(TemporalType.TIMESTAMP) private Date time3; }
3. EntityManagerFactory
類似與 hibernate 的 SessionFactory
4. EntityManager 實(shí)體的四種狀態(tài)
新建狀態(tài): 新創(chuàng)建還未擁有持久性主鍵持久化狀態(tài): 已經(jīng)擁有持久性主鍵并和持久化建立了上下文關(guān)系游離狀態(tài): 擁有持久性主鍵,但沒有和持久化建立上下文關(guān)系刪除狀態(tài): 擁有持久性主鍵,并且和持久化建立了上下文關(guān)系,但是從數(shù)據(jù)庫(kù)中刪除了
4.1 find(Class entityClass, Object primaryKey)
類似于 hibernate 中 session 的 get()
find 如果沒有查詢到會(huì)返回 null
4.2 getReference(Class entityClass, Object primaryKey)
類似與 hibernate 中 session 的 load()
只有當(dāng)真正獲取對(duì)象中的屬性時(shí),才會(huì)去執(zhí)行查詢的 sql 語(yǔ)句,getReference() 只是返回了一個(gè)代理對(duì)象
getReference 如果沒有查詢到不會(huì)返回 null , 會(huì)拋出 EntityNotFoundException
注意:使用此方法可能出現(xiàn)懶加載異常的情況,也就是我們還沒有去獲取實(shí)體類中的屬性值,結(jié)果 EntityManager 就已經(jīng)被關(guān)閉了
4.3 persist
類似與 hibernate 中 session 的 save()
注意:執(zhí)行方法時(shí)傳入的對(duì)象不能為主鍵設(shè)置值會(huì)拋出異常
4.4 remove
類似與 hibernate 中 session 的 delete()
注意:該方法只能刪除持久化對(duì)象,而不能刪除游離狀態(tài)的對(duì)象(hibernate 可以)
/** * 刪除游離態(tài)(失敗) */ public void testRemove(){ Users user = new Users(); Users.setUserId(1); entityManager.remove(customer); } /** * 刪除持久化狀態(tài)(成功) */ public void testRemove(){ Users user = entityManager.find(Users.class, 1); entityManager.remove(user); }
4.5 merge(T entity)
類似與 hibernate 中 session 的 saveOrUpdate()
// 新建狀態(tài) public void testMerge (){ Users user= new Users(); // 省略一系列的set // user.set..... Users newUser = entityManager.merge(user); // user.getUserId() == null ==> true // newUser.getUserId() == null ==> false }
4.6 flush()
類似與 hibernate 中 session 的 flush()
將上下文中所有未保存的實(shí)體保存到數(shù)據(jù)庫(kù)中
4.6 refresh()
類似與 hibernate 中 session 的 refresh()
刷新所有實(shí)體的屬性值
5. EntityTransaction
EntityManager.getTransaction()
5.1 begin
5.2 commit
5.3 rollback
6. 映射關(guān)系
6.1 單向一對(duì)多
以用戶和訂單之間的關(guān)系為例,一個(gè)用戶有多個(gè)訂單,一個(gè)訂單只屬于一個(gè)用戶
對(duì)于一對(duì)多關(guān)系的 insert,無(wú)論是先插入多的一方還是一的一方都會(huì)產(chǎn)生額外的 update 語(yǔ)句,因?yàn)槎嗟囊欢嗽?insert 時(shí)不會(huì)插入外鍵的列
/** * 訂單和用戶是多對(duì)一的關(guān)系 */ @Entity @Table(name="t_order") public class Order { // lazy為懶加載,默認(rèn)為eager立即查詢 @ManyToOne(fetch=FetchType.Lazy) // @JoinColumn標(biāo)注字段是一個(gè)類,userId為該類的主鍵 @JoinColumn(name="user_id") private Users user; }
6.2 單向多對(duì)一
以用戶和訂單之間的關(guān)系為例,一個(gè)用戶有多個(gè)訂單,一個(gè)訂單只屬于一個(gè)用戶
對(duì)于多對(duì)一關(guān)系的 insert,最好先保存一的一端然后在保存多的一端。
如果先保存多的一端再保存一的一端,為了維護(hù)外鍵的關(guān)系,需要對(duì)多的一端進(jìn)行額外的update的操作
/** * 訂單和用戶是多對(duì)一的關(guān)系 */ @Entity @Table(name="t_order") public class Order { // lazy為懶加載,默認(rèn)為eager立即查詢 @ManyToOne(fetch=FetchType.Lazy) // @JoinColumn標(biāo)注字段是一個(gè)類,userId為該類的主鍵 @JoinColumn(name="user_id") private Users user; }
6.3 雙向多對(duì)一
以用戶和訂單之間的關(guān)系為例,一個(gè)用戶有多個(gè)訂單,一個(gè)訂單只屬于一個(gè)用戶
雙向多對(duì)一就是以上兩個(gè)的結(jié)合,同時(shí)使用 @OneToMany 和 @ManyToOne
/** * 用戶和訂單是一對(duì)多的關(guān)系 */ @Entity @Table(name="t_users") public class User { // 如果兩側(cè)都要描述關(guān)聯(lián)關(guān)系的話,維護(hù)關(guān)聯(lián)關(guān)系的任務(wù)要交給多的一方 // 使用 @OneToMany 了 mappedBy 的代表不維護(hù)關(guān)聯(lián)關(guān)系,也就是不會(huì)產(chǎn)生額外的update語(yǔ)句 // @OneToMany 和 @JoinColumn 不能同時(shí)使用會(huì)報(bào)錯(cuò) @OneToMany(mappedBy="user") private Set<Orders> orders; } /** * 訂單和用戶是多對(duì)一的關(guān)系 */ @Entity @Table(name="t_orders") public class Order { // lazy為懶加載,默認(rèn)為eager立即查詢 @ManyToOne(fetch=FetchType.Lazy) // @JoinColumn標(biāo)注字段是一個(gè)類,userId為該類的主鍵 @JoinColumn(name="user_id") private Users user; }
6.4 雙向一對(duì)一
以學(xué)校和校長(zhǎng)之間的關(guān)系為例,一個(gè)學(xué)校只有一個(gè)校長(zhǎng),一個(gè)校長(zhǎng)也只屬于一個(gè)學(xué)校
一方使用 @OneToMany + @JoinColumn,另一方使用 @OneToOne(mappedBy=“xx”)
具體由哪一方維護(hù)關(guān)聯(lián)關(guān)系都可以,這里我們以學(xué)校一端維護(hù)關(guān)聯(lián)關(guān)系為例
保存時(shí)先保存不維護(hù)關(guān)聯(lián)關(guān)系的一方(也就是使用@OneToOne(mappedBy=“xx”)的一方),否則會(huì)產(chǎn)生額外的 update 語(yǔ)句
/** * 學(xué)校 */ @Entity @Table(name="t_school") public class School { // 默認(rèn)為eager立即查詢 @OneToOne // 添加唯一約束 @JoinColumn(name="school_master_id", unique = true) private SchoolMaster schoolMaster; } /** * 校長(zhǎng) */ @Entity @Table(name="t_school_master") public class SchoolMaster { // 不維護(hù)關(guān)聯(lián)關(guān)系要使用 mappedBy @OneToOne(mappedBy="schoolMaster") private School school; }
6.5 雙向多對(duì)多
以學(xué)生和課程之間的關(guān)系為例,一個(gè)學(xué)生可以選多門課,一個(gè)課程也有多個(gè)學(xué)生,多對(duì)多需要一個(gè)中間表,也就是選課表
維護(hù)關(guān)聯(lián)關(guān)系的一方需要使用 @JoinTable
關(guān)聯(lián)關(guān)系也是只有一方維護(hù)即可,這里我們由學(xué)生表進(jìn)行維護(hù)
/** * 學(xué)生 */ @Entity @Table(name="t_student") public class Student { @GeneratedValue @Id private Long student_id; // 要使用 set 集合接收 // 默認(rèn)為lazy懶加載 @ManyToMany // name 為中間表的表名 @JoinTable(name="t_student_choose_course", // name 為與中間表與當(dāng)前表所關(guān)聯(lián)的字段的名稱,referencedColumnName 為當(dāng)前表中與中間表關(guān)聯(lián)的字段的名稱 joinColumns={@JoinColumn(name="student_id", referencedColumnName="student_id")}, // name 為與中間表與多對(duì)多另一方表所關(guān)聯(lián)的字段的名稱,referencedColumnName 為多對(duì)多另一方與中間表關(guān)聯(lián)的字段的名稱 inverseJoinColumns={@JoinColumn(name="course_id", referencedColumnName="course_id")}) private Set<Course> courses; } /** * 課程 */ @Entity @Table(name="t_course") public class Course { @GeneratedValue @Id private Long course_id; // 要使用 set 集合接收 // 默認(rèn)為lazy懶加載 @ManyToMany(mappedBy="courses") private Set<Student> students; }
7. 二級(jí)緩存
開啟了二級(jí)緩存之后,緩存是可以跨越 EntityManager 的,
默認(rèn)是一級(jí)緩存也就是在一個(gè) EntityManager 中是有緩存的
二級(jí)緩存可以實(shí)現(xiàn),關(guān)閉了 EntityManager 之后緩存不會(huì)被清除
使用 @Cacheable(true) 開啟二級(jí)緩存
8. JPQL
8.1 查詢接口
8.1.1 createQuery
public void testCreateQuery(){ // 這里我們使用了一個(gè) new Student,因?yàn)槲覀兪遣樵?Student 中的部分屬性,如果不適用 new Student 查詢返回的結(jié)果就不是 Student 類型而是一個(gè) Object[] 類型的 List // 也可以在實(shí)體類中創(chuàng)建對(duì)應(yīng)的構(gòu)造器,然后使用如下這種 new Student 的方式,來(lái)把返回結(jié)果封裝為Student 對(duì)象 String jpql = "SELECT new Student(s.name, s.age) FROM t_student s WHERE s.student_id > ?"; // setParameter 時(shí)下標(biāo)是從1開始的 List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList(); }
8.1.2 createNamedQuery
需要在類上使用 @NamedQuery 注解,事先聲明 sql 語(yǔ)句
@NamedQuery(name="testNamedQuery", query="select * from t_student WHERE student_id = ?") @Entity @Table(name="t_student") public class Student { @GeneratedValue @Id private Long student_id; @Column private String name; @Column private int age; }
public void testCreateNamedQuery(){ Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3); Student student = (Student) query.getSingleResult(); }
8.1.3 createNativeQuery
public void testCreateNativeQuery(){ // 本地sql的意思是只能在數(shù)據(jù)庫(kù)中執(zhí)行的sql語(yǔ)句 String sql = "SELECT age FROM t_student WHERE student_id = ?"; Query query = entityManager.createNativeQuery(sql).setParameter(1, 18); Object result = query.getSingleResult(); }
8.2 關(guān)聯(lián)查詢
存在一對(duì)多關(guān)系時(shí),當(dāng)我們查詢一的一端時(shí),默認(rèn)多的一端是懶加載。此時(shí)我們?nèi)绻胍淮涡圆樵兂鏊械臄?shù)據(jù)就需要使用關(guān)聯(lián)查詢
注意: 下面 sql 中的重點(diǎn)就是要加上 fetch u.orders,表示要查詢出用戶所關(guān)聯(lián)的所有訂單
public void testLeftOuterJoinFetch(){ String jpql = "FROM t_users u LEFT OUTER JOIN FETCH u.orders WHERE u.id = ?"; Users user = (Users) entityManager.createQuery(jpql).setParameter(1, 123).getSingleResult(); }
到此這篇關(guān)于詳解SpringBoot JPA常用注解的使用方法的文章就介紹到這了,更多相關(guān)SpringBoot JPA使用方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springcloud-gateway整合jwt+jcasbin實(shí)現(xiàn)權(quán)限控制的詳細(xì)過程
這篇文章主要介紹了springcloud-gateway整合jwt+jcasbin實(shí)現(xiàn)權(quán)限控制,基于springboot+springcloud+nacos的簡(jiǎn)單分布式項(xiàng)目,項(xiàng)目交互采用openFeign框架,單獨(dú)提取出來(lái)成為一個(gè)獨(dú)立的model,需要的朋友可以參考下2023-02-02Spring Data JPA例子代碼[基于Spring Boot、Mysql]
這篇文章主要介紹了Spring Data JPA例子代碼[基于Spring Boot、Mysql],小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-04-04如何自動(dòng)生成Mybatis的Mapper文件詳解
這篇文章主要給大家介紹了關(guān)于如何自動(dòng)生成Mybatis的Mapper文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Mybatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07SpringCloudAlibaba整合Feign實(shí)現(xiàn)遠(yuǎn)程HTTP調(diào)用的簡(jiǎn)單示例
這篇文章主要介紹了SpringCloudAlibaba 整合 Feign 實(shí)現(xiàn)遠(yuǎn)程 HTTP 調(diào)用,文章中使用的是OpenFeign,是Spring社區(qū)開發(fā)的組件,需要的朋友可以參考下2021-09-09