JPA @Basic單表查詢?nèi)绾螌?shí)現(xiàn)大字段懶加載
JPA @Basic單表查詢實(shí)現(xiàn)大字段懶加載
近期看了JPA@Basic注解的使用,看到該注解可以設(shè)置字段的懶加載。
1.以前碰到的懶加載:
我們知道,多表關(guān)聯(lián)的時(shí)候,我們是可以配置懶加載的,比如一個(gè)Company類,里面可以關(guān)聯(lián)員工表,辦公設(shè)備表,當(dāng)我們查看公司信息的時(shí)候,我們并不需要直接加載員工表,辦公設(shè)備表,只需要在用戶查看員工,查看設(shè)備的時(shí)候再加載,這樣可以提高加載效率。
長話短說,大概是這樣子的
@Entity
@Table(name = "Company")
public class Company {
@OneToMany(mappedBy = "cId", fetch = FetchType.LAZY)
private List<Employee> employees;
// other properties
//getters and setters
}
2、單表大字段懶加載
對于一張表時(shí),里面有一個(gè)存儲用戶頭像的字段,我們只需要當(dāng)用戶點(diǎn)入用戶詳情頁的時(shí)候才去加載頭像,其余時(shí)間不用加載。例如為什么你微信換了頭像,其他人是不能在群聊中立即看到的,需要你查看用戶詳情時(shí)才會(huì)看到一樣。
寫了一個(gè)例子:
新建test表:

實(shí)體類:
@Entity
@Table(name = "TEST")
public class TestCMP {
@Id
@IdSequenceConsumer(producerClass = UUIDProducer.class)
private String id;
@Lob
@Basic(fetch = FetchType.LAZY)
private String image;
private String name;
//getters and setters
}
repository接口:
@Repository
public interface TestRepository extends CrudRepository<TestCMP,String> {
}
測試方法:
@Test
@Transactional(value = "nwTransactionManager")
public void BasicTest3() {
TestCMP testCMP = testRepository.findOne("12345"); //懶加載,image沒有查出來
System.out.println(testCMP);
System.out.println(testCMP.getImage()); //主動(dòng)去獲取image,進(jìn)行加載
}
1、看到網(wǎng)上有同學(xué)直接設(shè)置了@Basic注解,沒有實(shí)現(xiàn)的截圖。

但我試一下,并沒有實(shí)現(xiàn)懶加載,還是一次性就加載出來了。
打出來的sql為全查,沒有實(shí)現(xiàn)懶加載:
select testcmp0_.id as id1_0_0_, testcmp0_.image as image2_0_0_, testcmp0_.name as name3_0_0_ from TEST testcmp0_ where testcmp0_.id=?
2、分析其中原因,應(yīng)是:即使我通過@Basic設(shè)置了懶加載,但有g(shù)etter,toString方法,已經(jīng)不允許它懶加載了,所以會(huì)全查。
3、讓實(shí)體類實(shí)現(xiàn)FieldHandled接口,這個(gè)接口,目的就是利用FieldInterceptorImpl這個(gè)類,他專門對懶加載的字段加了一個(gè)攔截器,能夠?qū)屑虞d的值注入到實(shí)體類中。(這類似于將懶加載的字段與原有代碼隔離開,加載的時(shí)候再寫進(jìn)去,讀出來)
將實(shí)體類改為:
@Entity
@Table(name = "TEST")
public class TestCMP implements FieldHandled{
@Id
@IdSequenceConsumer(producerClass = UUIDProducer.class)
private String id;
@Lob
@Basic(fetch = FetchType.LAZY)
private String image;
private String name;
@Transient
@JsonIgnore
private FieldHandler fieldHandler;
@Override
public void setFieldHandler(FieldHandler handler) {
this.fieldHandler = handler;
}
@Override
public FieldHandler getFieldHandler() {
return fieldHandler;
}
/**
* 獲取image
*
* @return image
*/
public String getImage() {
if (fieldHandler != null) {
return (String) fieldHandler.readObject(this, "image", this.image);
}
return null;
}
// other getters and setters
}
首先查詢sql:懶加載不查詢image
select testcmp0_.id as id1_0_0_, testcmp0_.name as name3_0_0_ from TEST testcmp0_ where testcmp0_.id=?
當(dāng)獲取image時(shí)sql:
select testcmp_.image as image2_0_ from TEST testcmp_ where testcmp_.id=?
打印testCMP的結(jié)果:
TestCMP@d56fc13[id=12345,image=<null>,name=jenkins, fieldHandler=FieldInterceptorImpl(entityName={路徑省略}.cmp.TestCMP,dirty=false,uninitializedFields=[image])]
注意點(diǎn):
第一次查詢與加載懶加載數(shù)據(jù),應(yīng)在同一個(gè)事務(wù)中,如

如果查和加載懶加載數(shù)據(jù)在不同的方法中,可以對整個(gè)service加事務(wù)@Transactional
jpa 懶加載 、N+1、指定字段查詢示例
屬性懶加載
說明:默認(rèn)情況下,實(shí)體的屬性會(huì)被立即加載(一次全部加載)。但是,我們也可以延遲加載它們。這對于存儲大量數(shù)據(jù)的列類型有用:CLOB,BLOB,VARBINARY
配置項(xiàng)
spring.jpa.open-in-view=false
@Basic(fetch = FetchType.LAZY)
查詢的實(shí)體類如果進(jìn)行g(shù)et懶加載屬性操作,會(huì)出現(xiàn)N+1性能問題
控制字段輸出
@Entity @JsonInclude(Include.NON_EMPTY)
避免對具有空值的字段進(jìn)行序列化
指定字段查詢1(接口式)
定義接口類
public class AuthorDto implements Serializable {
private static final long serialVersionUID = 1L;
private final String name;
private final int age;
public AuthorDto(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
repository
@Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {
@Transactional(readOnly = true)
List<AuthorDto> findByGenre(String genre);
}
指定字段查詢2(構(gòu)造函數(shù)式)
定義接口類
public class AuthorDto implements Serializable {
private static final long serialVersionUID = 1L;
private final String name;
private final int age;
public AuthorDto(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
repository
@Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {
@Transactional(readOnly = true)
@Query(value = "SELECT new com.bookstore.dto.AuthorDto(a.name, a.age) FROM Author a")
List<AuthorDto> fetchAuthors();
}
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java普通項(xiàng)目讀取不到resources目錄下資源文件的解決辦法
這篇文章主要給大家介紹了關(guān)于java普通項(xiàng)目讀取不到resources目錄下資源文件的解決辦法,Web項(xiàng)目中應(yīng)該經(jīng)常有這樣的需求,在maven項(xiàng)目的resources目錄下放一些文件,比如一些配置文件,資源文件等,需要的朋友可以參考下2023-09-09
Java如何獲取當(dāng)前進(jìn)程ID以及所有Java進(jìn)程的進(jìn)程ID
本篇文章主要介紹了Java如何獲取當(dāng)前進(jìn)程ID以及所有Java進(jìn)程的進(jìn)程ID,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
SpringBoot集成ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)碼播放示例詳解
這篇文章主要為大家介紹了SpringBoot集成ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)碼播放示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
解決idea打包成功但是resource下的文件沒有成功的問題
這篇文章主要介紹了解決idea打包成功但是resource下的文件沒有成功的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
web中拖拽排序和java后臺交互實(shí)現(xiàn)方法示例
這篇文章主要給大家介紹了關(guān)于web中拖拽排序和java后臺交互實(shí)現(xiàn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12
有關(guān)ServletConfig與ServletContext的訪問
下面小編就為大家?guī)硪黄嘘P(guān)ServletConfig與ServletContext的訪問。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01
SpringBoot使用CXF集成WebService的方法
這篇文章主要介紹了SpringBoot使用CXF集成WebService的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08

