SpringDataJpa入门案例及查询详细解析(深度好文)

转载 小中配奇 2019/9/8 21:45:25

让我们解脱了层的操作,基本上所有都可以依赖于它来实现,在实际的工作工程中,推荐使用(如:)完成操作,这样在切换不同的框架时提供了极大的方便,同时也使数据库层操作更加简

?SpringDataJpaSpring Data JPA

让我们解脱了DA0层的操作,基本上所有CRUD都可以依赖于它来实现,在实际的工作工程中,推荐使用Spring Data JPA+ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦。

?

把JPA规范的代码封装起来,真正进行查询的还是hibernate或mybatis? >>(封装了jdbc操作),然后进行查询或操作数据库。

?SpringDataJpa入门操作(搭建环境)

创建工程,导入坐标

??1?

????4.0.0

????cn.itcast
????jpa-day02
????1.0-SNAPSHOT

????
????????5.0.2.RELEASE
????????5.0.7.Final
????????1.6.6
????????1.2.12
????????0.9.1.2
????????5.1.6
????

????
????????
????????
????????????junit
????????????junit
????????????4.9
????????????test
????????
????????
????????
????????????org.aspectj
????????????aspectjweaver
????????????1.6.8
????????
????????
????????????org.springframework
????????????spring-aop
????????????${spring.version}
????????
????????
????????????org.springframework
????????????spring-context
????????????${spring.version}
????????
????????
????????????org.springframework
????????????spring-context-support
????????????${spring.version}
????????
????????
????????
????????????org.springframework
????????????spring-orm
????????????${spring.version}
????????
????????
????????????org.springframework
????????????spring-beans
????????????${spring.version}
????????
????????
????????????org.springframework
????????????spring-core
????????????${spring.version}
????????

????????

????????
????????
????????????org.hibernate
????????????hibernate-core
????????????${hibernate.version}
????????
????????
????????????org.hibernate
????????????hibernate-entitymanager
????????????${hibernate.version}
????????
????????
????????????org.hibernate
????????????hibernate-validator
????????????5.2.1.Final
????????

????????

????????
????????
????????????c3p0
????????????c3p0
????????????0.9.1.2
????????

????????
????????
????????????log4j
????????????log4j
????????????1.2.17
????????
????????
????????????org.slf4j
????????????slf4j-api
????????????1.7.25
????????
????????
????????????org.slf4j
????????????slf4j-log4j12
????????????1.6.6
????????
????????

????????
????????????mysq1
????????????mysql-connector-java
????????????5.1.6
????????
????????
????????
????????????org.springframework.data
????????????spring-data-jpa
????????????1.9.0.RELEASE
????????
????????
????????????org.springframework
????????????spring-test
????????????4.2.4.RELEASE
????????

????????
????????
????????????javax.el
????????????javax.el-api
????????????2.2.4
????????
????????
????????????org.glassfish.web
????????????javax.el
????????????2.2.4
????????
????????
????????????org.projectlombok
????????????lombok
????????????1.16.22
????????
????
项目所需的依赖坐标

?配置Spring的配置文件

?1?
???????(权限定位类名)
?????????????(依赖注入)
???????????(配置的扫描的包,实体类所在的包)
??????????(JPA的实现厂家)
????????????
????????

????????
????????
????????????
????????????????
????????????????
????????????????
????????????????
????????????????
????????????????
????????????????
????????????????
????????????
????????

????????
????????
????????????
????????
????
????
????
????????
????????
????????
????????
????
(以下的不需要特别记忆)>>>
????
????
????
????
????????
????
????
????
????

?编写符合SpringDataJpa规范的dao层接口

?1?package?cn.itcast.dao;

import?cn.itcast.domain.Customer;

import?org.springframework.data.jpa.repository.JpaRepository;
import?org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
?*?符合springDataJpa的dao层接口规范
?*?JpaRepository<操作的实体类类型,实体类中主键属性的类型)?>>>封装了基本的CRUD操作
?*?JpaSpecificationExecutor<操作的实体类类型>???>>>封装了复杂查询()
?*/
public?interface?CustomerDao?extends?JpaRepository,?JpaSpecificationExecutor?{}

?

完成客户的增删改查操作

根据id查询

  • findOne

    em.find() 立即加载

  • getOne

    @Transactional:保证getOne正常运行

    em.getReference() 延迟加载? >>返回的是一个客户的动态代理对象,什么时候用、什么时候查询

1?@Test
????public?void?testFindOne()?{
????????Customer?customer?=?customerDao.findOne(3l);
????????System.out.println(customer);
????}

?

保存和更新(sava

  • ?如果没有id主键属性:>> 保存

1?@Test
????public?void?testSave()?{
????????Customer?customer?=?new?Customer();
????????customer.setCustname("黑马程序员");
????????customer.setCustaddress("北京");
????????customer.setCustindustry("IT教育");
????????customerDao.save(customer);
????}
  • ?存在id主键属性:? >> 根据id查询数据,更新数据

1?@Test
????public?void?testUpdate()?{
????????Customer?customer?=?new?Customer();
????????customer.setCustid(1l);
????????customer.setCustname("播客");
????????customer.setCustindustry("黑马程序员很厉害");
????????customerDao.save(customer);
????}

?

根据id删除(delete)

1?@Test
????public?void?testDelete()?{
????????Customer?customer?=?new?Customer();
????????customerDao.delete(1l);
????}

?

查询所有客户(findAll)

1?@Test
????public?void?findAll(){
????????List?list?=?customerDao.findAll();
????????for?(Customer?customer?:?list)?{
????????????System.out.println(customer);
????????}

?

SpringDataJpa的运行过程和原理剖析

  1. 通过JdkDynamicAopProxy的 invoke 方法创建了一个动态代理对象
  2. simpleJpaRepository当中封装了 JPA的操作(借助JPA的api完成数据库的CRUD)
  3. 通过 hibernate完成数据库操作(封装了jdbc)

?复杂查询

  • 借助接口中的定义好的方法完成查询

    findone(id):根据id查询

测试统计查询:查询客户的总数量

1?@Test
????public?void?testdount()?{
????????long?count?=?customerDao.count();//查询全部的客户数量System.out.println(count);
????????System.out.println(count);
????}

测试:判断id为3的客户是否存在

  • 可以查询以下id为3的客户

    如果值为空,代表不存在,如果不为空,代表存在

  • 判断数据库中id为3的客户的数量

    如果数量为0,代表不存在(false),如果大于0,代表存在(true)

1?@Test
????public?void?testExists()?{
????????boolean?exists?=?customerDao.exists(3l);
????????System.out.println(exists);
????}

?

?

?

?

  • jpql的查询方式??

    jpql:jpa query language( jpq查询语言 )

    特点:语法或关键字和sql语句类似
    查询的是类和类中的属性

  需要将JPQL语句配置到接口方法上

    1 .特有的查询:需要在dao接口上配置方法

    2. 在新添加的方法上,使用注解的形式配置jpql查询语句
    3. 注解:@Query

案例:根据客户名称查询名称 >> 使用Jpql的形式查询

CustomerDao

?

1?public?interface?CustomerDao?extends?JpaRepository,?JpaSpecificationExecutor?{
????/**
?????*?案例:根据客户名称查询名称
?????*??????使用Jpql的形式查询
?????*??????jpql:?from?Customer?where?custName?=??
?????*/
????@Query(value?=?"from?Customer?where?custname?=??")
????public?Customer?findJpql(String?custname);
}

?

?

?

?JpqlTest

1?@Test
????public?void?testFindJpql(){
????????Customer?customer?=?customerDao.findJpql("传智");
????????System.out.println(customer);
????}

?

案例:根据客户名称和客户id查询客户 >> 使用Jpql的形式查询

  • 对于多个占位符参数:?赋值的时候,默认的情况下,占位符的位置需要和方法参数中的位置保持一致? ?[? custName >>?String name? ? ? ? ? ??custId >>?Long id? ]

?

    @Query(value="from Customer where custName=? and custId=?")
    public Customer findCustNameAndId (String name , Long id );

  • 也可以指定占位符参数的位置 :? ??索引的方式,指定此占位的取值来源

    @Query (value=" from Customer where custName = ?2 and custId = ?1 ")

    public Customer findCustNameAndId ( Long id , String name );

CustomerDao

1?@Query(value?=?"from?Customer?where?custname?=???and?custid?=??")
????public?Customer?findCustNameAndId(String?custname,?long?id);

?JpqlTest  ?

1?@Test
????public?void?testCustNameAndId(){
????????Customer?customer?=?customerDao.findCustNameAndId("黑马",2l);
????????System.out.println(customer);
????}

使用jpql完成更新操作案例:根据id更新更新2号客户的名称,将名称改为“黑马程序员”

CustomerDao

1?@Query(value?=?"?update?Customer?set?custname?=??2?where?custid?=??1?")?//代表的是进行查询
????@Modifying?//当前执行的是一个更新操作
????//更新不需要返回值?选择void
????public?void?UpdateCustomer(?long?custid,String?custname);

?JpqlTest  

1?@Test
????@Transactional?//添加对事务的支持
????@Rollback(value?=?false)?//设置是否自动回滚
????public?void?testUpdateCustomer(){
????????customerDao.UpdateCustomer(2l,"黑马程序员");
????}

执行结束后,默认回滚事务,可以通过@Rollback 设置是否自动回滚? >>? false? |? true

?

  • SQL查询方式.

    1 .特有的查询:需要在dao接口上配置方法

    2. 在新添加的方法上,使用注解的形式配置sql查询语句
    3. 注解:@Query

      value: jsql? ?|? sql

      nativeQuery : fals(使用jpql查询) l? ?true(使用本地查询:sql查询)

CustomerDao

1?@Query(value?=?"select?*?from?cst_customer",nativeQuery?=?true)
????public?ListfindSql();

?JpqlTest 

1?@Test
????public?void?testfindSql(){
????????List?list?=?customerDao.findSql();
????????for?(Object[]?obj?:?list)?{
????????????System.out.println(Arrays.toString(obj));//每一个里面都还是object数组,所以需要借助Arrays.toString()方法打印数组
????????}
  • 方法命名规则查询?? ? ?

?

>>?1: findBy +属性名(首字母大写)

?

?

public?Customer?findByCustname(String?custname);

?

?

?

1?@Test
????public?void?testNaming(){
????????Customer?customer?=?customerDao.findByCustname("传智");
????????System.out.println(customer);
????}

?

?>> 2:?findBy + 属性名(首字母大写)+ “查询方式”

public?List?findByCustnameLike(String?custname);
1?@Test
????public?void?testfindByCustnameLike(){
????????List?list?=?customerDao.findByCustnameLike("黑马%");
????????for?(Customer?customer?:?list)?{
????????????System.out.println(customer);
????????}?}

?

>> 3:?findBy + 属性名(首字母大写)+?“查询方式”?+? “多条件的连接符(and | or)” + 属性名 + “查询方式”

    使用客户名称模糊匹配和客户所属行业精准匹配的查询

public?List?findByCustnameLikeAndCustindustry(String?custname,?String?custindustry);?//结果可能是一个或多个,所以选择List

?

1?@Test
????public?void?testFindByCustnameLikeAndCustindustry(){
????????List?list?=?customerDao.findByCustnameLikeAndCustindustry("黑马%","it教育");
????????for?(Customer?customer?:?list)?{
????????????System.out.println(customer);
????????}?}

?

?

Specifications动态查询

  • root :查询的根对象(查询的任何属性都可以从根对象中获取)

  • cirteriaQuery:顶层查询对象,自定义查询方式(了解,一般不用)

  • cirteriaBuilder:查询的构造器,封装了很多查询条件

  public Predicate toPredicate(Root?root?, CriteriaQuery?query?, CriteriaBuilder?cb) { }? //封装查询条件

?

查询客户名为 “传智” 的客户

?1?@Test
????public?void?testSpec()?{
       实现Specification接口(?提供泛型?:查询的对象属性)
????????Specification?spec?=?new?Specification()?{
       实现toPredicate方法(构造查询条件)
????????????public?Predicate?toPredicate(Root?root,?CriteriaQuery?query,?CriteriaBuilder?cb)?{
????????????????//1.获取比较的属性
????????????????Path?custname?=?root.get("custname");
????????????????//2.构造查询条件
????????????????Predicate?predicate?=?cb.equal(custname,?"传智");?//进行精准的匹配(custname:比较的属性?,?“传智”:比较的属性取值)
????????????????return?predicate;
????????????}};
????????Customer?customer?=?customerDao.findOne(spec);
????????System.out.println(customer);
????}

查询客户名为 “黑马2” 并且行业为 "it教育" 的的客户

?1?@Test
????public?void?testSpec1()?{
????????Specification?spec?=?new?Specification()?{
????????????public?Predicate?toPredicate(Root?root,?CriteriaQuery?query,?CriteriaBuilder?cb)?{
????????????????//1.获取比较的属性
????????????????Path?custname?=?root.get("custname");
????????????????Path?custindustry?=?root.get("custindustry");
????????????????//2.构造查询条件
????????????????Predicate?p1?=?cb.equal(custname,?"黑马2");
????????????????Predicate?p2?=?cb.equal(custindustry,?"it教育");
           and(与关系):满足条件1并且满足条件2????or(或关系):满足条件1或满足条件2
????????????????Predicate?and?=?cb.and(p1,?p2);
????????????????return?and;
????????????}
????????};
????????Customer?customer?=?customerDao.findOne(spec);
????????System.out.println(customer);
????}

?

?案例:完成根据客户名称的模糊匹配,返回客户列表? ?>>客户名称以? “传智播客” 开头

  默认: equal:直接得到 path对象(属性),然后进行比较即可

  gt(大于),lt(小于),ge(大于等于),le(小于等于),like:得到path对象,根据path指定比较的参数类型,再去进行比较

  指定参数类型:path.as(类型的字节码对象)

?

?1?@Test
????public?void?testSpec2()?{
????????Specification?spec?=?new?Specification()?{
????????????public?Predicate?toPredicate(Root?root,?CriteriaQuery?query,?CriteriaBuilder?cb)?{
????????????????Path?custname?=?root.get("custname");??//查询属性:客户名
????????????????Predicate?predicate?=?cb.like(custname.as(String.class),?"传智播客%");?//查询方式:模糊匹配
????????????????return?predicate;
????????????}
????????};
????????List?list?=?customerDao.findAll(spec);
????????for?(Customer?customer?:?list)?{
????????????System.out.println(customer);
????????}?}

添加排序? >>创建排序对象,需要调用构造方法实例化sort对象

? 第一个参数:排序的顺序(倒序,正序)

  • Sort.Direction.DESC:倒序

  • Sort.Direction.ASC:升序

? 第二个参数:排序的属性名称

1???Sort?sort?=?new?Sort(Sort.Direction.DESC,?"custid");
??List?list?=?customerDao.findAll(spec,?sort);

?

?

?分页查询

  • 不带参数的分页查询

 创建PageRequest的过程中,需要调用他的构造方法传入两个参数

  第一个参数:当前查询的页数(从e开始)

  第二个参数:每页查询的数量

?

?1?@Test
????public?void?testSpec3()?{
????????Specification?spec?=?null;?//不带参数
????????Pageable?pageable?=?new?PageRequest(0,?2);
????????//分页查询
????????Page?page?=?customerDao.findAll(null,?pageable);
????????System.out.println(page.getContent());//得到数据集合列表
????????System.out.println(page.getTotalElements());//得到总条数
????????System.out.println(page.getTotalPages());//得到总页数
????}

?

  • ?带参数分页查询

?1?@Test
????public?void?testSpec4()?{
????????Specification?spec?=?new?Specification()?{
????????????public?Predicate?toPredicate(Root?root,?CriteriaQuery?criteriaQuery,?CriteriaBuilder?criteriaBuilder)?{
????????????????Path?custname?=?root.get("custname");
????????????????Predicate?predicate?=?criteriaBuilder.equal(custname,?"传智播客");
????????????????return?predicate;
????????????}};
????????Pageable?pageable?=?new?PageRequest(0,?2);
????????//分页查询
????????Page?page?=?customerDao.findAll(spec,?pageable);
????????System.out.println(page.getContent());//得到数据集合列表
????????System.out.println(page.getTotalElements());//得到总条数
????????System.out.println(page.getTotalPages());//得到总页数
????}

?

上一篇:多表操作

下一篇:第一次裸辞

赞(0)

共有 条评论 网友评论

验证码: 看不清楚?
    IT文章导航
    扫一扫关注最新编程为什么上不了bet356_bet356 下载安装_bet356黑钱