Spring Data項目是Spring用來解決數(shù)據(jù)訪問問題的一攬子解決方案。
全部章節(jié)傳送門:
Spring Boot學習筆記(一):Spring Boot 入門基礎(chǔ)
Spring Boot學習筆記(二):Spring Boot 運行原理
Spring Boot學習筆記(三):Spring Boot Web開發(fā)
Spring Boot學習筆記(四):Spring Boot 數(shù)據(jù)訪問
Spring Boot學習筆記(五):Spring Boot 企業(yè)級開發(fā)
Spring Boot學習筆記(六):Spring Boot 應(yīng)用監(jiān)控
Spring Data JPA
Spring Data JPA是Spring Data的一個子項目婚脱,它提供了一套簡化JPA開發(fā)的框架,用來簡化數(shù)據(jù)庫訪問增热。同時提供了很多除了CRUD之外的功能,如分頁盅粪、排序钓葫、復雜查詢等等。
準備環(huán)境
創(chuàng)建數(shù)據(jù)表
在MySQL數(shù)據(jù)庫中建立一個數(shù)據(jù)表t_person票顾,用來進行后面的測試础浮,并在里面隨便添加幾條數(shù)據(jù)帆调。
create table t_person (
id INT PRIMARY KEY AUTO_INCREMENT,
name varchar(10),
age INT,
address VARCHAR(20)
) CHARACTER SET UTF8;
建立項目
建立一個springboot項目,在pom.xml中添加如下依賴豆同。其中g(shù)uava是一個工具包番刊。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置基本屬性
在application.properties里面配置數(shù)據(jù)源和JPA相關(guān)屬性。
# 數(shù)據(jù)庫相關(guān)
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springstudy
spring.datasource.username=spring
spring.datasource.password=spring
spring.datasource.dirverClassName=com.mysql.jdbc.Driver
# 根據(jù)實體類自動維護數(shù)據(jù)庫表結(jié)構(gòu)的功能
spring.jpa.hibernate.ddl-auto=none
# 設(shè)置hibernate操作的時候在控制臺顯示真實的SQL語句
spring.jpa.show-sql=true
# 讓控制器輸出的json字符串格式更美觀
spring.jackson.serialization.indent_output=true
其中影锈,spring.jpa.hibernate.ddl-auto 提供根據(jù)實體類自動維護數(shù)據(jù)庫表結(jié)構(gòu)的功能芹务,可選值包括:
- create----每次運行該程序,沒有表格會新建表格鸭廷,表內(nèi)有數(shù)據(jù)會清空枣抱。
- create-drop----每次程序結(jié)束的時候會清空表。
- update----每次運行程序辆床,沒有表格會新建表格佳晶,表內(nèi)有數(shù)據(jù)不會清空,只會更新讼载。
- validate----運行程序會校驗數(shù)據(jù)與數(shù)據(jù)庫的字段類型是否相同轿秧,不同會報錯。
- none----不采取任何措施咨堤。
定義映射實體類
創(chuàng)建實體類Person菇篡,將數(shù)據(jù)表的字段映射過來。
其中一喘,@Entity注解表明這個類是一個實體驱还,任何Hibernate映射對象都要有這個注解,@Table注解用來映射表名津滞,@Column注解用來映射屬性名和字段名铝侵,不注解的時候可以自動映射灼伤,比如將name映射為NAME触徐,將testName映射為TEST_NAME。
package com.wyk.datademo;
import javax.persistence.*;
@Entity
@Table(name = "t_person") //表名
public class Person {
@Id //映射為數(shù)據(jù)庫主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY) // 生成方式為自增
private Long id;
private String name;
private Integer age;
private String address;
public Person() {}
public Person(Long id, String name, Integer age, String address) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
定義數(shù)據(jù)訪問層
使用Spring Data JPA建立數(shù)據(jù)訪問層需要定義一個繼承JapRepository的接口狐赡。
package com.wyk.datademo;
import org.springframework.data.jpa.repository.JpaRepository;
public class PersonRespositary extends JpaRepository {
...
}
JpaRepository接口存在如下數(shù)據(jù)訪問操作方法撞鹉。
package org.springframework.data.jpa.repository;
import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
<S extends T> List<S> saveAll(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
配置使用 Spring Data JPA
在Spring中,可以通過@EnableJpaRepositories注解來開啟Spring Data JPA的支持颖侄,通過接收的value參數(shù)來掃描數(shù)據(jù)訪問層所在包下的數(shù)據(jù)訪問接口定義鸟雏。
package com.wyk.datademo;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import javax.persistence.EntityManagerFactory;
@Configuration
@EnableJpaRepositories("com.wyk.datademo")
public class JpaConfigurattion {
public EntityManagerFactory entityManagerFactory() {
...
}
...
}
在Sring Boot中,會進行自動配置览祖,不需要添加如上配置代碼孝鹊。
定義查詢方法
根據(jù)屬性名查詢
Spring Data JPA支持通過定義在Repository接口中的方法名來定義查詢,而方法名是根據(jù)實體類的屬性名來確定展蒂。
根據(jù)屬性名來定義查詢方法又活。
public interface PersonRepository extends JpaRepository<Person, Long> {
/**
* 通過名字查詢
* 相當于 select p from Person p where p.name=?1
* @param name
* @return
*/
List<Person> findByName(String name);
/**
* 通過名字模糊查詢
* 相當于select p from Person p where p.name like ?1
* @param name
* @return
*/
List<Person> findByNameLike(String name);
/**
* 通過名字和地址查詢
* 相當于 select p from Perosn p where p.name=?1 and p.address=?2
* @param name
* @param address
* @return
*/
List<Person> findByNameAndAddress(String name, String address);
}
還可以通過top和first等關(guān)鍵字來限制結(jié)果數(shù)量苔咪。
```java
/**
* 查詢符合條件的前10條數(shù)據(jù)
* @param name
* @return
*/
List<Person> findFirst10ByName(String name);
/**
* 查詢符合條件的奇拿30條數(shù)據(jù)
* @param name
* @return
*/
List<Person> findTop30ByName(String name);
使用JPA的NamedQuery查詢
Spring Data JPA 支持用JPA的NamedQuery來定義查詢方法,即一個名稱映射一個查詢語句柳骄。需要在實體類上添加@NamedQuery注解团赏。
@Entity
@NamedQuery(name="Person.withNameAndAddressNamedQuery",
query = "select p from Person p where p.name = ?1 and address=?2")
@Table(name = "t_person") //表名
public class Person {
...
}
查詢使用如下語句。
/**
* 使用NamdeQuery里定義的查詢語句
* @param name
* @return
*/
Person withNameAndAddressQuery(String name, String address);
使用@Query查詢
Spring Data JPA 還支持用@Query注解在接口的方法上實現(xiàn)查詢耐薯,可以根據(jù)參數(shù)索引舔清。
@Query("select p from Person p where p.name=?1 and p.address=?2")
Person withNameAndAddressQuery(String name, String address);
還可以使用參數(shù)的名稱來匹配查詢參數(shù)。
@Query("select p from Person p where p.address= :address")
List<Person> findByAddress(@Param("address")String address);
Spring Data JPA 支持@Modifying和@Query注解組合來事件更新查詢曲初。
@Modifying
@Transactional
@Query("update Person p set p.name=?1")
int setName(String name);
分頁與排序
Spring Data JPA 也對排序和分頁提供了支持体谒。
/**
* 查詢結(jié)果排序
* @param name
* @param sort
* @return
*/
List<Person> findByName(String name, Sort sort);
/**
* 查詢結(jié)果分頁
* @param name
* @param pageable
* @return
*/
Page<Person> findByName(String name, Pageable pageable);
使用排序:
List<Person> people = personRepository.findByName("haha", new Sort(Sort.Direction.ASC, "age"));
使用分頁:
Page<Person> people2 = personRepository.findByName("haha", PageRequest.of(0, 10));
Page接口可有獲取當前頁面記錄、總頁數(shù)臼婆、總記錄數(shù)等营密。
Specification
JPA 提供了基于準則查詢的方式,即Criteria查詢目锭,可以用來進行復雜的動態(tài)查詢评汰。Spring Data JPA 提供了一個Specification接口,其中定義了一個toPredicate方法用來構(gòu)造查詢條件痢虹。
定義一個Criterial查詢被去。其中Root用來獲取需要查詢的屬性,通過CriteriaBuilder構(gòu)造查詢條件(例子中是來自北京的人).
public class CustomerSpecs {
public static Specification<Person> personFromBeijing() {
return new Specification<Person>() {
@Override
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery,
CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.equal(root.get("address"), "北京");
}
};
}
}
在接口類上需要實現(xiàn)JpaSpecificationExecutor接口奖唯。
public interface PersonRepository extends JpaRepository<Person, Long>,
JpaSpecificationExecutor<Person> {
...
}
使用的時候需要靜態(tài)導入惨缆。
import static com.wyk.datademo.CustomerSpecs.*;
注入personRepository的Bean后可以調(diào)用方法。
List<Person> people = personRepository.findAll(perosnFromBeijing());
添加控制器
將PersonRepository注入到控制器丰捷。
package com.wyk.datademo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class DataController {
//Spring Data JPA 已自動為你注冊bean坯墨,所以可自動注入
@Autowired
PersonRepository personRepository;
/**
* 保存
* @param name
* @param address
* @param age
* @return
*/
@RequestMapping("/save")
public Person save(String name, String address, Integer age) {
// save 支持批量保存
Person p = personRepository.save(new Person(null, name, age, address));
return p;
}
/**
* 測試findByAddress
* @param address
* @return
*/
@RequestMapping("/q1")
public List<Person> q1(String name) {
List<Person> people = personRepository.findByName(name);
return people;
}
/**
* 測試findByNameAndAddress
* @param name
* @param address
* @return
*/
@RequestMapping("/q2")
public Person q2(String name, String address) {
Person people = personRepository.findByNameAndAddress(name, address);
return people;
}
/**
* 測試withNameAndAddressQuery
* @param name
* @param address
* @return
*/
@RequestMapping("/q3")
public Person q3(String name, String address) {
Person people = personRepository.withNameAndAddressQuery(name, address);
return people;
}
/**
* 測試withNameAndAddressNamedQuery
* @param name
* @param address
* @return
*/
@RequestMapping("/q4")
public Person q4(String name, String address) {
Person people = personRepository.withNameAndAddressNamedQuery(name, address);
return people;
}
/**
* 測試排序
* @return
*/
@RequestMapping("/sort")
public List<Person> sort() {
List<Person> people = personRepository.findAll(new Sort(Sort.Direction.ASC, "age"));
return people;
}
/**
* 測試分頁
* @return
*/
@RequestMapping("/page")
public Page<Person> page() {
Page<Person> pagePeople = personRepository.findAll(PageRequest.of(1, 2));
return pagePeople;
}
}
查看運行結(jié)果
運行項目,依次查看結(jié)果:
保存實體(http://localhost:8080/save?name=ss&address=Shanghai&age=25):
根據(jù)屬性查詢(http://localhost:8080/q1?name=xiaoming):
根據(jù)多條屬性查詢(http://localhost:8080/q2?name=xiaoming&address=Beijing):
根據(jù)@Query注解查詢(http://localhost:8080/q3?name=xiaoming&address=Beijing):
根據(jù)NamedQuery查詢(http://localhost:8080/q4?name=xiaoming&address=Beijing):
查詢結(jié)果排序(http://localhost:8080/sort):
查詢結(jié)果分頁(http://localhost:8080/sort):
自定義Repository的實現(xiàn)
我們可以通過Spring Data JPA的JpaRepository封裝自己的數(shù)據(jù)庫操作病往,提供給Repository接口使用捣染。
定義Specification
首先需要定義Specification,本部分定制一個自動模糊查詢:當值為字符型時使用like查詢停巷,其余類型使用等于查詢耍攘,沒有值就查詢?nèi)俊?/p>
package com.wyk.datademo;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.SingularAttribute;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.collect.Iterables.toArray;
public class CustomerSpecs {
/**
* 定義一個返回值為Specification的方法byAuto
* @param entityManager
* @param example
* @param <T>
* @return
*/
public static <T> Specification<T> byAuto(final EntityManager entityManager,
final T example) {
// 獲得當前實體類對象的類型
final Class<T> type = (Class<T>)example.getClass();
return new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery,
CriteriaBuilder criteriaBuilder) {
// 新建Predicate列表存儲構(gòu)造的查詢條件
List<Predicate> predicates = new ArrayList<>();
// 獲取實體類的entityType,我們可以從中獲得實體類的屬性
EntityType<T> entity = entityManager.getMetamodel().entity(type);
//對實體類的屬性進行循環(huán)
for(Attribute<T, ?> attr : entity.getDeclaredAttributes()) {
// 獲取實體類對象某一屬性的值
Object attrValue = getValue(example, attr);
if(attrValue != null) {
// 當前屬性為字符類型的時候
if(attr.getJavaType() == String.class) {
// 當前字符不為空的情況下
if(!StringUtils.isEmpty(attrValue)) {
// 構(gòu)造當前屬性like查詢條件畔勤,并添加條件列表
predicates.add(criteriaBuilder.like(root.get(attribute(entity, attr.getName(),
String.class)), pattern((String) attrValue)));
} else {
// 構(gòu)造屬性和屬性值equal查詢條件蕾各,并添加到條件列表中
predicates.add(criteriaBuilder.equal(root.get(attribute(entity,
attr.getName(), attrValue.getClass())), attrValue));
}
}
}
}
//將條件列表轉(zhuǎn)換成Predicate
return predicates.isEmpty() ? criteriaBuilder.conjunction() :
criteriaBuilder.and(toArray(predicates, Predicate.class));
}
/**
* 通過反射獲取實體類對象對應(yīng)屬性的屬性值
* @param example
* @param attr
* @param <T>
* @return
*/
private <T> Object getValue(T example, Attribute<T, ?> attr) {
return ReflectionUtils.getField((Field) attr.getJavaMember(), example);
}
/**
* 獲取實體類當前屬性的SingularAttribute
* @param entity
* @param fieldName
* @param fieldClass
* @param <E>
* @param <T>
* @return
*/
private <E, T> SingularAttribute<T, E> attribute(EntityType<T> entity,
String fieldName, Class<E> fieldClass) {
return entity.getDeclaredSingularAttribute(fieldName, fieldClass);
}
};
}
/**
* 構(gòu)造like的查詢模式
* @param str
* @return
*/
static private String pattern(String str) {
return "%" + str + "%";
}
}
定義Repository接口
定義一個繼承JpaRepository的接口,使它具備JpaRepository接口的所有方法庆揪,還繼承了JpaSpecificationExecutor式曲,具備使用Specification的能力。
package com.wyk.datademo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
@NoRepositoryBean //表示當前接口不是領(lǐng)域類的接口
public interface CustomRepository<T, ID extends Serializable> extends
JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
Page<T> findByAuto(T example, Pageable pageable);
}
定義接口實現(xiàn)
定義一個實現(xiàn)前面接口的類缸榛,并繼承SimpleJpaRepository吝羞,讓我們可以使用SimpleJpaRepository中的方法始鱼。
package com.wyk.datademo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import javax.persistence.EntityManager;
import java.io.Serializable;
import static com.wyk.datademo.CustomerSpecs.byAuto;
public class CustomRepositoryImpl <T, ID extends Serializable> extends
SimpleJpaRepository<T, ID> implements CustomRepository<T, ID> {
private final EntityManager entityManager;
public CustomRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
/**
* 實現(xiàn)用byAuto的條件查詢,并提供分頁查詢
* @param example
* @param pageable
* @return
*/
@Override
public Page<T> findByAuto(T example, Pageable pageable) {
return findAll(byAuto(entityManager, example), pageable);
}
}
定義repositoryFactoryBean
自定義repositoryFactoryBean擴展JpaRepositoryFactoryBean脆贵,可以從獲得一個RepositoryFactory医清。
package com.wyk.datademo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import javax.persistence.EntityManager;
import java.io.Serializable;
public class CustomRepositaryFactoryBean<T extends JpaRepository<S, ID>, S, ID
extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
public CustomRepositaryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new CustomRepositoryFactory(entityManager);
}
private static class CustomRepositoryFactory<S, ID extends Serializable>
extends JpaRepositoryFactory {
public CustomRepositoryFactory(EntityManager entityManager) {
super(entityManager);
}
@Override
@SuppressWarnings({"unchecked"})
protected SimpleJpaRepository<?, ?> getTargetRepository(
RepositoryInformation information, EntityManager entityManager) {// 獲得當前自定義類的實現(xiàn)
return new CustomRepositoryImpl<S, ID>((Class<S>) information.getDomainType(), entityManager);
}
/*
@Override
@SuppressWarnings({"unchecked"})
protected <T, ID extends Serializable> SimpleJpaRepository<?, ?>
getTargetRepository (RepositoryInformation information,
EntityManager entityManager) {
return new CustomRepositoryImpl<T, ID>((Class<T>) information.getDomainType(),
entityManager);
}
*/
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return CustomRepositoryImpl.class;
}
}
}
使用自定義倉庫
讓實體類的Repository繼承自定義的Repository接口旗扑,即可使用自定義Repository中實現(xiàn)的功能祥诽。
public interface PersonRepository extends CustomRepository<Person, Long>,
JpaSpecificationExecutor<Person> {
...
}
在控制器中添加測試方法保礼。
/**
* 測試自定義倉庫
* @param person
* @return
*/
@RequestMapping("/auto")
public Page<Person> auto(Person person) {
Page<Person> pagePeople = personRepository.findByAuto(person, PageRequest.of(0, 10));
return pagePeople;
}
在運行類上使用@EnableJpaRepositories讓自定義的Repoisitory生效诵竭。
@SpringBootApplication
@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositaryFactoryBean.class)
public class DatademoApplication {
public static void main(String[] args) {
SpringApplication.run(DatademoApplication.class, args);
}
}
查看效果
運行程序醒叁,訪問http://localhost:8080/auto, 無查詢條件回窘,查看結(jié)果冯挎。
訪問http://localhost:8080/auto?address=h泉瞻,進行模糊查詢系吭。
Spring Data REST
Spring Data REST是基于Spring Data的repository之上五嫂,可以將repository自動輸出為REST資源。
配置Spring Data REST
Spring Data REST的配置是定義在RepositoryRestMvcConfiguration配置類中肯尺,我們可以通過繼承此類或者直接在自己的配置類上@Import此配置類沃缘。
繼承方式:
@Configuration
public class MyRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
@Override
public RepositoryRestConfiguraiton config() {
return super.config();
}
//其它可重寫以config開頭的方法
...
}
導入方式:
@Configuration
@Import(RepositoryRestMvcConfiguration.class)
public class AppConfig {
...
}
Spring Boot對Spring Data REST的自動配置放置在rest包中.通過SpringBootRestConfiguration類的源碼我們可以得出,Spring Boot已經(jīng)為我們自動配置了RepositoryRestConfiguration则吟,所以在Spring boot中使用Spring Data REST只需引入spring-boot-starter-data-rest的依賴槐臀,無須任何配置即可使用。
Spring boot通過在application.properties中配置以spring.data.rest為前綴的屬性來配置RepositoryRestConfiguration氓仲。
Spring Data REST實戰(zhàn)
新建SpringBoot項目水慨,與上例類似,依賴在前面的基礎(chǔ)上增加REST(spring-boot-starter-data-rest)敬扛。application.properties的配置信息與前面一樣晰洒。
添加同樣的實體類Person.java,并定義實體類的Repository啥箭。其中谍珊,在Repository中的方法上添加注解@RestResource可以將方法暴漏為REST源。
package com.wyk.datarestdemo.repository;
import com.wyk.datarestdemo.bean.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RestResource;
public interface PersonRepository extends JpaRepository<Person, Long> {
@RestResource(path="nameStartsWith", rel="nameStartsWith")
Person findByNameStartsWith(String name);
}
為了方便測試捉蚤,我們使用一個工具Postman抬驴,可以在官網(wǎng)直接下載。
運行程序缆巧,打開Postman,在其中使用GET訪問http://localhost:8080/persons/1, 收到如下返回豌拙。
使用GET訪問地址 http://localhost:8080/persons/search/nameStartsWith?name=Li, 用來測試方法陕悬。
Spring Data Rest 還支持分頁和排序,以及更新按傅、保存捉超、刪除等多個操作胧卤,這里不再展示。
Spring Data Rest定制
定制根路徑
前面提到相關(guān)配置都在application.properties中配置以spring.data.rest為前綴的屬性來配置拼岳。默認訪問路徑是根路徑枝誊,如果想修改,可以進行如下配置惜纸。
spring.data.rest.base-path=/api
定制節(jié)點路徑
在上面的例子叶撒,我們使用 http://localhost:8080/persons 訪問,這時Spring Data REST的默認規(guī)則耐版,使用實體類加s形成路徑祠够。如果想對映射名稱進行修改,需要在實體類Repository上使用@RepositoryRestResource 注解的path屬性進行修改粪牲。
@RepsositoryRestResource(path="people")
public interface PersonRepository extends JpaRepository<Person, Long> {
@RestResource(path="nameStartsWith", rel="nameStartsWith")
Person findByNameStartsWith(String name);
}
這樣訪問地址就變成了 http://localhost:8080/api/people 古瓤。
聲明式事務(wù)
Spring事務(wù)機制
Spring的事務(wù)機制是用統(tǒng)一的機制來處理不同數(shù)據(jù)訪問技術(shù)的事務(wù)處理。Spring的事務(wù)機制提供了一個PlatformTransactionManager接口腺阳,不同的數(shù)據(jù)訪問技術(shù)的事務(wù)使用不同的接口實現(xiàn)落君。
數(shù)據(jù)庫訪問技術(shù) | 實現(xiàn) |
---|---|
JDBC | DataSourceTransactionManager |
JPA | JpaTransactionManager |
Hibernate | HibernateTransactionManager |
JDO | JdoTransactionManager |
分布式事務(wù) | JtaTransactionManager |
注解事務(wù)行為
Spring支持聲明式事務(wù)。即使用注解來選擇需要使用事務(wù)的方法亭引。它使用@Transactional注解在方法上表明該方法需要事務(wù)支持叽奥。如果@Transactional注解使用在類上,則此類的所有public方法都是開啟事務(wù)的痛侍。
Spring提供了一個@EnableTransactionManagement注解在配置類上開啟聲明式事務(wù)支持朝氓。使用方式:
@Configuration
@EnableTransactionManagement
public class AppConfig {
...
}
@Transactional的屬性如下表。
參數(shù)名稱 | 功能描述 | 默認值 |
---|---|---|
readOnly | 該屬性用于設(shè)置當前事務(wù)是否為只讀事務(wù) | false |
rollbackFor | 該屬性用于設(shè)置需要進行回滾的異常類數(shù)組主届,當方法中拋出指定異常數(shù)組中的異常時赵哲,則進行事務(wù)回滾。 | Throwble的子類 |
noRollbackFor | 該屬性用于設(shè)置不需要進行回滾的異常類數(shù)組君丁,當方法中拋出指定異常數(shù)組中的異常時枫夺,不進行事務(wù)回滾。 | Throwble的子類 |
propagation | 該屬性用于設(shè)置事務(wù)的傳播行為绘闷。 | REQUIRED |
isolation | 該屬性用于設(shè)置底層數(shù)據(jù)庫的事務(wù)隔離級別橡庞,事務(wù)隔離級別用于處理多事務(wù)并發(fā)的情況,通常使用數(shù)據(jù)庫的默認隔離級別即可印蔗,基本不需要進行設(shè)置扒最。 | DEFAULT |
timeout | 該屬性用于設(shè)置事務(wù)的超時秒數(shù) | TIMEOUT_DEFAULT |
SpringBoot事務(wù)支持
Spring Data JPA對所有默認的方法都開啟了事務(wù)支持,且查詢類事務(wù)默認啟用readOnly=true屬性华嘹。
Spring Boot會自動配置事務(wù)管理器吧趣,且會自動開啟注解事務(wù)的支持。
使用和前面相同的例子,創(chuàng)建一個實體類Person和接口PersonRepository强挫。
添加業(yè)務(wù)服務(wù)接口岔霸。
package com.wyk.datarestdemo.service;
import com.wyk.datarestdemo.bean.Person;
public interface DemoService {
public Person savePersonWithRollBack(Person person);
public Person savePersonWithoutRollBack(Person person);
}
添加業(yè)務(wù)服務(wù)實現(xiàn)。
package com.wyk.datarestdemo.service.impl;
import com.wyk.datarestdemo.bean.Person;
import com.wyk.datarestdemo.repository.PersonRepository;
import com.wyk.datarestdemo.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DemoServiceImpl implements DemoService {
@Autowired
PersonRepository personRepository;
@Transactional(rollbackFor={IllegalArgumentException.class})
public Person savePersonWithRollBack(Person person) {
Person p = personRepository.save(person);
if(person.getName().equals("wyk")) {
throw new IllegalArgumentException("wyk已存在俯渤,數(shù)據(jù)將回滾");
}
return p;
}
@Transactional(noRollbackFor = {IllegalArgumentException.class})
public Person savePersonWithoutRollBack(Person person) {
Person p = personRepository.save(person);
if(person.getName().equals("wyk")) {
throw new IllegalArgumentException("wyk雖已存在呆细,數(shù)據(jù)不會回滾");
}
return p;
}
}
添加控制器。
package com.wyk.datarestdemo.controller;
import com.wyk.datarestdemo.bean.Person;
import com.wyk.datarestdemo.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@Autowired
DemoService demoService;
@RequestMapping("/rollback")
public Person rollback(Person person) {
return demoService.savePersonWithRollBack(person);
}
@RequestMapping("/norollback")
public Person noRollback(Person person) {
return demoService.savePersonWithoutRollBack(person);
}
}
運行程序八匠,訪問 http://localhost:8080/rollback?name=wyk&age=29 絮爷,這時程序拋出異常。
java.lang.IllegalArgumentException: wyk已存在臀叙,數(shù)據(jù)將回滾
at com.wyk.datarestdemo.service.impl.DemoServiceImpl.savePersonWithRollBack(DemoServiceImpl.java:20) ~[classes/:na]
at com.wyk.datarestdemo.service.impl.DemoServiceImpl$$FastClassBySpringCGLIB$$2ef6f418.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
...
查看數(shù)據(jù)庫略水。
mysql> select * from t_person;
+----+----------+------+----------+
| id | name | age | address |
+----+----------+------+----------+
| 1 | xiaoming | 22 | Beijing |
| 2 | xiaohong | 21 | Beijing |
| 3 | Peter | 18 | New York |
| 4 | Jingjing | 18 | Hengshui |
| 5 | Lily | 28 | Tianjin |
| 6 | ss | 25 | Shanghai |
+----+----------+------+----------+
6 rows in set (0.00 sec)
并沒有插入成功。
改為訪問 http://localhost:8080/norollback?name=wyk&age=29 劝萤,這時程序同樣拋出異常渊涝。
java.lang.IllegalArgumentException: wyk雖已存在,數(shù)據(jù)不會回滾
at com.wyk.datarestdemo.service.impl.DemoServiceImpl.savePersonWithoutRollBack(DemoServiceImpl.java:30) ~[classes/:na]
at com.wyk.datarestdemo.service.impl.DemoServiceImpl$$FastClassBySpringCGLIB$$2ef6f418.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
'''
查看數(shù)據(jù)庫床嫌,發(fā)現(xiàn)語句已經(jīng)插入成功跨释。
mysql> select * from t_person;
+----+----------+------+----------+
| id | name | age | address |
+----+----------+------+----------+
| 1 | xiaoming | 22 | Beijing |
| 2 | xiaohong | 21 | Beijing |
| 3 | Peter | 18 | New York |
| 4 | Jingjing | 18 | Hengshui |
| 5 | Lily | 28 | Tianjin |
| 6 | ss | 25 | Shanghai |
| 10 | wyk | 29 | NULL |
+----+----------+------+----------+
7 rows in set (0.00 sec)
Spring 數(shù)據(jù)緩存
緩存是實際工作中非經(jīng)常常使用的一種提高性能的方法, 我們會在很多場景下來使用緩存。
Spring 緩存支持
Spring 定義了 org.springframework.cache.CacheMananger 和 org.springframework.cache.Cache 接口用來統(tǒng)一不同的緩存技術(shù)厌处。其中鳖谈,CacheManager 是 Spring 提供的各種緩存技術(shù)的抽象接口, Cache 接口包含緩存的各種操作(一般不直接使用)阔涉。
Spring 支持的 CacheManager
針對不同的緩存技術(shù)缆娃,需要實現(xiàn)不同的 CacheManger,Spring 定義了多個 CacheManager 實現(xiàn)瑰排。
CacheManager | 描述 |
---|---|
SimpleCacheManager | 使用簡單的 Collection 來存儲緩存贯要,主要用來測試用途 |
ConcurrentMapCacheManager | 使用 ConcurrentMap 來存儲緩存 |
NoOpCacheManager | 僅測試用途,不會實際存儲緩存 |
EhCacheCacheManager | 使用 EhCache 作為緩存技術(shù) |
GuavaCacheManger | 使用 Google Guava 的 GuavaCache 作為緩存技術(shù) |
HazelcastCacheManager | 使用 Hazelcast 作為緩存 |
JCacheCacheManager | 使用 JCache 標準的實現(xiàn)作為緩存技術(shù) |
RedisCacheManager | 使用Redis作為緩存技術(shù) |
在我們使用任意一個實現(xiàn)的 CacheManager 的時候椭住,需注冊實現(xiàn) CacheManager 的 Bean崇渗。
@Bean
public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager) {
return new EhCacheCacheManager(ehCacheCacheManager);
}
聲明式緩存注解
Spring 提供了4個注解來聲明緩存規(guī)則。
注解 | 作用 |
---|---|
@Cacheable | 方法執(zhí)行前京郑,先從緩存中讀取數(shù)據(jù)宅广,如果緩存沒有找到數(shù)據(jù),再調(diào)用方法獲取數(shù)據(jù)些举,然后把數(shù)據(jù)添加到緩存中 |
@CachePut | 調(diào)用方法時會自動把方法返回的相應(yīng)數(shù)據(jù)放入緩存 |
@CacheEvict | 調(diào)用方法時會從緩存中移除相應(yīng)的數(shù)據(jù) |
@Caching | 組合多個注解策略在一個方法上 |
@Cacheable跟狱、@CachePut、@CacheEvit 都有 value 屬性金拒,指定緩存名稱兽肤,key 屬性指定的是數(shù)據(jù)在緩存中的存儲的鍵套腹。
開啟聲明式緩存支持
在配置類上使用 @EnableCaching 即可開啟聲明式緩存支持绪抛。
@Condiguration
@EnableCaching
public class AppConfig {
}
Spring Boot 緩存支持
在 Spring Boot 中已經(jīng)自動配置了多個 CacheManager 的實現(xiàn)资铡。在不做任何額外配置的情況下默認使用 SimpleCacheManager。Spring Boot 支持以 spring.cache 為前綴的屬性來配置緩存幢码。
spring.cache.type= # 緩存類型
spring.cache.cache-names= # 程序啟動時創(chuàng)建緩存名稱
spring.cache.ehcache.config= # ehcache配置文件地址
spring.cache.hazelcast.config= # hazelcast配置文件地址
spring.cache.jcache.provider= # 當多個 jcache 實現(xiàn)在類路徑的時候笤休,指定 jcache 實現(xiàn)
spring.cache.guava.spec= # guava specs
在 Spring Boot 環(huán)境下,只需要在項目中導入相關(guān)緩存技術(shù)的依賴包症副,并在配置類上使用 @EnableConfig 開啟緩存支持即可店雅。
新建 Spring Boot 項目,添加依賴至 pom.xml 贞铣。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
在配置文件 application.properties 中添加數(shù)據(jù)庫配置信息闹啦。
# 數(shù)據(jù)庫相關(guān)
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springstudy
spring.datasource.username=spring
spring.datasource.password=spring
spring.datasource.dirverClassName=com.mysql.jdbc.Driver
創(chuàng)建和前面相同的實體類。
package com.wyk.cachedemo.bean;
import javax.persistence.*;
@Entity
@Table(name = "t_person")
public class Person {
@Id //映射為數(shù)據(jù)庫主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY) // 生成方式為自增
private Long id;
private String name;
private Integer age;
private String address;
public Person() {}
public Person(Long id, String name, Integer age, String address) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
添加實體類的 Repository 辕坝。
package com.wyk.cachedemo.repository;
import com.wyk.cachedemo.bean.Person;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PersonRepository extends JpaRepository<Person, Long> {
}
添加業(yè)務(wù)服務(wù)接口:
package com.wyk.cachedemo.service;
import com.wyk.cachedemo.bean.Person;
public interface DemoService {
public Person save(Person person);
public void remove(Long id);
public Person findOne(Person person);
}
添加業(yè)務(wù)服務(wù)實現(xiàn):
package com.wyk.cachedemo.service.impl;
import com.wyk.cachedemo.repository.PersonRepository;
import com.wyk.cachedemo.bean.Person;
import com.wyk.cachedemo.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class DemoServiceImpl implements DemoService {
@Autowired
PersonRepository personRepository;
@Override
@CachePut(value="people", key="#person.id")
public Person save(Person person) {
Person p = personRepository.save(person);
System.out.println("為 id窍奋、key為" + p.getId() + "數(shù)據(jù)做了緩存");
return p;
}
@Override
@CacheEvict(value="people")
public void remove(Long id) {
System.out.println("刪除了id、key為" + id + "的數(shù)據(jù)庫緩存");
personRepository.deleteById(id);
}
@Override
@Cacheable(value="people", key="#person.id")
public Person findOne(Person person) {
Optional<Person> p = personRepository.findById(person.getId());
System.out.println("為 id酱畅、key為" + person.getId() + "數(shù)據(jù)做了緩存");
if(p.isPresent()) {
return p.get();
} else {
return null;
}
}
}
添加控制器:
package com.wyk.cachedemo.controller;
import com.wyk.cachedemo.bean.Person;
import com.wyk.cachedemo.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CacheController {
@Autowired
DemoService demoService;
@RequestMapping("/put")
public Person put(Person person) {
return demoService.save(person);
}
@RequestMapping("/able")
public Person cacheable(Person person) {
return demoService.findOne(person);
}
@RequestMapping("/evit")
public String evit(Long id) {
demoService.remove(id);
return "ok";
}
}
開啟緩存支持琳袄。
package com.wyk.cachedemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class CacheDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CacheDemoApplication.class, args);
}
}
運行程序。首先訪問 http://localhost:8080/able?id=1 纺酸。
第一次訪問會在控制臺打印“為 id窖逗、key為1數(shù)據(jù)做了緩存”,后面再次訪問則不會餐蔬,說明已經(jīng)存在于緩存中碎紊。
訪問 http://localhost:8080/put?name=tt&age=26&address=Hebei 。
在訪問 http://localhost:8080/able?id=11 樊诺,控制臺無輸出仗考,會直接獲得數(shù)據(jù)。
訪問 http://localhost:8080/evit?id=11 啄骇,會刪除數(shù)據(jù)及其緩存痴鳄。
切換緩存技術(shù)
切換緩存只需要在 pom.xml 中添加相應(yīng)的依賴即可,如果需要配置文件缸夹,則在類路徑下進行配置痪寻, Spring 會自動掃描。
如果我們需要使用 Guava 作為緩存技術(shù)虽惭,只需要在 pom.xml 中增加 Guava 依賴橡类。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
非關(guān)系型數(shù)據(jù)庫 NoSQL
NoSQL 是對不使用關(guān)系作為數(shù)據(jù)管理的數(shù)據(jù)庫系統(tǒng)的統(tǒng)稱,NoSQL 的主要特點是不使用 SQL 作為查詢語言芽唇,數(shù)據(jù)存儲也不是固定的表顾画、字段取劫。
NoSQL 數(shù)據(jù)庫主要有文檔存儲型(MongoDB)、圖形關(guān)系存儲型(Neo4j)和鍵值對存儲型(Redis)研侣。
MongoDB
Spring 支持
Spring 對 MongoDB 的支持主要通過 Spring Data MongoDB來實現(xiàn)谱邪,Spring Data MongoDB提供了如下功能。
Object/Document 映射注解支持
Spring Data MongoDB 提供如下注解庶诡。
注解 | 作用 |
---|---|
@Document | 映射領(lǐng)域?qū)ο笈cMongoDB的一個文檔 |
@Id | 映射當前屬性為ID |
@DbRef | 當前屬性將參考其它文檔 |
@Filed | 為文檔的屬性定義名稱 |
@Version | 將當前屬性作為版本 |
@Indexed | 用于字段惦银,表示該字段需要如何創(chuàng)建索引 |
@CompoundIndex | 用于類,以聲明復合索引 |
@GeoSpatialIndexed | 用于字段末誓,進行地理位置索引 |
@TextIndexed | 用于字段扯俱,標記該字段要包含在文本索引中 |
@Language | 用于字段,以設(shè)置文本索引的語言覆蓋屬性 |
@Transient | 默認情況下喇澡,所有私有字段都映射到文檔迅栅,此注解將會去除此字段的映射 |
@PersistenceConstructor | 標記一個給定的構(gòu)造函數(shù),即使是一個protected修飾的晴玖,在從數(shù)據(jù)庫實例化對象時使用读存。構(gòu)造函數(shù)參數(shù)通過名稱映射到檢索的DBObject中的鍵值 |
MongoTemplate
MongoTemplate 提供了數(shù)據(jù)訪問的方法,我們還需要為 MongoClient 以及 MongoDbFactory來配置數(shù)據(jù)庫連接屬性窜醉。
@Bean
public MongoClient client() throws UnknowHostException {
MongoClient client = new MongoClient(new ServerAddress("127.0.0.1",27017));
return client;
}
@Bean
public MongoDbFactory mongoDbFactory() throws Exception {
String database = new MongoCientURI("mongodb://localhost/test").getDataBase();
return new SimpleMongoDbFactory(client(), database);
}
@Bean
public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory) throws UnkownHostException {
return new MongoTemplate(mongoDbFactory);
}
Repository 支持
Spring Data MongoDB 還提供了 Repostiory 的支持宪萄,使用方式和 Spring Data JPA 一致。
public interface PersonRepository extends MongoRepository<Person, String> {
}
MongoDB 的 Repository 的支持開啟需在配置類上注解 @EnableMongoRepositories榨惰。
@Configuration
@EnableMongoRepositories
public class AppConfig {
}
Spring Boot 支持
在 Spring Boot 下使用 MongoDB拜英, 只需要引入 spring-boot-starter-data-mongodb 依賴即可,無需任何配置琅催。
其中 MongoDB 相關(guān)的信息可以在 application.properties 中以 spring.data.mongodb 為前綴進行配置居凶。
創(chuàng)建項目,添加 Web 和 MongoDB 依賴藤抡,添加如下數(shù)據(jù)庫配置信息侠碧。
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=spring
spring.data.mongodb.username=wyk
spring.data.mongodb.password=123456
添加 Person 實體類,與前面不同的是添加了一個 location 字段缠黍。
package com.wyk.mongotest.bean;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.util.Collection;
import java.util.LinkedHashSet;
@Document
public class Person {
@Id
private String id;
private String name;
private Integer age;
@Field("locs")
private Collection<Location> location = new LinkedHashSet<Location>();
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Collection<Location> getLocation() {
return location;
}
public void setLocation(Collection<Location> location) {
this.location = location;
}
}
其中 Location 類的定義如下弄兜。
package com.wyk.mongotest.bean;
public class Location {
private String place;
private String year;
public Location(String place, String year) {
this.place = place;
this.year = year;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
}
在 repository 中添加數(shù)據(jù)訪問方法。
package com.wyk.mongotest.repository;
import com.wyk.mongotest.bean.Person;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import java.util.List;
public interface PersonRepository extends MongoRepository<Person, String> {
Person findByName(String name);
@Query("{'age':?0}")
List<Person> withQueryFindByAge(Integer age);
}
添加控制器瓷式。
package com.wyk.mongotest.contronller;
import com.wyk.mongotest.bean.Location;
import com.wyk.mongotest.bean.Person;
import com.wyk.mongotest.repository.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
@RestController
public class DataController {
@Autowired
PersonRepository personRepository;
@RequestMapping("/save")
public Person save() {
Person p = new Person("wyk", 30);
Collection<Location> locations = new LinkedHashSet<>();
Location loc1 = new Location("河北", "2006");
Location loc2 = new Location("北京","2009");
locations.add(loc1);
locations.add(loc2);
p.setLocation(locations);
return personRepository.save(p);
}
@RequestMapping("/q1")
public Person q1(String name) {
return personRepository.findByName(name);
}
@RequestMapping("/q2")
public List<Person> q2(Integer age) {
return personRepository.withQueryFindByAge(age);
}
}
運行程序替饿,訪問 http://localhost:8080/save 保存數(shù)據(jù)。
還可以訪問 http://localhost:8080/q1?name=wyk 和 http://localhost:8080/q2?age=30 查看查詢結(jié)果贸典,這里不再演示视卢。
Redis
待補充。