領先一步
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
會將一些預設 bean 新增到 ApplicationContext
。您可以覆寫其方法來自訂 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
註釋。
如果您想要執行 update 或 delete 語句,您可以向方法新增 @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 上提問。如果您發現錯誤或想要請求功能,請建立 issue。