Spring Data JDBC介紹

banq發表於2018-09-30
Spring新增了一個新的資料模組:Spring Data JDBC。Spring Data JDBC背後的想法是提供對關聯式資料庫的訪問,而無需處理JPA的複雜性。JPA提供延遲載入,快取和髒跟蹤等功能。果你需要這些功能會很很棒,但會讓猜測JPA的行為比非JPA更難。

延遲載入可能會在你不需要時觸發昂貴的語句,或者它可能會因異常而失敗。當你想要比較一個實體的兩個版本是哪個變成髒資料時,快取可能會妨礙你,讓你很難找到所有永續性操作都透過的那個點。

Spring Data JDBC目標是實現更簡單的模型,不會有快取,髒資料跟蹤或延遲載入。相反,只有在呼叫資料庫方法時才會發出SQL語句。方法返回的物件會完全載入,不會有延遲。實體沒有“會話”和代理。所有這些都應該使Spring Data JDBC更易於推理。

當然,這種更簡單的方法會導致約束。

我們來看一個簡單的例子。
首先,我們需要一個實體:

class Customer {
    @Id
    Long id;
    String firstName;
    LocalDate dob;
}
<p class="indent">

請注意,不需要getter或setter。如果您意,可以增加。實際上,唯一的要求是實體有一個註釋的屬性Id(即@org.springframework.data.annotation.Id,注意不是javax.persistence,後者是JPA)。

接下來,我們需要宣告一個儲存庫。最簡單的方法是擴充套件CrudRepository:

interface CustomerRepository extends CrudRepository<Customer, Long> {}
<p class="indent">


最後,我們需要配置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();
    }
}
<p class="indent">


讓我們一步一步地解釋。

1. EnableJdbcRepositories可以建立儲存庫。由於它需要存在一些bean,我們需要其餘的配置。

2. 繼承擴充套件的JdbcConfiguration將一些預設bean新增到ApplicationContext。可以覆蓋其方法以自定義Spring Data JDBC的某些行為。現在,我們使用預設實現。

3. 真正重要的部分是NamedParameterJdbcOperations,它在內部用於向資料庫提交SQL語句。

4. 嚴格來說,事務管理器不是必需的。不支援跨越多個SQL語句的事務。

5. Spring Data JDBC沒有直接使用DataSource,但是,由於TransactionManager和NamedParameterJdbcOperations需要,將DataSource註冊為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");
    }
}
<p class="indent">


@Query 註解
你可能不會只使用基本的CRUD方法CrudRepository。可以使用簡單的@Query註釋來指定儲存庫方法的查詢:

@Query("select id, first_name, dob from customer where upper(first_name) like '%' || upper(:name) || '%' ")
List<Customer> findByName(@Param("name") String name);
<p class="indent">


請注意,@Param如果使用-parameters標誌進行編譯,則不需要註釋。

如果要執行更新或刪除語句,可以使用@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)
}
<p class="indent">


由於Java物件與其對應行之間的連線是Id型別,因此設定Id為null並再次儲存它會在資料庫中建立另一行。

我們正在進行不區分大小寫(例如)搜尋,因此,我們找到“Albert”和“Bertram”,但不是“Beth”。

Introducing Spring Data JDBC

相關文章