前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

用了这么久springboot springdata jpa了,是时候简单总结一下下了

1、CrudRepository与JpaRepository的不同

其实用起来一模一样

1.1、继承关系

PagingAndSortingRepository 继承 CrudRepository,JpaRepository 继承 PagingAndSortingRepository,所以,我们以后一般用JpaRepository

12、使用关系

CrudRepository 提供基本的增删改查;

PagingAndSortingRepository 提供分页和排序方法;

JpaRepository 提供JPA需要的方法。

2、方法集锦

关键字 方法命名 sql where字句
And findByNameAndPwd where name= ? and pwd =?
Or findByNameOrSex where name= ? or sex=?
Is,Equals findById,findByIdEquals where id= ?
Between findByIdBetween where id between ? and ?
LessThan findByIdLessThan where id < ?
LessThanEquals findByIdLessThanEquals where id <= ?
GreaterThan findByIdGreaterThan where id > ?
GreaterThanEquals findByIdGreaterThanEquals where id > = ?
After findByIdAfter where id > ?
Before findByIdBefore where id < ?
IsNull findByNameIsNull where name is null
isNotNull,NotNull findByNameNotNull where name is not null
Like findByNameLike where name like ?
NotLike findByNameNotLike where name not like ?

StartingWith

findByNameStartingWith where name like '?%'
EndingWith findByNameEndingWith where name like '%?'
Containing findByNameContaining where name like '%?%'
OrderBy findByIdOrderByXDesc where id=? order by x desc
Not findByNameNot where name <> ?
In findByIdIn(Collection<?> c) where id in (?)
NotIn findByIdNotIn(Collection<?> c) where id not  in (?)
True

findByAaaTue

where aaa = true
False findByAaaFalse where aaa = false
IgnoreCase findByNameIgnoreCase where UPPER(name)=UPPER(?)

2.1、count

count sql 解释
1 Long countByName(String name); 通过名字查询
2 Long countAllByName(String name); 通过名字查询
3 Long countBy(); 查询库中所有的
4 long count(); 查询库中所有的,注意这里为long

2.1.2、测试


public interface DemoEntityJapCruRepository extends JpaRepository<DemoEntity,Long> {

  
    Long countByName(String name);
    Long countAllByName(String name);
    Long countBy();
    long count();
    
}

2.2、exists 检测数据是否存在

exists sql 解释
1 boolean exists(Long id); 判断id的实体是否存在
3 boolean existsByUserInfoId(Long userInfoId); 判断库里面的匹配项是否存在
    boolean exists(Long id);
    boolean existsByUserInfoId(Long userInfoId);

2.3、返回结果为对象

2.3.1、返回Date类型


    @Query("select d.cdate from  DemoEntity d  where d.id = :id")
    Date findDate(@Param("id") Long id);
    

2.3.2、返回实体对象

下面这种方式不可以使用原生的sql语句,必须使用Hibernate 对象语法。所以尽量使用mybatis


@Query("select  new com.hlj.data.res.RspDemoModel(d.id,d.name,d.age)  from DemoEntity  d where d.id  = :id")
RspDemoModel findDtoModel(@Param("id") Long id) ;

3、getOne和上面的findOne区别

使用中get和上面的find在Jpa方法中没什么区别的,比如:getByNameContaining也就是说可以用下吗的get去替代上面的find

但是如果是getOne和findOne就会有一些问题

findOne()是返回的是一个实体对象,查不到的时候会返回null。 getOne()是返回的一个对象的引用,也是是代理对象,查不到会抛异常。

SpringBoot版本1.5.4


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


3.1、测试Repository

public interface DemoEntityJapRepository extends JpaRepository<DemoEntity,Long> {

}


public interface DemoEntityCruRepository extends CrudRepository<DemoEntity,Long> {
}

3.2、service

接口

    DemoEntity findOrGet (String type , String which , Long id);
实现类



    @Override
    public DemoEntity findOrGet(String type , String which , Long id) {
        DemoEntity  demoEntitie = null ;
        if(StringUtils.equals("jpa", type)){
            if(StringUtils.equals("find",which )){
                demoEntitie = demoEntityJapRepository.findOne(id) ;
            }else if(StringUtils.equals("get",which )){
                demoEntitie = demoEntityJapRepository.getOne(id) ;
            }
        }else if(StringUtils.equals("cru",type )){
            if(StringUtils.equals("find",which )){
                demoEntitie = ( demoEntityCruRepository.findOne(id));
            }else if(StringUtils.equals("get",which )){
                //下面这种不存在的
//                demoEntitie =  demoEntityCruRepository.getOne(id);
            }
        }
        System.out.println(demoEntitie);
        return  demoEntitie ; //jpa getOne(代理对象能够获取结果但是不能传递到前台)

    }


3.3、controller


//http://localhost:8080/demo/jpa/findOrGet?type=jpa&which=get&id=17
@ApiOperation(notes = "所有Demo实体类",
              value = "所有Demo实体类",
              consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
              produces = MediaType.APPLICATION_JSON_VALUE,
              response = DemoEntity.class)
@ApiImplicitParams({
    @ApiImplicitParam(name = "type",value = "jpa cru",required = true,dataType = "string",paramType = "query")
})
@GetMapping("findOrGet")
@ResponseBody
public ResponseBean  findOrGet(String type,String which, Long id){
    try {
        return ResponseBean.buildSuccess(demo02JapMethodService.findOrGet(type,which,id));
    }catch (AppException e){
        ExceptionLogUtils.log(e,this.getClass() );
        return  ResponseBean.buildFailure(e.getCode(),e.getMessage());
    }catch (Exception e){
        ExceptionLogUtils.log(e,this.getClass() );
        return  ResponseBean.buildFailure(e.getMessage());
    }
}


3.3、测试

3.3.1、测试1 getOne查询一个不存在的数据

http://localhost:8080/demo/jpa/findOrGet?type=cru&which=get&id=100


报错信息
报错的文件是EntityManagerFactoryBuilderImpl.java报错方法是handleEntityNotFound报错的行是144报错的信息是Unable to find com.hlj.entity.db.demo.DemoEntity with id 100


3.3.2、findOne:查询一个不存在的id数据时,返回的值是null.

type分别为jpa和cur

http://localhost:8080/demo/jpa/findOrGet?type=cru&which=find&id=100

http://localhost:8080/demo/jpa/findOrGet?type=jpa&which=find&id=100

{
    "success": true,
    "result": null,
    "message": "",
    "code": "200",
    "date": "1547197480777"
}

3.3.3、getOne返回一个存在的数据,也会出现问题


方法中可以使用再包装之后传递给前端会报错错误如下

打印日志DemoEntity(id=17, name=HealerJean, age=2, cdate=2019-01-10 15:15:10.0, udate=2019-01-10 01:15:11.0)


报错信息:
2019-01-11 17:06:47.898 [http-nio-8080-exec-7] ERROR c.h.config.ControllerExceptionConfig - 报错的文件是AbstractJackson2HttpMessageConverter.java报错方法是writeInternal报错的行是299报错的信息是Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.hlj.data.general.ResponseBean["result"]->com.hlj.entity.db.demo.DemoEntity_$$_jvstcc7_0["handler"])



原因: Jason转换失败(直接返回前端会造成),不是没有 implements Serializable 的原因

解决方法: //实体类上忽略下面的字段,在Json传递的时候 @JsonIgnoreProperties(value={“hibernateLazyInitializer”,”handler”,”fieldHandler”})

3.4、总结:

总之以后我们使用的时候,就用findOne,不要使用getOne,查询语句get,find不受影响,随意使用

getOne:查询一个不存在的id数据时,直接抛出异常,因为它返回的是一个引用,简单点说就是一个代理对象。

这样一看想起来hibernate中get和load区别

WX20190111-155653@2x

ContactAuthor