SpringBoot之Data JPA介绍、开发
来源:互联网 发布:巨人网络最新招聘信息 编辑:程序博客网 时间:2024/06/06 03:20
一、Spring Data JPA
1.什么是Spring Data JPA
Spring Data JPA是Spring Data的一个子项目,它通过提供基于JPA的Repository极大地减少了JPA作为数据访问方案的代码量。
2.Spring Data JPA定义数据访问层方法
使用Spring Data JPA建立数据访问层十分简单,只需定义一个继承JpaRepository的接口即可,定义如下:
public interface DemoRepository extends JpaRepository<Demo, Long> { //定义数据访问操作的方法}
而继承JpaRepository接口意味着我们默认已经有了下面的数据访问操作方法:
@NoRepositoryBeanpublic interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { List<T> findAll(); List<T> findAll(Sort var1); List<T> findAll(Iterable<ID> var1); <S extends T> List<S> save(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);}
3.在springboot中使用
在springboot中已经为jpa做了自动配置,如下图:
通过上面的截图,从HibernateJpaAutoConfiguration可以看出,SpringBoot默认JPA的实现者是Hibernate;HibernateJpaAutoConfiguration依赖于DataSourceAutoConfiguration。
4.定义查询方法
a. 根据属性名查询:支持通过定义在Repository接口中的方法名来定义查询,而方法名是根据实体类的属性名来确定的。
public interface DemoRepository extends JpaRepository<Demo, Long> { /** * * 通过名字相等查询,参数为name * 相当于JPQL:select d from Demo d where d.name=?1 */ List<Demo> findByName(String name); /** * * 通过名字like查询,参数为name * 相当于JPQL: select d from Demo d where d.name like ?1 */ List<Demo> findByNameLike(String name); /** * * 通过名字和地址查询,参数为name和address * 相当于JPQL:select d from Demo d where d.name=? 1 and p.address=?2 */ List<Demo> findByNameAndAddress(String name,String address); /** * 获得符合查询条件的前10条数据 */ List<Demo> findFirst10ByName(String name); /** * 获得符合查询条件的前30条数据 */ List<Demo> findTop30ByName(String name);}
从代码可以看出,这里使用了findBy、Like、And这样的关键字。其中findBy可以用find、read、readBy、query、queryBy、get、getBy来代替。
还有更多的查询关键字,如下图所示:
b. 使用JPA的NamedQuery查询
支持用JPA的NameQuery来定义查询方法,即一个名称映射一个查询语句。定义如下:
@Entity@NamedQuery(name = "Demo.findByName",query = "select d from Demo d where d.name=?1")public class Demo{}//使用如下语句:public interface DemoRepository extends JpaRepository<Demo, Long> {/** 1. 这时我们使用的是NamedQuery里定义的查询语句,而不是根据方法名称查询*/List<Demo> findByName(String name);}
c. 使用@Query查询
支持用
@Query注解在接口的方法上实现查询,例如:
//1.使用参数索引。public interface DemoRepository extends JpaRepository<Demo, Long> { @Query("select d from Demo d where d.address=?1") List<Demo> findByAddress(String address);}//2.使用命名参数。public interface DemoRepository extends JpaRepository<Demo, Long> { @Query("select d from Demo d where d.address= :address") List<Demo> findByAddress(@Param("address") String address);}//3.更新查询,支持@Modifying和@Query注解组合来事件更新查询,例如:public interface DemoRepository extends JpaRepository<Demo, Long> { @Modifying @Transactional @Query("update Demo d set d.name=?1") int setName(String name);}//4.Specificationpublic class CustomerSpecs { public static Specification<Demo> demoFromHefei() { return new Specification<Demo>() { @Override public Predicate toPredicate(Root<Demo> root, CriteriaQuery<?> query, CriteriaBuilder cb) { return cb.equal(root.get("address"), "云南"); } }; }}//5.排序与分页public interface DemoRepository extends JpaRepository<Demo, Long> { List<Demo> findByName(String name,Sort sort); Page<Demo> findByName(String name,Pageable pageable);}//使用List<Demo> demo = demoRepository.findByName("xx", new sort(Direction.ASC,"age"));Page<Demo> demo2 = demoRepository.findByName("xx", new PageRequest(0, 10));
二、实例(SpringBoot开发)
1.pom.xml中添加jpa和mysql的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
2.实体类,Teacher
//Teacher@Entity@Table(name = "t_teacher_info")@NamedQuery(name = "Teacher.withNameAndAddressNamedQuery", query = "select t from Teacher t where t.name=?1 and t.address=?2")public class Teacher { @Id @GeneratedValue private Long id; private String name; private int age; private String address; public Teacher() { super(); } public Teacher(Long id, String name, int age, String address) { super(); this.id = id; this.name = name; this.age = age; this.address = address; } //略get、set方法。。。}
3.定义数据访问接口
public interface TeacherRepository extends JpaRepository<Teacher, Long> { //使用方法名查询,接受一个name参数,返回值为列表。 List<Teacher> findByAddress(String address); //使用方法名查询,接受name和address,返回值为单个对象。 Teacher findByNameAndAddress(String name, String address); //使用@Query查询,参数按照名称绑定。 @Query("select t from Teacher t where t.name= :name and t.address= :address") Teacher withNameAndAddressQuery(@Param("name") String name, @Param("address") String address); //使用@NamedQuery查询,请注意我们在实体类中做的@NamedQuery的定义。 Teacher withNameAndAddressNamedQuery(String name, String address);}
4.控制器-本地作为演示,省略掉service,实际项目中不可省略
@RestController@RequestMapping("/teacher")public class DemoController { @Autowired TeacherRepository teacherRepository;//1 Spring Data JPA已自动为你注册bean,所以可自动注入 /** * 保存 * * @param name * @param address * @param age * @return */ @RequestMapping("/save") public Teacher save(String name, String address, int age) { Teacher t = teacherRepository.save(new Teacher(null, name, age, address)); return t; } /** * 执行findByAddress * * @param address * @return */ @RequestMapping("/q1") public List<Teacher> q1(String address) { List<Teacher> teachers = teacherRepository.findByAddress(address); return teachers; } /** * 执行findByNameAndAddress */ @RequestMapping("/q2") public Teacher q2(String name, String address) { Teacher teacher = teacherRepository.findByNameAndAddress(name, address); return teacher; } /** * 执行withNameAndAddressQuery */ @RequestMapping("/q3") public Teacher q3(String name, String address) { Teacher teacher = teacherRepository.withNameAndAddressQuery(name, address); return teacher; } /** * 执行withNameAndAddressNamedQuery */ @RequestMapping("/q4") public Teacher q4(String name, String address) { Teacher teacher = teacherRepository.withNameAndAddressNamedQuery(name, address); return teacher; } /** * 执行排序 */ @RequestMapping("/sort") public List<Teacher> sort() { List<Teacher> teachers = teacherRepository.findAll(new Sort(Direction.ASC, "age")); return teachers; } /** * 执行分页 */ @RequestMapping("/page") public Page<Teacher> page() { Page<Teacher> pageTeacher = teacherRepository.findAll(new PageRequest(1, 2)); return pageTeacher; }}
5、测试(测试工具:postman介绍)
1. save功能测试
2. q1功能测试
3. q2功能测试
4.q3功能测试
5.q4功能测试
6.sort功能测试 (代码中是按照age升序排序【Sort(Direction.ASC, “age”)】)
7.page功能测试(代码中取了2条【new PageRequest(1, 2)】)
三、利用Spring Data Jpa做自定义Repository
1.pom.xml中添加依赖
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.4-jre</version> </dependency>
2.定义Specification:
public class CustomerSpecs { //1定义一个返回值为Specification的方法byAuto,这里使用的是泛型T,所以这个Specification是可以用于任意的实体类的。它接受的参数是entityManager和当前的包含值作为查询条件的实体类对象。 public static <T> Specification<T> byAuto(final EntityManager entityManager, final T example) { final Class<T> type = (Class<T>) example.getClass();//2获得当前实体类对象类的类型。 return new Specification<T>() { @Override public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) { List<Predicate> predicates = new ArrayList<>(); //3新建Predicate列表存储构造的查询条件。 EntityType<T> entity = entityManager.getMetamodel().entity(type);//4获得实体类的EntityType,我们可以从EntityType获得实体类的属性。 for (Attribute<T, ?> attr : entity.getDeclaredAttributes()) {//5对实体类的所有属性做循环。 Object attrValue = getValue(example, attr); //6获得实体类对象某一个属性的值。 if (attrValue != null) { if (attr.getJavaType() == String.class) { //7当前属性值为字符类型的时候。 if (!StringUtils.isEmpty(attrValue)) { //8若当前字符不为空的情况下。 predicates.add(cb.like(root.get(attribute(entity, attr.getName(), String.class)), pattern((String) attrValue))); //9构造当前属性like(前后%)属性值查询条件,并添加到条件列表中。 } } else { //这里注释掉是因为如果字段不为String类型会自动分配值,如(int=0),导致自动查询结果有误 //predicates.add(cb.equal(root.get(attribute(entity, attr.getName(), attrValue.getClass())), attrValue)); //10其余情况下,构造属性和属性值equal查询条件,并添加到条件列表中。 } } } return predicates.isEmpty() ? cb.conjunction() : cb.and(toArray(predicates, Predicate.class));//11将条件列表转换成Predicate。 } /** * 12通过反射获得实体类对象对应属性的属性值。 */ private <T> Object getValue(T example, Attribute<T, ?> attr) { return ReflectionUtils.getField((Field) attr.getJavaMember(), example); } /** * 13获得实体类的当前属性的SingularAttribute, SingularAttribute包含的是实体类的某个单独属性。 */ private <E, T> SingularAttribute<T, E> attribute(EntityType<T> entity, String fieldName, Class<E> fieldClass) { return entity.getDeclaredSingularAttribute(fieldName, fieldClass); } }; } /** * 14构造like的查询模式,即前后加%。 */ static private String pattern(String str) { return "%" + str + "%"; }}
3.定义接口:
/** * 此例中的接口继承了JpaRepository,让我们具备了JpaRepository所提供的方法;继承了JpaSpecificationExecutor,让我们具备使用Specification的能力。 * @param <T> * @param <ID> */@NoRepositoryBeanpublic interface CustomRepository<T, ID extends Serializable>extends JpaRepository<T, ID> ,JpaSpecificationExecutor<T>{ Page<T> findByAuto(T example,Pageable pageable);}
4.定义实现:
/** * 此类继承JpaRepository的实现类SimpleJpaRepository,让我们可以使用SimpleJpaRepository的方法;此类当然还要实现我们自定义的接口CustomRepository。findByAuto方法使用byAuto Specification构造的条件查询,并提供分页功能。 * @param <T> * @param <ID> */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; } @Override public Page<T> findByAuto(T example, Pageable pageable) { return findAll(CustomerSpecs.byAuto(entityManager, example),pageable); }}
5.定义RepositoryFactoryBean:
/** * 只需让实体类Repository继承我们自定义的Repository接口,即可使用我们在自定义Respository中实现的功能。 * @param <T> * @param <S> * @param <ID> */public class CustomRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> { public CustomRepositoryFactoryBean(Class<? extends T> repositoryInterface) { super(repositoryInterface); } @Override protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { return new CustomRepositoryFactory(entityManager); } private static class CustomRepositoryFactory extends JpaRepositoryFactory { public CustomRepositoryFactory(EntityManager entityManager) { super(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; } }}
6.使用:
DemoController中:
/** * 执行auto * @param teacher * @return */ @RequestMapping("/auto") public Page<Teacher> auto(Teacher teacher){ Page<Teacher> pageTeachers = teacherRepository.findByAuto(teacher, new PageRequest(0, 10)); return pageTeachers; }
Springboot启动bean中(添加@EnableJpaRepositories):
@SpringBootApplication@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)public class SpringbootcacheApplication { public static void main(String[] args) { SpringApplication.run(SpringbootcacheApplication.class, args); }}
6.执行效果:
执行/auto
执行/auto?name=徐
执行/auto?address=99
参考资料《JavaEE开发的颠覆者 Spring Boot》
**
新手一枚,欢迎拍砖~ ~ ~
**
- SpringBoot之Data JPA介绍、开发
- SpringBoot Data JPA
- SpringBoot Data JPA 实战
- springboot-data-jpa使用
- springboot【9】数据访问之Spring-data-jpa
- springboot整合spring data jpa
- springboot集成spring-data-jpa
- Spring Data JPA介绍
- spring data jpa 介绍
- Spring data jpa 介绍
- spring data jpa介绍
- Spring Data JPA开发手册——1.介绍
- springboot之web项目开发(spring+jpa+jsp)
- springboot(五):spring data jpa的使用
- springboot整合swagger UI 、spring-data-JPA
- springboot-data-jpa默认数据库连接池
- springBoot+easyui +spring data JPA 实现分页
- SpringBoot(五) :spring data jpa 的使用
- 亚马逊全球开店卖家峰会昨日举行,内附2018亚马逊开店入驻通道
- 史上最牛JAVA思维导图学习笔记
- Fragment对于Listview未满一屏添加脚布局,满屏将View固定在屏幕下方的解决方案
- js实现下载远程文件
- setContentView对应的getContentView
- SpringBoot之Data JPA介绍、开发
- 项目外面显示红叉,但是项目内容没有报错
- 用作业来停止作业
- python中的循环与break和continue的关系和用法
- HikariCP、MySQL Configuration 性能优化
- enclipse 常用快捷键
- Mysql索引的使用和性能优化
- UE4 动画重定向之使用同一套骨骼
- Python3.x 多线程