詳解SpringBoot是如何整合JPA的
SpringBoot整合JPA
JPA & Spring Data JPA
JPA是Java Persistence API的簡稱,中文名Java持久層API,是Sun官方提出的Java持久化規(guī)范.
其設(shè)計目標(biāo)主要是為了簡化現(xiàn)有的持久化開發(fā)工作和整合ORM技術(shù)。
JPA使用XML文件或注解(JDK 5.0或更高版本)來描述對象-關(guān)聯(lián)表的映射關(guān)系,能夠?qū)⑦\行期的實體對象持久化到數(shù)據(jù)庫,它為Java開發(fā)人員提供了一種ORM工具來管理Java應(yīng)用中的關(guān)系數(shù)據(jù)。
簡單地說,JPA就是為POJO(Plain Ordinary Java Object)提供持久化的標(biāo)準(zhǔn)規(guī)范,即將Java的普通對象通過對象關(guān)系映射(Object-Relational Mapping,ORM)持久化到數(shù)據(jù)庫中。
由于JPA是在充分吸收了現(xiàn)有Hibernate,TopLink,JDO等ORM框架的基礎(chǔ)上發(fā)展而來的,因而具有易于使用、伸縮性強等優(yōu)點。
Spring Data JPA 是 Spring 基于 Spring Data 框架、在JPA 規(guī)范的基礎(chǔ)上開發(fā)的一個框架,使用 Spring Data JPA 可以極大地簡化JPA 的寫法,可以在幾乎不用寫實現(xiàn)的情況下實現(xiàn)對數(shù)據(jù)庫的訪問和操作,除了CRUD外,還包括分頁和排序等一些常用的功能。
Spring Data JPA 還提供了對分頁查詢、自定義SQL、查詢指定N條記錄、聯(lián)表查詢等功能的支持
JPA不是一種新的ORM框架,它的出現(xiàn)只是用于規(guī)范現(xiàn)有的ORM技術(shù),它不能取代現(xiàn)有的Hibernate、TopLink等框架。相反,在采用JPA開發(fā)時,我們將仍將使用到這些ORM框架,只是此時開發(fā)出來的應(yīng)用不再依賴于某個持久化提供商。應(yīng)用可以在不修改代碼的情況下在任何JPA環(huán)境下運行,真正做到低耦合,可擴展的程序設(shè)計。
Hibernate & JPA
1、JPA
全稱Java Persistence API,通過JDK 5.0注解或XML描述對象-關(guān)系表的映射關(guān)系,并將運行期的實體對象持久化到數(shù)據(jù)庫中。
JPA的出現(xiàn)有兩個原因:
其一,簡化現(xiàn)有Java EE和Java SE應(yīng)用的對象持久化的開發(fā)工作;
其二,Sun希望整合對ORM技術(shù),實現(xiàn)持久化領(lǐng)域的統(tǒng)一。
JPA提供的技術(shù):
1)ORM映射元數(shù)據(jù):JPA支持XML和JDK 5.0注解兩種元數(shù)據(jù)的形式,元數(shù)據(jù)描述對象和表之間的映射關(guān)系,框架據(jù)此將實體對象持久化到數(shù)據(jù)庫表中;
2)JPA 的API:用來操作實體對象,執(zhí)行CRUD操作,框架在后臺替我們完成所有的事情,開發(fā)者從繁瑣的JDBC和SQL代碼中解脫出來。
3)查詢語言:通過面向?qū)ο蠖敲嫦驍?shù)據(jù)庫的查詢語言查詢數(shù)據(jù),避免程序的SQL語句緊密耦合。
2、JPA & Hibernate 關(guān)系
JPA是規(guī)范,Hibernate是框架,JPA是持久化規(guī)范,而Hibernate實現(xiàn)了JPA。
Hibernate VS Mybatis
Mybatis:小巧、方便、高效、簡單、直接、半自動
Hibernate:強大、方便、高效、復(fù)雜、繞彎子、全自動
一、導(dǎo)入依賴
<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.21</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
二、簡單的CRUD
2.1 配置文件
spring: datasource: username: root password: root url: jdbc:mysql://localhost:3306/shy driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource jpa: hibernate: #定義數(shù)據(jù)庫表的生成策略 create 創(chuàng)建一個表 update 更新或者創(chuàng)建數(shù)據(jù)表 ddl-auto: update #控制臺顯示sql語句 show-sql: true server: port: 80
其中,spring.jpa.hibernate.ddl-auto 參數(shù)用來配置是否開啟自動更新數(shù)據(jù)庫表結(jié)構(gòu),可取create、create-drop、update、validate、none五個值。
- create 每次加載hibernate時,先刪除已存在的數(shù)據(jù)庫表結(jié)構(gòu)再重新生成;
- create-drop 每次加載hibernate時,先刪除已存在的數(shù)據(jù)庫表結(jié)構(gòu)再重新生成,并且當(dāng) sessionFactory關(guān)閉時自動刪除生成的數(shù)據(jù)庫表結(jié)構(gòu);
- update 只在第一次加載hibernate時自動生成數(shù)據(jù)庫表結(jié)構(gòu),以后再次加載hibernate時根據(jù)model類自動更新表結(jié)構(gòu);
- validate 每次加載hibernate時,驗證數(shù)據(jù)庫表結(jié)構(gòu),只會和數(shù)據(jù)庫中的表進(jìn)行比較,不會創(chuàng)建新表,但是會插入新值。
- none 關(guān)閉自動更新
2.2 實體類
Shop:
package com.shy.entity; import lombok.Data; import javax.persistence.*; @Data //使用jpa注解 配置映射關(guān)系 @Entity//告訴jpa這是一個實體類 和數(shù)據(jù)表映射的類 public class Shop{ @Id//表明這是以一個主鍵 @GeneratedValue(strategy = GenerationType.IDENTITY)//自增 private Integer shopId; @Column(length = 20) private String shopName; private double price; private Integer shopClassId; private Integer num; }
ShopClass,商品類別
package com.shy.entity; import lombok.Data; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Data @Entity public class ShopClass { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer shopClassId; private String shopClassName; }
2.3 Dao層
編寫dao繼承JpaRepository類,泛型傳入 要操作的實體類,和主鍵類型
package com.example.dao; import com.shy.entity.Shop; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; /* 參數(shù)一 T :當(dāng)前需要映射的實體 * 參數(shù)二 ID :當(dāng)前映射的實體中的OID(映射對象標(biāo)識符,數(shù)據(jù)庫主鍵)的類型*/ @Repository public interface ShopRepository extends JpaRepository<Shop,Integer> { /* * 我們在這里直接繼承 JpaRepository * 這里面已經(jīng)有很多現(xiàn)成的方法了 * 這也是JPA的一大優(yōu)點 * 我們可以直接使用這些方法,包括其父類的好多方法。 * */ }
JpaRepository:
package org.springframework.data.jpa.repository; import java.util.List; import javax.persistence.EntityManager; import org.springframework.data.domain.Example; import org.springframework.data.domain.Sort; import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.QueryByExampleExecutor; @NoRepositoryBean public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { @Override List<T> findAll();// 查詢所有實體 @Override List<T> findAll(Sort sort);// 查詢所有實體并排序 @Override List<T> findAllById(Iterable<ID> ids);// 根據(jù)ID集合查詢實體 @Override <S extends T> List<S> saveAll(Iterable<S> entities);// 保存并返回(修改后的)實體集合 void flush();// 提交事務(wù) <S extends T> S saveAndFlush(S entity); // 保存實體并立即提交事務(wù) <S extends T> List<S> saveAllAndFlush(Iterable<S> entities); @Deprecated default void deleteInBatch(Iterable<T> entities){deleteAllInBatch(entities);} void deleteAllInBatch(Iterable<T> entities); // 批量刪除實體集合 void deleteAllByIdInBatch(Iterable<ID> ids); void deleteAllInBatch();// 批量刪除所有實體 @Deprecated T getOne(ID id);// 根據(jù)ID查詢實體 T getById(ID id); @Override <S extends T> List<S> findAll(Example<S> example);// 查詢與指定Example匹配的所有實體 @Override <S extends T> List<S> findAll(Example<S> example, Sort sort);// 查詢與指定Example匹配的所有實體并排序 }
2.4 service層
service:
package com.shy.service; import com.shy.entity.Shop; import com.shy.vo.ShopAndShopClassVo; import java.util.List; public interface ShopService { //查詢所有商品 List<Shop> findAll(); //增加商品 Shop addShop(Shop shop); //通過商品id修改商品名 Shop updateShop(); //通過商品id刪除商品 void delShop(Integer id); }
Impl:
package com.shy.service; import com.shy.dao.ShopRepository; import com.shy.entity.Shop; import com.shy.vo.ShopAndShopClassVo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import java.util.List; @Service public class ShopServiceImpl implements ShopService{ @Autowired private ShopRepository shopRepository; @Override public List<Shop> findAll() { return shopRepository.findAll(); } @Override public Shop addShop(Shop shop) { shop.setPrice(333); shop.setShopClassId(3); shop.setNum(30); shop.setShopName("耳機"); return shopRepository.save(shop); } @Override public Shop updateShop() { Shop shop = new Shop(); shop.setShopId(11); shop.setShopName("平板"); shop.setShopClassId(3); shop.setNum(40); return shopRepository.save(shop); } @Override public void delShop(Integer id) { shopRepository.deleteById(id); System.out.println("刪除成功"); } }
2.5 controller
package com.shy.controller; import com.alibaba.fastjson.JSON; import com.shy.entity.Shop; import com.shy.service.ShopService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class ShopController { @Autowired private ShopService shopService; @GetMapping("/list") public String findAll(){ return JSON.toJSONString(shopService.findAll()); } @GetMapping("/save") public String save(Shop shop){ return JSON.toJSONString(shopService.addShop(shop)); } @GetMapping("/saveAndFlush") public String saveAndFlush(){ return JSON.toJSONString(shopService.updateShop()); } @GetMapping("/delShop/{id}") public void delShop(@PathVariable Integer id){ shopService.delShop(id); } }
全程用postman測試
三、自定義SQL
在ShopRepository中添加
//使用原生sql需要加上,nativeQuery = true //?1代表第一個參數(shù) @Query(value="select * from shop where shop.price = ?1",nativeQuery = true) Shop findByPrice(Double price); //修改商品,@Modifying+@Query執(zhí)行更新操作,serviceImpl不要忘記加上,要使用hql的話,需要把entity別名刪掉 @Transactional//設(shè)計修改表的操作需要開啟事務(wù)支持 @Modifying//這個注解只支持返回值為int/Integer @Query("update Shop s set s.shopName = ?1 where s.shopId = ?2") int updateshop2(String name,Integer shopId);
service:
//通過價格查詢商品 Shop findByPrice(Double price); //修改商品名原生sql方法 int updateshop2(String name,Integer shopId);
Impl:
@Override public Shop findByPrice(Double price) { return shopRepository.findByPrice(price); } @Override public int updateshop2(String name, Integer shopId) { return shopRepository.updateshop2(name, shopId); }
controller:
@GetMapping("/listPrice/{price}") public String findByPrice(@PathVariable Double price){ return JSON.toJSONString(shopService.findByPrice(price)); } @GetMapping("/saveAndFlush2/{id}/{name}") public String saveAndFlush2(@PathVariable(value = "id") Integer shopId, @PathVariable String name){ return shopService.updateshop2(name, shopId)>0?"修改成功":"修改失敗"; }
四、分頁查詢
Pageable 是 Spring 封裝的分頁實現(xiàn)類,使用的時候需要傳入頁數(shù)、每頁條數(shù)和排序規(guī)則。
Spring Data JPA 已經(jīng)幫我們內(nèi)置了分頁功能,在查詢的方法中,需要傳入?yún)?shù) Pageable,當(dāng)查詢中有多個參數(shù)的時候 Pageable 建議作為最后一個參數(shù)傳入,
Pageable使用的時候需要傳入頁數(shù)、每頁條數(shù)和排序規(guī)則,排序規(guī)則可省略
service:
/** * 分頁查詢 * @param pageNo 第幾頁 * @param pageSize 每頁有多少條數(shù)據(jù) * @param pageable Spring 封裝的分頁實現(xiàn)類 * @return 數(shù)據(jù) */ Page<Shop> pageShop(Integer pageNo,Integer pageSize,Pageable pageable);
Impl:
@Override public Page<Shop> pageShop(Integer pageNo, Integer pageSize, Pageable pageable) { //注意排序這找的是實體類中的字段,不是數(shù)據(jù)庫里的 //分頁頁碼從0開始 pageable = PageRequest.of(pageNo,pageSize, Sort.Direction.DESC, "shopId"); return shopRepository.findAll(pageable); }
controller:
@GetMapping("/pageShop/{pageNo}/{pageSize}") public String pageShop(@PathVariable Integer pageNo, @PathVariable Integer pageSize,Pageable pageable){ return JSON.toJSONString(shopService.pageShop(pageNo, pageSize, pageable)); }
五、連表查詢
VO(value object)值對象
- 通常用于業(yè)務(wù)層之間的數(shù)據(jù)傳遞,僅僅包含數(shù)據(jù)而已
- View object:視圖對象
接受頁面?zhèn)鬟f來的對象,封裝對象
將業(yè)務(wù)處理完成的對象,封裝成頁面要用的數(shù)據(jù)
創(chuàng)建ShopAndShopClassVo用來接收連表查詢后的結(jié)果
entity,這里的有參構(gòu)造必須加,要往里賦值
package com.shy.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class ShopAndShopClassVo { private String shopName; private double price; private String shopClassName; }
ShopRepository:
//連表查詢 @Query("select new com.shy.vo.ShopAndShopClassVo(s.shopName,s.price,sc.shopClassName) from Shop s,ShopClass sc " + "where s.shopClassId=sc.shopClassId and sc.shopClassName=?1") List<ShopAndShopClassVo> findShopInfo(String shopClassName);
JPQL進(jìn)行查詢,它的特征就是與原生SQL語句類似,完全面向?qū)ο?,通過類名和屬性訪問,而不是表名和表屬性
service:
//連表查詢 List<ShopAndShopClassVo> findShopInfo(String shopClassName);
Impl:
@Override public List<ShopAndShopClassVo> findShopInfo(String shopClassName) { return shopRepository.findShopInfo(shopClassName); }
controller:
@GetMapping("/andFind/{name}") public String findShopInfo(@PathVariable("name") String shopClassName){ return JSON.toJSONString(shopService.findShopInfo(shopClassName)); }
六、分組查詢
接收數(shù)據(jù)的另一種寫法,創(chuàng)建一個結(jié)果集的接口來接收連表查詢后的結(jié)果
定義一個結(jié)果集的接口類,接口類的內(nèi)容來自于商品表和商品類別表。
entity:
package com.shy.entity; public interface GroupShop { String getNum(); String getShopClassName(); }
在運行中 Spring 會給接口(GroupShop)自動生產(chǎn)一個代理類來接收返回的結(jié)果,代碼中使用 getXX 的形式來獲取。
ShopRepository:
//分組查詢 @Query("select count(s.shopName) as 商品數(shù)量,sc.shopClassName as 類別名稱 from Shop s,ShopClass sc where s.shopClassId=sc.shopClassId group by s.shopClassId") List<GroupShop> groupShop();
service:
//分組查詢 List<GroupShop> groupShop();
Impl:
@Override public List<GroupShop> groupShop() { return shopRepository.groupShop(); }
controller:
@GetMapping("/groupShop") public String groupShop(){ return JSON.toJSONString(shopService.groupShop()); }
七、與mybatis對比
- jpa是對象與對象之間的映射,而mybatis是對象和結(jié)果集的映射
- jpa移植性比較好,不用關(guān)心用什么數(shù)據(jù)庫,因為mybatis自由寫sql語句,所以當(dāng)項目移植的時候還需要改sql。
- 修改字段時JPA更簡單,mybatis需要修改一堆的xml,mapper等文件很麻煩。
- mybatis自定義sql,比較靈活,也可以寫復(fù)雜的sql,JPA只適合簡單的單表sql
- 總結(jié):mybatis和JPA各有優(yōu)勢,如果sql簡單,則jpa使用效率更高,如果sql較復(fù)雜,需要自定義,則使用mybatis更加順手。
到此這篇關(guān)于詳解SpringBoot如何是整合JPA的的文章就介紹到這了,更多相關(guān)SpringBoot整合JPA內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springmvc+ajax+formdata上傳圖片代碼實例
這篇文章主要介紹了springmvc+ajax+formdata上傳圖片代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-09-09防止未登錄用戶操作—基于struts2攔截器的簡單實現(xiàn)
下面小編就為大家?guī)硪黄乐刮吹卿浻脩舨僮鳌趕truts2攔截器的簡單實現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10Spring框架中一個有用的小組件之Spring Retry組件詳解
Spring Retry 是從 Spring batch 中獨立出來的一個功能,主要實現(xiàn)了重試和熔斷,對于那些重試后不會改變結(jié)果,毫無意義的操作,不建議使用重試,今天通過本文給大家介紹Spring Retry組件詳解,感興趣的朋友一起看看吧2021-07-07spring+html5實現(xiàn)安全傳輸隨機數(shù)字密碼鍵盤
這篇文章主要為大家詳細(xì)介紹了spring html5實現(xiàn)安全傳輸隨機數(shù)字密碼鍵盤,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04spring boot實現(xiàn)上傳圖片并在頁面上顯示及遇到的問題小結(jié)
最近在使用spring boot搭建網(wǎng)站的過程之中遇到了有點小問題,最終解決方案是在main目錄下新建了一個webapp文件夾,并且對其路徑進(jìn)行了配置,本文重點給大家介紹spring boot實現(xiàn)上傳圖片并在頁面上顯示功能,需要的朋友參考下吧2017-12-12用C++實現(xiàn)求N!中末尾0的個數(shù)的方法詳解
這篇文章主要介紹了用C++實現(xiàn)求N!中末尾0的個數(shù)的方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Spring?Boot整合ELK實現(xiàn)日志采集與監(jiān)控
這篇文章主要介紹了Spring?Boot整合ELK實現(xiàn)日志采集與監(jiān)控,需要的朋友可以參考下2022-06-06String StringBuilder StringBuffer區(qū)別以及源碼分析
string是C++標(biāo)準(zhǔn)庫的一個重要的部分,主要用于字符串處理。可以使用輸入輸出流方式直接進(jìn)行string操作,同時,C++的算法庫對string類也有著很好的支持,并且string類還和c語言的字符串之間有著良好的接口2021-06-06