Spring Boot 整合 JPA

The Matrix

JPA介紹

JPA(Java Persistence API)是Sun官方提出的Java持久化規(guī)范古掏。它為Java開發(fā)人員提供了一種對象/關聯(lián)映射工具來管理Java應用中的關系數(shù)據(jù)盘榨。他的出現(xiàn)主要是為了簡化現(xiàn)有的持久化開發(fā)工作和整合ORM技術壶运,結(jié)束現(xiàn)在Hibernate剑勾,TopLink炉爆,JDO等ORM框架各自為營的局面榜配。值得注意的是祠汇,JPA是在充分吸收了現(xiàn)有Hibernate,TopLink失暂,JDO等ORM框架的基礎上發(fā)展而來的彼宠,具有易于使用,伸縮性強等優(yōu)點弟塞。

注意:JPA是一套規(guī)范凭峡,不是一套產(chǎn)品,那么像Hibernate,TopLink,JDO他們是一套產(chǎn)品决记,如果說這些產(chǎn)品實現(xiàn)了這個JPA規(guī)范摧冀,那么我們就可以叫他們?yōu)镴PA的實現(xiàn)產(chǎn)品。

Spring Data JPA

Spring Data JPA 是 Spring 基于 ORM 框架系宫、JPA 規(guī)范的基礎上封裝的一套JPA應用框架索昂,可使開發(fā)者用極簡的代碼即可實現(xiàn)對數(shù)據(jù)的訪問和操作。它提供了包括增刪改查等在內(nèi)的常用功能扩借,且易于擴展椒惨!學習并使用 Spring Data JPA 可以極大提高開發(fā)效率!Spring Data JPA讓我們解脫了DAO層的操作往枷,基本上所有CRUD都可以依賴于它來實現(xiàn)框产。

構建項目

打開pom.xml添加相關依賴

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>
    <dependencies>
                <!-- 分頁插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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-tomcat</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>

配置數(shù)據(jù)源以及JPA

spring.datasource.url=jdbc:mysql://127.0.0.1/spring?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql= true

#pagehelper
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql

spring.jpa.properties.hibernate.hbm2ddl.auto 是hibernate的配置屬性

  • create:每次加載hibernate時都會刪除上一次的生成的表,然后根據(jù)你的model類再重新來生成新表错洁,哪怕兩次沒有任何改變也要這樣執(zhí)行秉宿,這就是導致數(shù)據(jù)庫表數(shù)據(jù)丟失的一個重要原因。
  • create-drop:每次加載hibernate時根據(jù)model類生成表屯碴,但是sessionFactory一關閉,表就自動刪除描睦。
  • validate:每次加載hibernate時,驗證創(chuàng)建數(shù)據(jù)庫表結(jié)構导而,只會和數(shù)據(jù)庫中的表進行比較忱叭,不會創(chuàng)建新表,但是會插入新值今艺。
  • update:最常用的屬性韵丑,第一次加載hibernate時根據(jù)model類會自動建立起表的結(jié)構(前提是先建立好數(shù)據(jù)庫),以后加載hibernate時根據(jù)model類自動更新表結(jié)構虚缎,即使表結(jié)構改變了但表中的行仍然存在不會刪除以前的行撵彻。要注意的是當部署到服務器后,表結(jié)構是不會被馬上建立起來的,是要等應用第一次運行起來后才會陌僵。

創(chuàng)建實體

@Entity
public class User {
    @Id
    @GeneratedValue
    private long id;

    @Column(nullable = false,unique = true)
    private String userName;

    @Column(nullable = false)
    private String passWord;

    @Column(nullable = false)
    private int age;

    ......省略set/get方法
}

繼承JpaRepository接口(SpringDataJPA提供的簡單數(shù)據(jù)操作接口轴合、JpaSpecificationExecutor(復雜查詢接口)、Serializable(序列化接口)碗短。通過查看JpaRepository接口的API文檔受葛,可以看到該接口本身已經(jīng)實現(xiàn)了創(chuàng)建(save)、更新(save)偎谁、刪除(delete)总滩、查詢(findAll)等基本操作的函數(shù),因此對于這些基礎操作的數(shù)據(jù)訪問就不需要開發(fā)者再自己定義搭盾。

public interface UserRepository extends JpaRepository<User,Long>,
        JpaSpecificationExecutor<UserEntity>,
        Serializable{
}

用@RestController注解來編寫一個控制器

SpringDataJPA內(nèi)部使用了類代理的方式讓繼承了它接口的子接口都以spring管理的Bean的形式存在咳秉,我們可以直接使用@Autowired注解在spring管理bean使用婉支。

@RestController
public class UserController {
    @Autowired
    private UserRepository userRepository;

    /*@RequestMapping(value = "/list")
    public List<User> list(){
        return userRepository.findAll();
    }*/
    /**
     * 查詢?nèi)苛斜?并做分頁
     *  @param pageNum 開始頁數(shù)
     * @param pageSize 每頁顯示的數(shù)據(jù)條數(shù)
     */
    @RequestMapping(value = "/list/{pageNum}/{pageSize}")
    public List<User> list(@PathVariable("pageNum") int pageNum, @PathVariable("pageSize") int pageSize){
        //將參數(shù)傳給這個方法就可以實現(xiàn)物理分頁了鸯隅,非常簡單。
        Sort sort = new Sort(Sort.Direction.ASC, "id");
        Pageable pageable = new PageRequest(pageNum, pageSize, sort);
        Page<User> users = userRepository.findAll(pageable);
        List<User> list =  users.getContent();
        return  list;
    }
    /**
     * 如果需要執(zhí)行持久化的實體存在主鍵值則更新數(shù)據(jù)向挖,如果不存在則添加數(shù)據(jù)
     */
    @RequestMapping(value = "/save")
    public User save(User user){
       return userRepository.save(user);
    }
    @RequestMapping(value = "/delete")
    public List<User> delete(long id){
        userRepository.deleteById(id);
        return userRepository.findAll();
    }
    @RequestMapping(value = "/find")
    public User find(long id){
        return userRepository.findById(id).get();
    }
}

自定義簡單查詢

自定義的簡單查詢就是根據(jù)方法名來自動生成SQL

public interface UserRepository extends JpaRepository<User, Long> {
           User findByUserName(String userName);
           User findByUserNameOrEmail(String username, String email);
           Long deleteById(Long id);
           Long countByUserName(String userName);
           List<User> findByEmailLike(String email);
           User findByUserNameIgnoreCase(String userName);
           List<User> findByUserNameOrderByEmailDesc(String email);
           ......
}

分頁查詢

spring data jpa已經(jīng)幫我們實現(xiàn)了分頁的功能蝌以,在查詢的方法中,需要傳入?yún)?shù)Pageable ,當查詢中有多個參數(shù)的時候Pageable建議做為最后一個參數(shù)傳入

Page<User> findALL(Pageable pageable);
    
Page<User> findByUserName(String userName,Pageable pageable);

Pageable 是spring封裝的分頁實現(xiàn)類何之,使用的時候需要傳入頁數(shù)跟畅、每頁條數(shù)和排序規(guī)則

@Test
public void testPageQuery() throws Exception {
    int page=1,size=10;
    Sort sort = new Sort(Direction.DESC, "id");
    Pageable pageable = new PageRequest(page, size, sort);
    userRepository.findALL(pageable);
    userRepository.findByUserName("testName", pageable);
}

限制查詢

有時候我們只需要查詢前N個元素,或者支取前一個實體溶推。

ser findFirstByOrderByLastnameAsc();

User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);

自定義SQL查詢

在SQL的查詢方法上面使用@Query注解徊件,如涉及到刪除和修改在需要加上@Modifying.也可以根據(jù)需要添加 @Transactional 對事物的支持,查詢超時的設置等蒜危。

@Modifying
@Query("update User u set u.userName = ?1 where u.id = ?2")
int modifyByIdAndUserId(String  userName, Long id);
    
@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteByUserId(Long id);
  
@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);

多表查詢

多表查詢在spring data jpa中有兩種實現(xiàn)方式虱痕,第一種是利用hibernate的級聯(lián)查詢來實現(xiàn),第二種是創(chuàng)建一個結(jié)果集的接口來接收連表查詢后的結(jié)果辐赞,這里主要第二種方式部翘。

首先需要定義一個結(jié)果集的接口類。

public interface HotelSummary {

    City getCity();

    String getName();

    Double getAverageRating();

    default Integer getAverageRatingRounded() {
        return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
    }

}

查詢的方法返回類型設置為新創(chuàng)建的接口

@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
        - "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);

@Query("select h.name as name, avg(r.rating) as averageRating "
        - "from Hotel h left outer join h.reviews r  group by h")
Page<HotelSummary> findByCity(Pageable pageable);

使用

Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0, 10, Direction.ASC, "name"));
for(HotelSummary summay:hotels){
        System.out.println("Name" +summay.getName());
    }

在運行中Spring會給接口(HotelSummary)自動生產(chǎn)一個代理類來接收返回的結(jié)果响委,代碼匯總使用getXXX的形式來獲取

多數(shù)據(jù)源的支持


同源數(shù)據(jù)庫的多源支持

日常項目中因為使用的分布式開發(fā)模式新思,不同的服務有不同的數(shù)據(jù)源,常常需要在一個項目中使用多個數(shù)據(jù)源赘风,因此需要配置sping data jpa對多數(shù)據(jù)源的使用夹囚,一般分一下為三步:

  • 1 配置多數(shù)據(jù)源
  • 2 不同源的實體類放入不同包路徑
  • 3 聲明不同的包路徑下使用不同的數(shù)據(jù)源、事務支持

異構數(shù)據(jù)庫多源支持

比如我們的項目中邀窃,即需要對mysql的支持荸哟,也需要對mongodb的查詢等。

實體類聲明@Entity 關系型數(shù)據(jù)庫支持類型、聲明@Document 為mongodb支持類型敲茄,不同的數(shù)據(jù)源使用不同的實體就可以了位谋。

interface PersonRepository extends Repository<Person, Long> {
 …
}

@Entity
public class Person {
  …
}

interface UserRepository extends Repository<User, Long> {
 …
}

@Document
public class User {
  …
}

但是,如果User用戶既使用mysql也使用mongodb呢堰燎,也可以做混合使用

interface JpaPersonRepository extends Repository<Person, Long> {
 …
}

interface MongoDBPersonRepository extends Repository<Person, Long> {
 …
}

@Entity
@Document
public class Person {
  …
}

也可以通過對不同的包路徑進行聲明掏父,比如A包路徑下使用mysql,B包路徑下使用mongoDB

@EnableJpaRepositories(basePackages = "com.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.repositories.mongo")
interface Configuration { }

Spring Data JPA——參考文檔 中文版

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秆剪,隨后出現(xiàn)的幾起案子赊淑,更是在濱河造成了極大的恐慌,老刑警劉巖仅讽,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陶缺,死亡現(xiàn)場離奇詭異,居然都是意外死亡洁灵,警方通過查閱死者的電腦和手機饱岸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來徽千,“玉大人苫费,你說我怎么就攤上這事∷椋” “怎么了百框?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長牍汹。 經(jīng)常有香客問我铐维,道長,這世上最難降的妖魔是什么慎菲? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任嫁蛇,我火速辦了婚禮,結(jié)果婚禮上钧嘶,老公的妹妹穿的比我還像新娘棠众。我一直安慰自己,他們只是感情好有决,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布闸拿。 她就那樣靜靜地躺著,像睡著了一般书幕。 火紅的嫁衣襯著肌膚如雪新荤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天台汇,我揣著相機與錄音苛骨,去河邊找鬼篱瞎。 笑死,一個胖子當著我的面吹牛痒芝,可吹牛的內(nèi)容都是我干的俐筋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼严衬,長吁一口氣:“原來是場噩夢啊……” “哼澄者!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起请琳,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤粱挡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后俄精,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體询筏,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年竖慧,在試婚紗的時候發(fā)現(xiàn)自己被綠了嫌套。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡测蘑,死狀恐怖灌危,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碳胳,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布沫勿,位于F島的核電站挨约,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏产雹。R本人自食惡果不足惜诫惭,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蔓挖。 院中可真熱鬧夕土,春花似錦、人聲如沸瘟判。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拷获。三九已至篮撑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匆瓜,已是汗流浹背赢笨。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工未蝌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茧妒。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓萧吠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親桐筏。 傳聞我的和親對象是個殘疾皇子怎憋,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容