Spring Data是Spring的一个子项目。用于简化数据库访问,支持NoSQL和关系数据存储。其主要目标是使用数据库的访问变得方便快捷。
SpringData 项目所支持NoSQL存储:
MongoDB(文档数据库)
Neo4j(图形数据库)
Redis(键/值存储)
Hbase(列族数据库)
SpringData 项目所支持的关系数据存储技术:
JDBC
JPA
Spring Data : 致力于减少数据访问层 (DAO) 的开发量. 开发者唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data JPA 来帮你完成!
SpringData JPA只是SpringData框架下的一个基于JPA标准操作数据的模块。
Spring Data JPA 通过提供基于JPA的Repository极大地减少了JPA作为数据访问方案的代码量,开发者可以省略持久层业务逻辑的工作,唯一要做的就是声明持久层借口,其他的都交给Spring Data JPA 完成.
Repository接口
1、Repository是一个空接口,即:是一个标记接口,表示任何继承它的接口都是仓库接口类
2、若我们继承了Repository,则该接口会被Ioc容器表示为一个Repository Bean,放入到IOC容器中,进而可以在该接口中定义满足一定规范的方法
3、实际上也可以通过@RepositoryDefinition(domainClass = Person.class, idClass = Long.class)来替代继承Repository接口
子接口
CrudRepository:继承Repository,实现一组CURD相关的方法
T save(T entity);//保存单个实体
Iterable<T> save(Iterable<? extends T> entities);//保存集合
T findOne(ID id);//根据id查找实体
boolean exists(ID id);//根据id判断实体是否存在
Iterable<T> findAll();//查询所有实体,不用或慎用!
long count();//查询实体数量
void delete(ID id);//根据Id删除实体
void delete(T entity);//删除一个实体
void delete(Iterable<? extends T> entities);//删除一个实体的集合
void deleteAll();//删除所有实体,不用或慎用!
PagingAndSortingRespository:继承CrudRepository,实现了一组分页排序相关的方法
/该接口提供了分页与排序功能
Iterable<T> findAll(Sort sort); //排序
Page<T> findAll(Pageable pageable); //分页查询(含排序功能)
JpaRepository:继承PagingAndSortingRespository,实现了一组JPA规范相关的方法
<S extends T> List<S> saveAll(Iterable<S> var1):批量保存
void flush():刷新。同步Jpa缓存和数据库
<S extends T> S saveAndFlush(S var1):相当于JPA的merge方法
void deleteInBatch(Iterable<T> var1):批量删除
void deleteAllInBatch():批量删除所有
自定义的XxxRepository:需要继承JpaRepository,这样该接口就具备了通用的数据访问控制层的能力
JpaSpecificationExecutor:不属于Repository体系,实现一组 JPA Criteria 查询相关的方法
开发步骤:
1、引入依赖
<!-- springdata Jpa依赖包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql数据库连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2、配置mysql配置及其JPA配置
######################################数据库配置###################################
spring.datasource.url=jdbc:mysql://135.*.*.4:3306/xxl_job?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=**
spring.datasource.password=**
#######################################SpringData配置##################################
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
#通过方法名解析sql的策略,具体说明可以看README,这里就不配置了
#第一:org.hibernate.cfg.DefaultNamingStrategy 这个直接映射,不会做过多的处理(前提没有设置@Table,@Column等属性的时候)。如果有@Column则以@Column为准
#第二:org.hibernate.cfg.ImprovedNamingStrategy 表名,字段为小写,当有大写字母的时候会转换为分隔符号“_”。
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
#编码格式
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8
3、创建实体类
package qingxia.tang.jpa.bean;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
/**
* 使用@Entity进行实体类的持久化操作,当JPA检测到我们的实体类中有@Entity注解时,会在数据库生成相应的表结构信息
* 如何指定主键和主键的生成策略@Id
* @author tangqingxia
*
*/
@Entity
public class Cat {
/**
* @GeneratedValue(strategy=GenerationType.AUTO)指定主键生成规则,mysql默认的是自增长
*/
@Id@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private int age;
/**
* @Column注解定义数据库表中字段名称
*/
@Column(name="address_id")
private Long addressId;
public Long getAddressId() {
return addressId;
}
public void setAddressId(Long addressId) {
this.addressId = addressId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4、创建repository接口类
package qingxia.tang.jpa.repository;
import org.springframework.data.repository.CrudRepository;
import qingxia.tang.jpa.bean.Cat;
public interface CatRepository extends CrudRepository<Cat, Integer>{
}
package qingxia.tang.jpa.repository;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import qingxia.tang.jpa.bean.Cat;
/**
* 此类全部是自定义接口类
**/
public interface CatDefineRepository extends JpaRepository<Cat, Integer>{
/**
* Repository 查询方法定义规范
* 一、方法必须以find|read|get开头
* 二、涉及查询条件时,条件的实行用条件关键字连接,注意:条件属性需要首字母大写
* 三、支持属性的级联查询,
* 1、若当前类有符合条件的属性,会优先使用属性,而不是使用级联属性
* 2、若要使用级联属性,则属性之间用 _ 连接。而为了避免歧义,推荐使用 _ 分隔的写法。
* 四、缺点
* 方法名很长、不能用于子查询
*/
/**
* 自定义根据name查询cat对象
* @param name
* @return
*/
public Cat getCatByName(String name);
public Cat getByAddressId(Long id);
/**
* @Query注解sql表的首字母要大写如Cat而不能是cat
* 1、自定义的JPQL语句以更灵活的查询
* @return
*/
@Query("from Cat t")
public List<Cat> getCatAll();
/**
* 使用占位符:参数顺序必须和JPQL中的顺序一致
* addressId要与Cat实体类的属性名保持一致,而非表中字段名
* 参数类型要与Cat实体类中对应的属性类型保持一致
* @param id
* @param age
* @return
*/
@Query("from Cat t where t.addressId=?1 and t.age=?2")
public List<Cat> getCatByaddressIdAndByAge(Long id,int age);
/**
* 使用命名参数:这种写法可以随便设置参数顺序
* @param age
* @param id
* @return
*/
@Query("from Cat t where t.addressId=:id and t.age=:age")
public List<Cat> getCatByaddressIdAndByAge1(@Param("age")int age,@Param("id")Long id);
/**
* spring data允许在占位符上添加%(适用于模糊查询like:%占位符%)
* @param name
* @return
*/
@Query("from Cat t where t.name like %?1%")
public Cat getCatByNa(String name);
/**
* @Query支持原生sql查询
* @return
*/
@Query(value="select count(1) from Cat t",nativeQuery=true)
public int getAllCatCount();
/**
* @Modifying:可以使用该注解来实现通过JPQL修改和删除(JPQL不支持添加)
* 注意:更新和删除操作需要事务支持
* 在@Query中编写JPQL语句,但是必须添加@Modifying进行修饰来告诉JPA这是修改的操作
* @param name
* @param age
* @param id
*/
@Modifying
@Query(value="update Cat t set t.name=?1 where t.age=?2 and t.id=?3")
@Transactional
public void updateName(String name,int age,int id);
}
5、编写service层
package qingxia.tang.jpa.service;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import qingxia.tang.jpa.bean.Cat;
import qingxia.tang.jpa.repository.CatDefineRepository;
import qingxia.tang.jpa.repository.CatRepository;
@Service
public class CatService {
@Resource
CatRepository catRepository;
@Resource
CatDefineRepository catDefineRepository;
public void save(Cat cat){
catRepository.save(cat);
}
public void delete(int id){
catRepository.delete(id);
}
public Iterable<Cat> findAll(){
Iterable<Cat> findAll = catRepository.findAll();
return findAll;
}
public Cat getCatByName(String name){
Cat cat = catDefineRepository.getCatByName(name);
return cat;
}
public Cat getByAddressId(Long id){
Cat byAddress_Id = catDefineRepository.getByAddressId(id);
return byAddress_Id;
}
public List<Cat> getCatAll(){
List<Cat> catAll = catDefineRepository.getCatAll();
return catAll;
}
public List<Cat> getCatByaddressIdAndByAge(Long id,int age){
List<Cat> catByaddressIdAndByAge = catDefineRepository.getCatByaddressIdAndByAge(id, age);
return catByaddressIdAndByAge;
}
public List<Cat> getCatByaddressIdAndByAge1(Long id,int age){
List<Cat> catByaddressIdAndByAge1 = catDefineRepository.getCatByaddressIdAndByAge1(age, id);
return catByaddressIdAndByAge1;
}
public Cat getCatByNa(String name){
Cat catByNa = catDefineRepository.getCatByNa(name);
return catByNa;
}
public int getAllCatCount(){
int allCatCount = catDefineRepository.getAllCatCount();
return allCatCount;
}
public void updateName(String name,int age,int id){
catDefineRepository.updateName(name, age, id);
}
}
6、编写controller层
package qingxia.tang.jpa.controller;
import java.util.List;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import qingxia.tang.jpa.bean.Cat;
import qingxia.tang.jpa.service.CatService;
@RestController
public class CatController {
@Resource
CatService catService;
@RequestMapping("/save")
@Transactional
public String save(Cat cat){
cat.setAge((int)((Math.random())*100));
cat.setName("理科");
cat.setAddressId(16l);
catService.save(cat);
return "save is ok";
}
@RequestMapping("/delete")
@Transactional
public String delete(int id){
catService.delete(id);
return "delete is OK";
}
@RequestMapping(value="/findAll",produces={"application/json;charset=UTF-8"})
public Iterable<Cat> findAll(){
Iterable<Cat> findAll = catService.findAll();
return findAll;
}
/**
* http://localhost:8080/getCatByName?name=理科
* @param name
* @return
*/
@RequestMapping(value="/getCatByName",produces={"application/json;charset=UTF-8"})
public Cat getCatByName(String name){
Cat cat = catService.getCatByName(name);
return cat;
}
/**
* http://localhost:8080/getByAddress_Id?id=450
* @param id
* @return
*/
@RequestMapping(value="/getByAddress_Id",produces={"application/json;charset=UTF-8"})
public Cat getByAddressId(Long id){
Cat byAddress_Id = catService.getByAddressId(id);
return byAddress_Id;
}
@RequestMapping(value="/getCatAll",produces={"application/json;charset=UTF-8"})
public List<Cat> getCatAll(){
List<Cat> catAll = catService.getCatAll();
return catAll;
}
/**
* http://localhost:8080/getCatByaddressIdAndByAge?id=16&age=17
* @param id
* @param age
* @return
*/
@RequestMapping(value="/getCatByaddressIdAndByAge",produces={"application/json;charset=UTF-8"})
public List<Cat> getCatByaddressIdAndByAge(Long id,int age){
List<Cat> catByaddressIdAndByAge = catService.getCatByaddressIdAndByAge(id, age);
return catByaddressIdAndByAge;
}
/**
* http://localhost:8080/getCatByaddressIdAndByAge1?id=16&age=67
* @param id
* @param age
* @return
*/
@RequestMapping(value="/getCatByaddressIdAndByAge1",produces={"application/json;charset=UTF-8"})
public List<Cat> getCatByaddressIdAndByAge1(Long id,int age){
List<Cat> catByaddressIdAndByAge1 = catService.getCatByaddressIdAndByAge1(id, age);
return catByaddressIdAndByAge1;
}
/**
* http://localhost:8080/getCatByNa?name=3
* @param name
* @return
*/
@RequestMapping(value="/getCatByNa",produces={"application/json"})
public Cat getCatByNa(String name){
Cat catByNa = catService.getCatByNa(name);
return catByNa;
}
/**
* http://localhost:8080/getAllCatCount
* @return
*/
@RequestMapping(value="/getAllCatCount",produces={"application/json"})
public int getAllCatCount(){
int allCatCount = catService.getAllCatCount();
return allCatCount;
}
/**
* http://localhost:8080/updateName?name=%E6%96%87%E7%A7%91&age=16&id=3
* @param name
* @param age
* @param id
* @return
*/
@RequestMapping("/updateName")
public String updateName(String name,int age,int id){
catService.updateName(name, age, id);
return "update is ok";
}
}
总结:springboot集成springdata Jpa,需要访问数据库进行业务逻辑处理时,首先将自己定义的repositoty集成JpaRepository即可使用repository提供的所有接口能力,如repository自带接口能力不满足实际的业务需求,需自己重新定义接口时,建议用Query注解的形式开发新的接口进行mysql数据库交互。