領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多隨著即將釋出的 Lovelace GA 版本,我們將推出一個新的 Spring Data 模組:Spring Data JDBC。
Spring Data JDBC 的理念是提供對關係資料庫的訪問,同時避免 JPA 的複雜性。JPA 提供延遲載入、快取和髒資料跟蹤等功能。雖然這些功能在您需要時非常有用,但它們實際上會使考慮 JPA 及其行為變得比實際更難。
延遲載入可能會在您意想不到的時候觸發昂貴的語句,或者可能因異常而失敗。當您想要比較同一實體的兩個版本時,快取可能會妨礙您,而髒資料跟蹤使得很難找到所有持久化操作都透過的單一入口點。
Spring Data JDBC 旨在提供一個更簡單的模型。它不會有快取、髒資料跟蹤或延遲載入。相反,SQL 語句只會在您呼叫儲存庫方法時才發出。作為該方法結果返回的物件在方法返回之前會完全載入。沒有“會話”,也沒有實體的代理。所有這些都應該讓 Spring Data JDBC 更容易理解。
當然,這種更簡單的方法會導致一些限制,我們將在未來的文章中介紹。此外,這是第一個版本,因此有許多我們想要並計劃實現的功能,但為了儘早將產品提供給您,我們不得不推遲這些功能。
首先,我們需要一個實體
class Customer {
@Id
Long id;
String firstName;
LocalDate dob;
}
請注意,您不需要 getter 或 setter。如果您更喜歡使用它們,那也完全沒問題。實際上,唯一的要求是實體有一個帶有 Id 註解的屬性(即 @org.springframework.data.annotation.Id,而不是 javax.persistence 中的那個)。
接下來,我們需要宣告一個儲存庫。最簡單的方法是擴充套件 CrudRepository
interface CustomerRepository extends CrudRepository<Customer, Long> {}
最後,我們需要配置 ApplicationContext 以啟用儲存庫的建立
@Configuration
@EnableJdbcRepositories (1)
public class CustomerConfig extends JdbcConfiguration { (2)
@Bean
NamedParameterJdbcOperations operations() { (3)
return new NamedParameterJdbcTemplate(dataSource());
}
@Bean
PlatformTransactionManager transactionManager() { (4)
return new DataSourceTransactionManager(dataSource());
}
@Bean
DataSource dataSource(){ (5)
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.HSQL)
.addScript("create-customer-schema.sql")
.build();
}
}
讓我們逐步瞭解配置。
EnableJdbcRepositories 啟用儲存庫的建立。由於它需要一些 bean 的存在,因此我們需要其餘的配置。
擴充套件 JdbcConfiguration 會向 ApplicationContext 新增一些預設 bean。您可以重寫其方法以自定義 Spring Data JDBC 的某些行為。目前,我們使用預設實現。
真正重要的部分是 NamedParameterJdbcOperations,它在內部用於向資料庫提交 SQL 語句。
嚴格來說,事務管理器不是必需的。但是您將無法獲得跨越單個語句的事務支援,而沒有人希望這樣,對嗎?
Spring Data JDBC 不直接使用 DataSource,但由於 TransactionManager 和 NamedParameterJdbcOperations 需要它,因此將其註冊為 bean 是一種確保兩者使用相同例項的簡單方法。
這就是您開始使用它所需的一切。現在讓我們在一個測試中玩轉它
@RunWith(SpringRunner.class)
@Transactional
@ContextConfiguration(classes = CustomerConfig.class)
public class CustomerRepositoryTest {
@Autowired CustomerRepository customerRepo;
@Test
public void createSimpleCustomer() {
Customer customer = new Customer();
customer.dob = LocalDate.of(1904, 5, 14);
customer.firstName = "Albert";
Customer saved = customerRepo.save(customer);
assertThat(saved.id).isNotNull();
saved.firstName = "Hans Albert";
customerRepo.save(saved);
Optional<Customer> reloaded = customerRepo.findById(saved.id);
assertThat(reloaded).isNotEmpty();
assertThat(reloaded.get().firstName).isEqualTo("Hans Albert");
}
}
@Query 註解您可能無法僅使用 CrudRepository 中的基本 CRUD 方法走得很遠。我們決定將查詢派生(Spring Data 從方法名派生查詢的流行功能)推遲到以後的版本。在此之前,您可以使用簡單的 @Query 註解來指定儲存庫方法上的查詢
@Query("select id, first_name, dob from customer where upper(first_name) like '%' || upper(:name) || '%' ")
List<Customer> findByName(@Param("name") String name);
請注意,如果使用 -parameters 標誌進行編譯,則不需要 @Param 註解。
如果要執行更新或刪除語句,可以在方法中新增 @Modifying 註解。
讓我們建立另一個測試來嘗試新方法。
@Test
public void findByName() {
Customer customer = new Customer();
customer.dob = LocalDate.of(1904, 5, 14);
customer.firstName = "Albert";
Customer saved = customerRepo.save(customer);
assertThat(saved.id).isNotNull();
customer.id= null; (1)
customer.firstName = "Bertram";
customerRepo.save(customer);
customer.id= null;
customer.firstName = "Beth";
customerRepo.save(customer);
assertThat(customerRepo.findByName("bert")).hasSize(2); (2)
}
由於 Java 物件及其對應的行之間的連線只是它的 Id 加上它的型別,因此將 Id 設定為 null 並再次儲存會在資料庫中建立另一行。
我們正在進行不區分大小寫(like)的搜尋,因此我們找到了“Albert”和“Bertram”,但沒有找到“Beth”。
關於 Spring Data JDBC 還有更多內容需要學習。繼續閱讀 Spring Data JDBC 引用和聚合
或者您可以檢視示例、文件,當然還有原始碼。如果您有問題,請在 StackOverflow 上提問。如果您發現錯誤或想請求功能,請建立問題。