什么是JPA?
全称Java Persistence API,可以通过注解或者XML描述【对象-关系表】之间的映射关系,并将实体对象持久化到数据库中。
为我们提供了:
1)ORM映射元数据:JPA支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;
如:@Entity、@Table、@Column、@Transient等注解。
2)JPA 的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
如:entityManager.merge(T t);
3)JPQL查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。
如:from Student s where s.name = ?
JPA仅仅是一种规范,也就是说JPA仅仅定义了一些接口,而接口是需要实现才能工作的。所以底层需要某种实现,而Hibernate就是实现了JPA接口的ORM框架。
也就是说:
JPA是一套ORM规范,Hibernate实现了JPA规范:
什么是spring data jpa?
spirng data jpa是spring提供的一套简化JPA开发的框架,按照约定好的【方法命名规则】写dao层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作。同时提供了很多除了CRUD之外的功能,如分页、排序、复杂查询等等。
Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的 JPA 技术实现。如图:
接口约定命名规则:
CrudRepository接口:提供了最基本的对实体类的添删改查操作
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();//删除所有实体
PagingAndSortingRepository接口:提供了分页与排序的功能:
Iterable<T> findAll(Sort sort); //排序
Page<T> findAll(Pageable pageable); //分页查询(含排序功能)
JpaRepository接口:提供了JPA的相关功能:
List<T> findAll(); //查找所有实体
List<T> findAll(Sort sort); //排序、查找所有实体
List<T> save(Iterable<? extends T> entities);//保存集合
void flush();//执行缓存与数据库同步
T saveAndFlush(T entity);//强制执行持久化
void deleteInBatch(Iterable<T> entities);//删除一个实体集合
springBoot使用实例:
1.pom添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
2.实体类User添加注解:
package com.example.domain;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
@Entity
//@NamedQuery:在Repository接口定义的findByName方法不使用默认的查询实现,而是使用自定义查询语句去查询
//不标注,则使用默认实现
@NamedQuery(name = "User.findByName", query = "select name,address from User u where u.name=?1")
public class User implements Serializable{
private static final long serialVersionUID = 1L;
//主键
@Id
long id;
//对应数据库字段的列名
@Column(name = "name")
String name;
@Column(name = "address")
String 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 String getAddress(){
return address;
}
public void setAddress(String address){
this.address = address;
}
}
3.编写Repository接口(dao层)
package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.domain.User;
public interface UserJpaRepository extends JpaRepository<User,Long> {
}
这里的UserJpaRepository接口实现了JpaRepository接口。JpaRepository实现了PagingAndSortingRepository接口,PagingAndSortingRepository接口实现了CrudRepository接口,CrudRepository接口实现了Repository接口。
Repository接口是一个标识接口,里面是空的;
CrudRepository接口定义了增删改查方法;
PagingAndSortingRepository接口用于分页和排序;
由于JpaRepository接口继承了以上所有接口,所以拥有它们声明的所有方法;
但是使用过程中还是需要注意:以findAll方法为例,JpaRepository接口返回的是List,而PagingAndSortingRepository和CrudRepository返回的是迭代器;
UserRepository:
package com.example.repository;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param;
import com.example.domain.User;
public interface UserRepository extends Repository<User, Long>{
List<User> findByNameAndAddress(String name, String address);
@Query(value = "from User u where u.name=:name")
List<User> findByName1(@Param("name") String name);
@Query(value = "select * from #{#entityName} u where u.name=?1", nativeQuery = true)
List<User> findByName2(String name);
List<User> findByName(String name);
}
UserRepository接口主要定义了一些查询方法;
findByNameAndAddress方法:无需额外定义其查询语句就能直接执行。因为Spring Data Jpa会根据实体类的属性名字以及方法名自动实现该方法;
findByName方法:由于实体类中声明了@NamedQuery注解,则使用@NamedQuery注解标注的查询语句去查询;
@Query用来配置自定义SQL的注解。参数nativeQuery = true表明使用原生sql,如果不配置,默认是false,则使用HQL查询。
findByName1方法:使用了HQL语句查询;
findByName2方法:使用了原始的sql语句查询。
4.配置数据库配置:
application.properties:
spring.jpa.show-sql = true logging.level.org.springframework.data=DEBUG spring.jpa.hibernate.ddl-auto= spring.datasource.url=jdbc:mysql://localhost:3306/demo spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver
5.controller、service编写和普通项目一样
@Query配合@Modifying使用:
@Query注解单独使用:只能用来查询的;配合@Modifying注解一起使用,则可以完成数据的删除、添加、更新操作。
需要注意,此处还需要使用事务注解进行事务管理,否则会抛出TranscationRequiredException异常。
即加上@Transactional注解即可。
分页查询
UserRepository:
Page<Person> findByNameAndPassword(String name ,String password,Pageable pageable);
service层:
Page<Person> p1 = personRepository.findByNameAndPassword("张三","123", new PageRequest(1,10,new Sort("id")));
List<Person> list=p1.getContent();
数据排序
UserRepository:
List<Person> findByNameAndPassword(String name ,String password,Sort sort);
service层:
List<Person> p1 = personRepository.findByNameAndPassword("张三","123",new Sort(Sort.Direction.ASC,"id"));//根据Id升序排序
总结:
SpringDataJPA是Spring Data的一个子项目,通过提供基于JPA的Repository极大的减少了JPA作为数据访问方案的代码量,仅需要编写一个接口集成下SpringDataJPA内部定义的接口,即可完成简单的CRUD操作。
来源:oschina
链接:https://my.oschina.net/u/3858564/blog/2249966