spring boot 內(nèi)嵌數(shù)據(jù)庫(kù)支持
內(nèi)存數(shù)據(jù)庫(kù)不能提供數(shù)據(jù)持久化风喇,但用于測(cè)試很方便;Spring boot自動(dòng)配置的內(nèi)嵌數(shù)據(jù)庫(kù)包括H2,HSQL,Derby属百。不需要使用任何連接數(shù)據(jù)庫(kù)的URL强经,只需添加要使用的內(nèi)嵌數(shù)據(jù)庫(kù)依賴就可以婿禽。例如:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
內(nèi)嵌數(shù)據(jù)庫(kù)需要使用Spring-jdbc依賴眼滤,但是spring-boot-starter-data-jpa已經(jīng)包含巴席,所以不需要額外添加。
如果不在Srping boot中使用則對(duì)應(yīng)maven配置如下:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>Lovelace-RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
配置數(shù)據(jù)源
Spring boot使用如下策略選擇數(shù)據(jù)庫(kù)連接池:
1诅需,如果HikariCP可用的話漾唉,更傾向使用HikariCP荧库,提供更好的性能和并發(fā);
2赵刑,如果Tocmat DataSource鏈接池存在分衫,HikariCp不存在,則使用Tomcat DataSource般此;
3蚪战,如果以上兩個(gè)均不存在,如果Commons DBCP2存在則使用铐懊。
如果在Spring boot中使用spring-boot-starter-jdbc或則使用spring-boot-starter-data-jpa起步依賴屎勘,會(huì)自動(dòng)添加HikariCP依賴【影牵可以使用spring.datasource.type配置指定數(shù)據(jù)庫(kù)鏈接池。
數(shù)據(jù)源的配置使用額外的配置屬性丑慎,使用前綴spring.datasource.*喜喂,例如:
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
如果使用HikariCP,可以使用spring.datasource.hikari.指定特定屬性配置竿裂;如果tomcat pool可以使用spring.datasource.tomcat.配置玉吁。
使用數(shù)據(jù)源
Spring的JdbcTemplate和NamedParameterJdbcTemplate會(huì)自動(dòng)配置,通過(guò) @Autowire注解可以直接在Bean中使用腻异。例如:
@Component
public class UserDao{
@Autowired
private final JdbcTemplate jdbcTemplate;
// ...
}
spring-data-jpa
通過(guò)Spring jpa可以實(shí)現(xiàn)定義interface查詢數(shù)據(jù)庫(kù)进副,即根據(jù)方法名自動(dòng)生成sql語(yǔ)句,而不需要寫(xiě)具體查詢語(yǔ)句悔常。Spring 提供的接口有以下幾個(gè):
org.springframework.data.repository.Repository<T, ID>
org.springframework.data.repository.CrudRepository<T, ID>
org.springframework.data.repository.PagingAndSortingRepository<T, ID>
org.springframework.data.jpa.repository.JpaRepository<T, ID>
其中CrudRepository繼承自Repository影斑,PagingAndSortingRepository繼承自CrudRepository,JpaRepository繼承自PagingAndSortingRepository和QueryByExampleExecutor接口机打,定義的方法名稱根據(jù)規(guī)則就可以實(shí)現(xiàn)自動(dòng)生成sql語(yǔ)句矫户。
為了實(shí)現(xiàn)幾個(gè)不同的接口,先定義的一個(gè)Person Entity
@Entity(name="person")
public class Person implements Serializable{
private static final long serialVersionUID = 1L;
@Id
private String id;
@Column(name="name")
private String name;
@Column(name="password")
private String password;
@Column(name="country")
private String country;
@Column(name="city")
private String city;
@Column(name="street")
private String street;
// setter getter 省略
....
}
實(shí)現(xiàn)CrudRepository接口
創(chuàng)建PersonCrudRepository接口残邀,并定義部分查詢方法
@Repository
public interface PersonCrudRepository extends CrudRepository<Person,String>{
public Person save(Person person);
public Person findPersonById(String id);
public List<Person> findPersonByName(String name);
public List<Person> findPersonByCity(String city);
}
實(shí)現(xiàn)PagingAndSortingRepository
以同樣方法創(chuàng)建PersonPagingAndSortingRepository接口
@Repository
public interface PersonPagingAndSortingRepository extends PagingAndSortingRepository<Person, String>{
}
實(shí)現(xiàn)JpaRepository接口
創(chuàng)建PersonJpaRepository接口皆辽,并使用其繼承的Query接口方法定義查詢
@Repository
public interface PersonJpaRepository extends JpaRepository<Person, String>{
public Person save(Person person);
public Person findPersionById(String id);
public List<Person> findPersonByName(String name);
// 允許查詢結(jié)果中取出重復(fù)值
public List<Person> findDistinctPeopleByNameOrCity(String name, String city);
public List<Person> findPeopleDistinctByNameOrCity(String name, String city);
// 指定屬性忽略大小寫(xiě)
public List<Person> findByNameIgnoreCase(String name);
// 多個(gè)屬性忽略大小寫(xiě)
public List<Person> findByCityAndCountryAllIgnoreCase(String city, String coutry);
// 使用order進(jìn)行排序
public List<Person> findByNameOrderByNameAsc(String name);
public List<Person> findByCityOrderByCityDesc(String city);
}
自定義Repository接口
使用@NoRepositoryBean注解自定義Repository接口,例如:
@NoRepositoryBean
public interface MyRepository<T,ID extends Serializable> extends Repository<T, ID> {
Optional<T> findById(ID id);
<S extends T> S save(S entity);
}
自定義Repository的使用方法和Spring中定義的Repository使用方式相同芥挣,例如:
@Repository
public interface MyRepositoryTest extends MyRepository<Person, String>{
}
測(cè)試
不使用內(nèi)置數(shù)據(jù)庫(kù)測(cè)試驱闷,使用自己配置的mysql數(shù)據(jù)。編寫(xiě)測(cè)試用例會(huì)使用如下幾個(gè)注解:
@RunWith(SpringRunner.class)
@DataJpaTest :使用內(nèi)置H2數(shù)據(jù)庫(kù)作為測(cè)試數(shù)據(jù)庫(kù)空免,需要在maven添加對(duì)h2數(shù)據(jù)庫(kù)的支持空另;
@JdbcTest:使用配置數(shù)據(jù)源的庫(kù)作為測(cè)試庫(kù)
@AutoConfigureTestDatabase(replace = Replace.NONE) :使用真實(shí)數(shù)據(jù)源測(cè)試,不使用內(nèi)置數(shù)據(jù)庫(kù)替換蹋砚。通過(guò)Repalce.NONE參數(shù)指定
@TestPropertySource(locations={"classpath:application.properties"}) :指定配置文件位置
@SpringBootTest:指定test class為spring boot test
測(cè)試用例如下:
@RunWith(SpringRunner.class)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@TestPropertySource(locations={"classpath:application.properties"})
@SpringBootTest
public class PersonCrudRepositoryTest {
@Autowired
private PersonCrudRepository personCrudRepository;
@Autowired
private PersonJpaRepository personjpa;
@Autowired
private PersonPagingAndSortingRepository personPage;
@Autowired
private MyRepositoryTest myRepositoryTest;
@Test
public void testSavePerson() {
Person person = new Person();
person.setId("12345");
person.setName("zhongzhong90");
person.setPassword("12345678");
person.setCountry("china");
person.setCity("chengdu");
person.setStreet("雙楠");
assertNotNull(personCrudRepository.save(person));
Person person2 = new Person();
person2.setId("123455");
person2.setName("zhongzhong2");
person2.setPassword("12345678");
person2.setCountry("china");
person2.setCity("chengdu");
person2.setStreet("雙楠2");
assertNotNull(personjpa.save(person2));
Person person3 = new Person();
person3.setId("1234556");
person3.setName("ZHONGZHONG");
person3.setPassword("12345678");
person3.setCountry("china");
person3.setCity("chengdu");
person3.setStreet("雙楠2");
assertNotNull(personPage.save(person3));
Person person4 = new Person();
person4.setId("123455667");
person4.setName("ZHONGZHONG2");
person4.setPassword("12345678");
person4.setCountry("china");
person4.setCity("綿陽(yáng)");
person4.setStreet("雙楠2");
assertNotNull(myRepositoryTest.save(person4));
}
//其他方法省略
...
}