第三章 Spring Data JPA

本章是《 Spring Boot 快速入門 》系列教程的第三章井辆,若要查看本系列的全部章節(jié),請點擊 這里 溶握。

目錄

  • 簡介
  • 源碼下載
  • 軟件版本
  • JPA簡介
  • 在項目中配置JPA
  • 編寫實體類
  • 編寫 Repository 接口
  • 使用原生SQL查詢
  • 總結(jié)說明

簡介

在上一章《 Spring Boot MVC 》中杯缺,我們了解了使用 Spring Boot MVC 來開發(fā) Http Restful API的相關(guān)技術(shù),但只處理HTTP請求是不夠的睡榆,現(xiàn)在的應(yīng)用程序大多使用了關(guān)系型數(shù)據(jù)庫夺谁,因此本章我們會帶著大家繼續(xù) Spring Boot 體驗之旅,這次我們將采用 JPA 技術(shù)來訪問數(shù)據(jù)庫肉微,給 Hello Spring Boot 程序添加帶數(shù)據(jù)庫訪問演示代碼匾鸥。

源碼下載

本章的示例代碼放在“碼云”上,大家可以免費下載或瀏覽:

https://git.oschina.net/terran4j/springboot/tree/master/springboot-jpa

軟件版本

相關(guān)軟件使用的版本:

  • Java: 1.8
  • Maven: 3.3.9
  • MYSQL: 5.5

程序在以上版本均調(diào)試過碉纳,可以正常運行勿负,其它版本僅作參考。

JPA簡介

JPA是Java Persistence API的簡稱劳曹,中文名Java持久層API奴愉,是JDK 5.0注解或XML描述對象-關(guān)系表的映射關(guān)系,并將運行期的實體“對象持久化”到數(shù)據(jù)庫中铁孵。
JPA技術(shù)可以極大的降低了對數(shù)據(jù)庫編程的復(fù)雜性锭硼,一些簡單的增刪改查的操作,代碼只需要操作對象就可以了蜕劝,JPA自動的幫你映射成數(shù)據(jù)庫的SQL操作檀头。

不過 JPA 只是標準標準轰异,而 Spring Boot 提供了它的技術(shù)實現(xiàn): Spring Data JPA。不過 Spring Data JPA 也不是重復(fù)造輪子暑始,它是基于一個非常著名的ORM框架——Hibernate——之上封裝實現(xiàn)的搭独。

Spring Data JPA 極大簡化了數(shù)據(jù)庫訪問層代碼,只要3步廊镜,就能搞定一切:

  1. 在pom.xml中配置spring-boot-starter-data-jpa牙肝,及在 application配置文件中配置數(shù)據(jù)庫連接。
  2. 編寫 Entity 類嗤朴,依照 JPA 規(guī)范配椭,定義實體。
  3. 編寫 Repository 接口雹姊,依靠 Spring Data 規(guī)范颂郎,定義數(shù)據(jù)訪問接口(注意,只要接口容为,不需要任何實現(xiàn))

另外乓序,如果有復(fù)雜的SQL查詢,Spring Data JPA 也提供了編寫原生 SQL 實現(xiàn)的方式坎背。

在項目中配置JPA

首先替劈,我們要在 pom.xml 文件中添加 spring-boot-starter-data-jpa 的依賴,代碼如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>terran4j</groupId>
    <artifactId>springboot-jpa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot-jpa</name>
    <url>https://git.oschina.net/terran4j/springboot/tree/master/springboot-jpa</url>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

</project>

注意新增的兩個依賴得滤,一個是 spring-boot-starter-data-jpa陨献,它集成了JPA相關(guān)的 jar 包;另一個是 mysql-connector-java , 因為本示例中我們要連MYSQL的數(shù)據(jù)庫懂更,所以 mysql jdbc 驅(qū)動(java) 是必不可少的眨业。

然后,我們要在application.properties配置文件中配置數(shù)據(jù)庫連接及JPA配置沮协,如下所示:

spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/test
spring.datasource.username = root
spring.datasource.password = 

spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql = true

spring.datasource開頭的是數(shù)據(jù)庫連接的配置龄捡,請注意一定要保持對應(yīng)的數(shù)據(jù)庫是存在的,并且用戶名密碼都沒錯慷暂,不然待會程序運行時無法啟動聘殖。
spring.jpa開發(fā)的是 JPA 的配置,spring.jpa.hibernate.ddl-auto 表示每次程序啟動時對數(shù)據(jù)庫表的處理策略行瑞,有以下可選值:

  • create:
    每次程序啟動時奸腺,都會刪除上一次的生成的表,然后根據(jù)你的實體類再重新來生成新表血久,哪怕兩次沒有任何改變也要這樣執(zhí)行突照。
    這種策略適合于執(zhí)行自動化測試的環(huán)境下使用,其它環(huán)境請慎用氧吐。

  • create-drop :
    每次程序啟動時讹蘑,根據(jù)實體類生成表末盔,但是程序正常退出時,表就被刪除了衔肢。

  • update:
    最常用的屬性,第一次程序啟動時豁翎,根據(jù)實體類會自動建立起表的結(jié)構(gòu)(前提是先建立好數(shù)據(jù)庫)角骤,以后程序啟動時會根據(jù)實體類自動更新表結(jié)構(gòu),即使表結(jié)構(gòu)改變了心剥,但表中的記錄仍然存在邦尊,不會刪除以前的記錄。要注意的是當(dāng)部署到服務(wù)器后优烧,表結(jié)構(gòu)是不會被馬上建立起來的蝉揍,是要等 第一次訪問JPA時后才會建立。

  • validate :
    每次程序啟動時,驗證創(chuàng)建數(shù)據(jù)庫表結(jié)構(gòu),只會和數(shù)據(jù)庫中的表進行比較他炊,不會創(chuàng)建新表捞烟,但是會插入新值。

因此苹粟,建議大多數(shù)場景下用 update 就可以了,線上環(huán)境(或需要慎重的環(huán)境)中用 validate 會更保險一些,沒有特殊情況下不建議用 create 及 create-drop 模式滑燃。

配置完成后,我們運行下 main 程序(代碼如下):

@SpringBootApplication
public class HelloJPAApp {

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

}

結(jié)果控制臺輸入里多了一些東西:

......
2017-08-04 15:51:27.017  INFO 20248 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.12.Final}
2017-08-04 15:51:27.018  INFO 20248 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2017-08-04 15:51:27.020  INFO 20248 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2017-08-04 15:51:27.086  INFO 20248 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-08-04 15:51:27.666  INFO 20248 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2017-08-04 15:51:28.230  INFO 20248 --- [           main] org.hibernate.tool.hbm2ddl.SchemaUpdate  : HHH000228: Running hbm2ddl schema update
2017-08-04 15:51:28.424  INFO 20248 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
......

如果控制臺輸出中沒有報錯颓鲜,并且有這之類的輸出表窘,表示配置成功了。

編寫實體類

要操作數(shù)據(jù)庫數(shù)據(jù)甜滨,首先得建表乐严。然而 JPA 使用起來非常簡單,簡單得你只需要在Java的實體類上加上一些注解衣摩,就可以自動映射成數(shù)據(jù)庫表麦备。

下面是一個實體類的代碼:

package com.terran4j.springboot.jpa;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity(name = "t_user") // 定義數(shù)據(jù)庫表名稱。
@Table(indexes = { // 定義數(shù)據(jù)庫索引昭娩。

        // 唯一索引凛篙。
        @Index(name = "ux_user_login_name", columnList = "loginName", unique = true), //

        // 非唯一索引。
        @Index(name = "idx_user_age", columnList = "age"), //
})
public class User {

    /**
     * id, 自增主鍵栏渺。
     */
    @Id
    @GeneratedValue
    @Column(length = 20)
    private Long id;

    /**
     * 用戶的登錄名呛梆。
     */
    @Column(length = 100, nullable = false)
    private String loginName;

    /**
     * 用戶的年齡。
     */
    @Column(length = 3)
    private Integer age;

    /**
     * 用戶的狀態(tài)磕诊。
     */
    @Column(length = 16, nullable = false)
    @Enumerated(EnumType.STRING)
    private UserStatus status = UserStatus.enable;

    /**
     * 用戶的注冊時間填物。
     */
    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = false)
    private Date registTime;

    public final Long getId() {
        return id;
    }

    public final void setId(Long id) {
        this.id = id;
    }

    public final String getLoginName() {
        return loginName;
    }

    public final void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public final Integer getAge() {
        return age;
    }

    public final void setAge(Integer age) {
        this.age = age;
    }

    public final UserStatus getStatus() {
        return status;
    }

    public final void setStatus(UserStatus status) {
        this.status = status;
    }

    public final Date getRegistTime() {
        return registTime;
    }

    public final void setRegistTime(Date registTime) {
        this.registTime = registTime;
    }
    
}

首先纹腌,我們看 User 類上兩個注解 @Entity 和 @Table :
@Entity(name = "t_user") 注解 加在 User 上,表示它是一個實體類滞磺, 表名是 t_user 升薯。

@Table(indexes = { // 定義數(shù)據(jù)庫索引。

        // 唯一索引击困。
        @Index(name = "ux_user_login_name", columnList = "loginName", unique = true), //

        // 非唯一索引涎劈。
        @Index(name = "idx_user_age", columnList = "age"), //
})

@Table 里面定義了這個表的索引,一個 @Index 注解定義了一個索引阅茶, name 屬性表示數(shù)據(jù)庫表中索引的名稱蛛枚, columnList 表示對應(yīng)的 java 屬性名稱, unique = true 表示此索引是唯一索引脸哀。
比如上面的 @Index(name = "ux_user_login_name", columnList = "loginName", unique = true) 表示對 loginName 屬性所對應(yīng)的字段(映射到數(shù)據(jù)庫表中應(yīng)該是 login_name 字段)建立唯一索引蹦浦,索引名為ux_user_login_name。
columnList 中可以放多個java屬性撞蜂,中間用逗號隔開盲镶,表示聯(lián)合索引,如:@Index(name = "idx_user_age_name", columnList = "age,loginName") 表示建立 age 與 login_name 字段的聯(lián)合索引蝌诡。

注意: java 屬性名都是駝峰命名法(如 loginName)徒河,而數(shù)據(jù)庫表字段都是下劃線命名法(如 login_name),JPA會自動根據(jù)java屬性名的駝峰命名法映射成數(shù)據(jù)庫表字段的下劃線命名法送漠,如 loginName 屬性映射到數(shù)據(jù)庫就是 login_name 字段顽照。

這個 User 實體類寫好后,我們再運行下之前的 main 程序闽寡,然后驚奇的發(fā)現(xiàn):數(shù)據(jù)庫里自動建了一個名為 "t_user"的表:

t_user.png

表示JPA在啟動時根據(jù)實體類代兵,自動在數(shù)據(jù)庫中創(chuàng)建了對應(yīng)的表了。

注意: 實體類 User 一定要放在 HelloJPAApp 類所在包中或子包中爷狈,不然
HelloJPAApp 啟動時 Spring Boot 可能掃描不到植影。

編寫 Repository 接口

有了表之后,我們要寫對表進行增刪改查的代碼涎永,用JPA干這事簡直是簡單到姥姥家了思币,只需要繼續(xù)一個接口就搞定了,請看代碼:

package com.terran4j.springboot.jpa;

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

public interface UserRepository extends JpaRepository<User, Long> {

}

這樣就寫完了基本的增刪改查的代碼羡微? 的確是這樣谷饿,因為 JpaRepository 接口已經(jīng)定義了很多方法,JpaRepository 的父類也定義了很多方法妈倔,如:

JPA.png

而 Spring Boot JPA又幫你實現(xiàn)了這些方法博投,你只需要在繼承 JpaRepository 時指定了實體類的類對象和 ID 屬性的類對象就可以了,如 public interface UserRepository extends JpaRepository<User, Long> 表示實體類是 User, User 中 ID 屬性是 Long 類型的盯蝴。
并且毅哗, Spring Boot JPA 掃描到 UserRepository 是 Repository 的子類后听怕,會以動態(tài)代理的方式對 UserRepository 進行實現(xiàn),并將實現(xiàn)的對象作為 Bean 注入到 Spring 容器中虑绵,而我們只需要像使用普通的 Spring Bean 一樣尿瞭,用 @Autowired 引入即可使用。

下面翅睛,我們編寫一個 Controller 類來調(diào)用 UserRepository 声搁,如下所示:

package com.terran4j.springboot.jpa;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @Autowired
    private HelloService helloService;

    @Autowired
    private UserRepository userRepository;

    // URL示例: http://localhost:8080/hello/1
    @RequestMapping(value = "/hello/{id}", method = RequestMethod.GET)
    public String sayHello(@PathVariable("id") Long id) {

        User user = userRepository.findOne(id);

        if (user == null) {
            return String.format("User NOT Found: %d", id);
        }

        String name = user.getLoginName();
        return helloService.hello(name);
    }

}

相關(guān)的 HelloService 的代碼為:

package com.terran4j.springboot.jpa;

import org.springframework.stereotype.Component;

@Component
public class HelloService {

    public String hello(String name) {
        return "Hello, " + name + "!";
    }
    
}

代碼中, User user = userRepository.findOne(id); 表示根據(jù) id 從表中查出一條記錄宏所,并映射成 User 對象酥艳。

為了測試效果摊溶,我們先執(zhí)行以下SQL在數(shù)據(jù)庫中制造點數(shù)據(jù):

delete from `t_user`;
insert into `t_user` (`id`, `login_name`, `age`, `regist_time`, `status`) values 
('1','Jim','12','2017-07-26 09:29:47','enable'),
('2','Mike','23','2017-07-25 09:30:54','disable');

然后啟動程序爬骤,在瀏覽器中用以下URL訪問:

http://localhost:8080/hello/1
sayHello運行效果

可以看到, userRepository.findOne(id) 的確把數(shù)據(jù)給查出來了莫换。

使用原生SQL查詢

然而霞玄,JpaRepository 提供的僅是簡單的增刪查改方法,那遇到復(fù)雜的查詢怎么辦拉岁?
Spring Boot JAP 底層是 Hibernate 實現(xiàn)的坷剧, Hibernate 提供了 hql 的類SQL語法來編寫復(fù)雜查詢,不過我個人不建議用 HQL喊暖,因為畢竟 HQL 與SQL還是有較大不同的惫企,需要學(xué)習(xí)成本(但這個成本其實是沒必要投入的),另外就是一些場景下需要用數(shù)據(jù)庫的特定優(yōu)化機制時陵叽,HQL 實現(xiàn)不了狞尔。
所以,我的建議是使用原生 SQL 的方式實現(xiàn)巩掺,而 JPA 是提供了這個能力的偏序,下面我介紹一種用在 orm.xml 中寫原生 SQL的方法。

假如需求是這樣的胖替,我們要查詢某一年齡段的 User(如 10歲 ~ 20歲的)研儒,SQL大概要這樣寫:

SELECT * FROM t_user AS u 
WHERE u.age >= '10' AND u.age <= '20' 
ORDER BY u.regist_time DESC 

Spring Boot JAP 約定是把 SQL 寫在類路徑的 META-INF/orm.xml 文件中(如果 META-INF 文件夾沒有就創(chuàng)建一個),文件路徑如下:

orm.xml

orm.xml 文件的內(nèi)容如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_0.xsd"
    version="2.1">

    <named-native-query name="User.findByAgeRange" 
            result-class="com.terran4j.springboot.jpa.User">
        <query><![CDATA[
            select * from t_user as u
            where u.age >= :minAge and u.age <= :maxAge
            order by u.regist_time desc
        ]]></query>
    </named-native-query>

</entity-mappings>

<named-native-query>表示是一個“原生SQL查詢”独令, name="User.findByAgeRange"表示給這個查詢起了一個名字叫“User.findByAgeRange”端朵,后面代碼中會根據(jù)這個名字來引用這個查詢,result-class="com.terran4j.springboot.jpa.User" 表示SQL查詢返回的結(jié)果集燃箭,每條記錄轉(zhuǎn)化成 User 對象逸月。
<query>里面是原生的SQL語句,其中 : 開始的是變量遍膜,如上面的SQL碗硬,有兩個變量 :minAge 和 :maxAge 瓤湘,這些變量的值,會從外面?zhèn)魅脒M來恩尾。

然后我們可以在 UserRepository 中添加一個findByAgeRange方法來使用這個原生SQL查詢弛说,如下代碼所示:

package com.terran4j.springboot.jpa;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface UserRepository extends JpaRepository<User, Long> {

    /**
     * 查詢某年齡段范圍之內(nèi)的用戶。
     * 
     * @param minAge
     *            最小年齡翰意。
     * @param maxAge
     *            最大年齡木人。
     * @return
     */
    @Query(nativeQuery = true, name = "User.findByAgeRange")
    List<User> findByAgeRange(@Param("minAge") int minAge, @Param("maxAge") int maxAge);

}

這個findByAgeRange方法上面有一個@Query(nativeQuery = true, name = "User.findByAgeRange")注解,表示這個方法的實現(xiàn)使用名為User.findByAgeRange的查詢冀偶,此查詢是用原生SQL寫的醒第;方法參數(shù)上有@Param注解,表示將方法的參數(shù)值映射到查詢中的變量进鸠。

最后稠曼,我們寫一個 Controller 調(diào)用這個方法試,如下代碼所示:

package com.terran4j.springboot.jpa;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController2 {

    @Autowired
    private UserRepository userRepository;

    // URL示例: http://localhost:8080/users
    @RequestMapping(value = "/users", method = RequestMethod.GET)
    @ResponseBody
    public List<User> findByAgeRange(
            @RequestParam(value = "minAge", defaultValue = "1") int minAge,
            @RequestParam(value = "maxAge", defaultValue = "999") int maxAge) {

        List<User> users = userRepository.findByAgeRange(minAge, maxAge);

        return users;
    }

}

然后訪問 URL: http://localhost:8080/users客年,運行效果如下:

findByAgeRange查詢結(jié)果

我們看到findByAgeRange方法把數(shù)據(jù)給查出來了霞幅,同時控制臺有一行輸出:

Hibernate: select * from t_user as u where u.age >= ? and u.age <= ? order by u.regist_time desc

這也是 JPA 底層實際執(zhí)行的 SQL,也就是把我們寫的 SQL 中 :minAge 和 :maxAge 兩個變量換成“綁定變量”的方式量瓜。

總結(jié)說明

本文我們講解了用 Spring Boot JPA 來訪問數(shù)據(jù)庫司恳,是不是覺得用 Spring Boot 開發(fā)超級爽呢,本系列這三章就講到這了绍傲,主要是帶大家對 Spring Boot 快速上手扔傅,后面筆者會努力出更多關(guān)于 Spring Boot && Spring Cloud 的技術(shù)文章,敬請期待烫饼。

點擊 這里 可以查看本系列的全部章節(jié)猎塞。
(本系列的目標是幫助有 Java 開發(fā)經(jīng)驗的程序員們快速掌握使用 Spring Boot 開發(fā)的基本技巧,感受到 Spring Boot 的極簡開發(fā)風(fēng)格及超爽編程體驗枫弟。)

另外邢享,我們有一個名為 SpringBoot及微服務(wù) 的微信公眾號,感興趣的同學(xué)請掃描下面的二維碼關(guān)注下吧淡诗,關(guān)注后就可以收到我們定期分享的技術(shù)干貨哦骇塘!

SpringBoot及微服務(wù)-公眾號二維碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市韩容,隨后出現(xiàn)的幾起案子款违,更是在濱河造成了極大的恐慌,老刑警劉巖群凶,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件插爹,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機赠尾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門力穗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人气嫁,你說我怎么就攤上這事当窗。” “怎么了寸宵?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵崖面,是天一觀的道長。 經(jīng)常有香客問我梯影,道長巫员,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任甲棍,我火速辦了婚禮简识,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘救军。我一直安慰自己财异,他們只是感情好倘零,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布唱遭。 她就那樣靜靜地躺著,像睡著了一般呈驶。 火紅的嫁衣襯著肌膚如雪拷泽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天袖瞻,我揣著相機與錄音司致,去河邊找鬼。 笑死聋迎,一個胖子當(dāng)著我的面吹牛脂矫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播霉晕,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼庭再,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了牺堰?” 一聲冷哼從身側(cè)響起拄轻,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伟葫,沒想到半個月后恨搓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年斧抱,在試婚紗的時候發(fā)現(xiàn)自己被綠了常拓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡辉浦,死狀恐怖墩邀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盏浙,我是刑警寧澤眉睹,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站废膘,受9級特大地震影響竹海,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丐黄,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一斋配、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧灌闺,春花似錦艰争、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蕉斜,卻和暖如春逾柿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宅此。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工机错, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人父腕。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓弱匪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親璧亮。 傳聞我的和親對象是個殘疾皇子萧诫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356

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

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,827評論 6 342
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)杜顺,斷路器财搁,智...
    卡卡羅2017閱讀 134,672評論 18 139
  • 簡介: 本文由淺入深地講述了使用 Spring Data JPA 需要關(guān)注的各個方面,為讀者了解和使用該框架提供了...
    AiPuff閱讀 4,507評論 1 28
  • 一直都想寫點東西提茁,但是又不知道自己寫點什么淹禾,猶猶豫豫了那么久,終于還是動了想法茴扁。 我一直都認為我是一個獨...
    老賊別跑閱讀 1,201評論 0 0
  • 熟悉的場景 2017年伊始铃岔,一個午飯桌上,我的一位同事信誓旦旦的說:“今年我的目標是學(xué)習(xí)英語峭火;出去旅游2次毁习;找到一...
    凱凱劉閱讀 383評論 0 1