1. 程式人生 > >Spring Boot 基礎系列教程 | 第十二篇:使用Spring-data-jpa簡化資料訪問層(推薦)

Spring Boot 基礎系列教程 | 第十二篇:使用Spring-data-jpa簡化資料訪問層(推薦)

推薦 Spring Boot/Cloud 視訊:

Spring Boot中使用Spring-data-jpa讓資料訪問更簡單、更優雅

在上一篇Spring中使用JdbcTemplate訪問資料庫 中介紹了一種基本的資料訪問方式,結合構建RESTful API和使用Thymeleaf模板引擎渲染Web檢視的內容就已經可以完成App服務端和Web站點的開發任務了。

然而,在實際開發過程中,對資料庫的操作無非就“增刪改查”。就最為普遍的單表操作而言,除了表和欄位不同外,語句都是類似的,開發人員需要寫大量類似而枯燥的語句來完成業務邏輯。

為了解決這些大量枯燥的資料操作語句,我們第一個想到的是使用ORM框架,比如:Hibernate。通過整合Hibernate之後,我們以操作Java實體的方式最終將資料改變對映到資料庫表中。

為了解決抽象各個Java實體基本的“增刪改查”操作,我們通常會以泛型的方式封裝一個模板Dao來進行抽象簡化,但是這樣依然不是很方便,我們需要針對每個實體編寫一個繼承自泛型模板Dao的介面,再編寫該介面的實現。雖然一些基礎的資料訪問已經可以得到很好的複用,但是在程式碼結構上針對每個實體都會有一堆Dao的介面和實現。

由於模板Dao的實現,使得這些具體實體的Dao層已經變的非常“薄”,有一些具體實體的Dao實現可能完全就是對模板Dao的簡單代理,並且往往這樣的實現類可能會出現在很多實體上。Spring-data-jpa的出現正可以讓這樣一個已經很“薄”的資料訪問層變成只是一層介面的編寫方式。比如,下面的例子:


public interface UserRepository extends JpaRepository<User, Long> {

    User findByName(String name);

    @Query("from User u where u.name=:name")
    User findUser(@Param("name") String name);

}

我們只需要通過編寫一個繼承自JpaRepository的介面就能完成資料訪問,下面以一個具體例項來體驗Spring-data-jpa給我們帶來的強大功能。

使用示例

由於Spring-data-jpa依賴於Hibernate。如果您對Hibernate有一定了解,下面內容可以毫不費力的看懂並上手使用Spring-data-jpa。如果您還是Hibernate新手,您可以先按如下方式入門,再建議回頭學習一下Hibernate以幫助這部分的理解和進一步使用。

工程配置

在pom.xml中新增相關依賴,加入以下內容:


<dependency
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

在application.xml中配置:資料庫連線資訊(如使用嵌入式資料庫則不需要)、自動建立表結構的設定,例如使用mysql的情況如下:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop

spring.jpa.properties.hibernate.hbm2ddl.auto是hibernate的配置屬性,其主要作用是:自動建立、更新、驗證資料庫表結構。該引數的幾種配置如下:

  • create:每次載入hibernate時都會刪除上一次的生成的表,然後根據你的model類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致資料庫表資料丟失的一個重要原因。
  • create-drop:每次載入hibernate時根據model類生成表,但是sessionFactory一關閉,表就自動刪除。
  • update:最常用的屬性,第一次載入hibernate時根據model類會自動建立起表的結構(前提是先建立好資料庫),以後載入hibernate時根據model類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到伺服器後,表結構是不會被馬上建立起來的,是要等應用第一次執行起來後才會。
  • validate:每次載入hibernate時,驗證建立資料庫表結構,只會和資料庫中的表進行比較,不會建立新表,但是會插入新值。 至此已經完成基礎配置,如果您有在Spring下整合使用過它的話,相信你已經感受到Spring Boot的便利之處:JPA的傳統配置在persistence.xml檔案中,但是這裡我們不需要。當然,最好在構建專案時候按照之前提過的最佳實踐的工程結構來組織,這樣以確保各種配置都能被框架掃描到。

建立實體

建立一個User實體,包含id(主鍵)、name(姓名)、age(年齡)屬性,通過ORM框架其會被對映到資料庫表中,由於配置了hibernate.hbm2ddl.auto,在應用啟動的時候框架會自動去資料庫中建立對應的表。

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private Integer age;

    // 省略建構函式

    // 省略getter和setter

}

建立資料訪問介面

下面針對User實體建立對應的Repository介面實現對該實體的資料訪問,如下程式碼:

public interface UserRepository extends JpaRepository<User, Long> {

    User findByName(String name);

    User findByNameAndAge(String name, Integer age);

    @Query("from User u where u.name=:name")
    User findUser(@Param("name") String name);

}

在Spring-data-jpa中,只需要編寫類似上面這樣的介面就可實現資料訪問。不再像我們以往編寫了介面時候還需要自己編寫介面實現類,直接減少了我們的檔案清單。

下面對上面的UserRepository做一些解釋,該介面繼承自JpaRepository,通過檢視JpaRepository介面的API文件,可以看到該介面本身已經實現了建立(save)、更新(save)、刪除(delete)、查詢(findAll、findOne)等基本操作的函式,因此對於這些基礎操作的資料訪問就不需要開發者再自己定義。

在我們實際開發中,JpaRepository介面定義的介面往往還不夠或者效能不夠優化,我們需要進一步實現更復雜一些的查詢或操作。由於本文重點在spring boot中整合spring-data-jpa,在這裡先拋磚引玉簡單介紹一下spring-data-jpa中讓我們興奮的功能,後續再單獨開篇講一下spring-data-jpa中的常見使用。

在上例中,我們可以看到下面兩個函式:

  • User findByName(String name)
  • User findByNameAndAge(String name, Integer age) 它們分別實現了按name查詢User實體和按name和age查詢User實體,可以看到我們這裡沒有任何類SQL語句就完成了兩個條件查詢方法。這就是Spring-data-jpa的一大特性:通過解析方法名建立查詢。

除了通過解析方法名來建立查詢外,它也提供通過使用@Query 註解來建立查詢,您只需要編寫JPQL語句,並通過類似“:name”來對映@Param指定的引數,就像例子中的第三個findUser函式一樣。

Spring-data-jpa的能力遠不止本文提到的這些,由於本文主要以整合介紹為主,對於Spring-data-jpa的使用只是介紹了常見的使用方式。諸如@Modifying操作、分頁排序、原生SQL支援以及與Spring MVC的結合使用等等內容就不在本文中詳細展開,這裡先挖個坑,後續再補文章填坑,如您對這些感興趣可以關注我部落格或簡書,同樣歡迎大家留言交流想法。

單元測試

在完成了上面的資料訪問介面之後,按照慣例就是編寫對應的單元測試來驗證編寫的內容是否正確。這裡就不多做介紹,主要通過資料操作和查詢來反覆驗證操作的正確性。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTests {

	@Autowired
	private UserRepository userRepository;

	@Test
	public void test() throws Exception {

		// 建立10條記錄
		userRepository.save(new User("AAA", 10));
		userRepository.save(new User("BBB", 20));
		userRepository.save(new User("CCC", 30));
		userRepository.save(new User("DDD", 40));
		userRepository.save(new User("EEE", 50));
		userRepository.save(new User("FFF", 60));
		userRepository.save(new User("GGG", 70));
		userRepository.save(new User("HHH", 80));
		userRepository.save(new User("III", 90));
		userRepository.save(new User("JJJ", 100));

		// 測試findAll, 查詢所有記錄
		Assert.assertEquals(10, userRepository.findAll().size());

		// 測試findByName, 查詢姓名為FFF的User
		Assert.assertEquals(60, userRepository.findByName("FFF").getAge().longValue());

		// 測試findUser, 查詢姓名為FFF的User
		Assert.assertEquals(60, userRepository.findUser("FFF").getAge().longValue());

		// 測試findByNameAndAge, 查詢姓名為FFF並且年齡為60的User
		Assert.assertEquals("FFF", userRepository.findByNameAndAge("FFF", 60).getName());

		// 測試刪除姓名為AAA的User
		userRepository.delete(userRepository.findByName("AAA"));

		// 測試findAll, 查詢所有記錄, 驗證上面的刪除是否成功
		Assert.assertEquals(9, userRepository.findAll().size());

	}


}

專家推薦

“隨著微服務架構的發展,Spring Cloud 使用得越來越廣泛。馳狼課堂http://www.chilangedu.com Spring Boot 快速入門,Spring Boot 與Spring Cloud 整合,docker+k8s,大型電商商城等多套免費實戰教程可以幫您真正做到快速上手,將技術點切實運用到微服務專案中。”