JPA(Hibernate)+QueryDSL+NamedQuery 笔记

JPA

  • Entity初始化

  1. 从数据库反向生成实体
  2. Entity类注解@Table(name = "pm_user")只保留name,删除schema``catalog
  3. UUID为了方便, 数据库实体统一使用String
  4. 时间类型修改为 LocalDateTime 方便使用
  5. 布尔值,数据库中指定为tinyint(1), 转换为实体修改为boolean
  • 基础查询

Entity为基本, 适用于最简单的单表查询
接口继承

public List<PmUserModel> search(String loginNameParam, String trueNameParam, Pageable pageable) {    
   //JpaRepository<T, K> 基本jpa查询接口,可以直接拼凑查询方法名 T=Entity类型, K=主键类型
   pmUserRepository.getOne(id);
   pmUserRepository.findAll();

   //PagingAndSortingRepository<T, K> 分页排序接口,返回 Page<PmUserEntity>, pageable 为前端传入spring自动构建的pageable类
   pmUserRepository.findByLoginNameContaining(name, pageable);

  // JpaSpecificationExecutor<T> 条件查询接口, 书写太复杂,不建议使用
   pmUserRepository.findAll(new Specification<PmUserEntity>() {
           @Override
           public Predicate toPredicate(Root<PmUserEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
               List<Predicate> list = new ArrayList<Predicate>();
               if (!StringUtils.isEmpty(loginNameParam)) {
                   list.add(criteriaBuilder.like(root.get("loginName"), "%" + loginNameParam + "%"));
               }
               if (!StringUtils.isEmpty(trueNameParam)) {
                   list.add(criteriaBuilder.like(root.get("trueName"), "%" + trueNameParam + "%"));
               }
               Predicate[] p = new Predicate[list.size()];
               return criteriaBuilder.and(list.toArray(p));
           }
       }, pageable);
}

QueryDSL

   <!--query dsl-->
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>${querydsl.version}</version>
            <scope>provided</scope>
        </dependency>
        <!--query dsl end-->

  <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources/java</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

需要先执行 mvn:compile
单表配合JPA

 //QuerydslPredicateExecutor<PmUserEntity> QueryDSL配合JPA查询接口, 比paSpecificationExecutor<T>要简单实用
public List<PmUserModel> search(String loginNameParam, String trueNameParam, Pageable pageable) {
       JPAQueryFactory queryFactory =  new JPAQueryFactory(em);
        BooleanBuilder where = new BooleanBuilder();
        if (loginNameParam != null) {
            where.and(QPmUserEntity.pmUserEntity.loginName.like('%' + loginNameParam + '%'));
        }
        if (trueNameParam != null) {
            where.and(QPmUserEntity.pmUserEntity.trueName.like('%' + trueNameParam + '%'));
        }

    return pmUserRepository.findAll(where, pageable);
}

多表联查

public List<PmUserModel> search(String loginNameParam, String trueNameParam, Pageable pageable) {
  JPAQueryFactory queryFactory =  new JPAQueryFactory(em);
        BooleanBuilder where = new BooleanBuilder();
        if (loginNameParam != null) {
            where.and(QPmUserEntity.pmUserEntity.loginName.like('%' + loginNameParam + '%'));
        }
        if (trueNameParam != null) {
            where.and(QPmUserEntity.pmUserEntity.trueName.like('%' + trueNameParam + '%'));
        }

        List<PmUserModel> userModelList = queryFactory
//                .select(QPmUserEntity.pmUserEntity, QParamSexEntity.paramSexEntity)
                .select(Projections.bean(
                        PmUserModel.class,//返回自定义实体的类型
                        QPmUserEntity.pmUserEntity.id,
                        QPmUserEntity.pmUserEntity.loginName,
                        QParamSexEntity.paramSexEntity.name.as("sexStr")
                        )
                )
                .from(QPmUserEntity.pmUserEntity)
                .leftJoin(QParamSexEntity.paramSexEntity)
                .on(QParamSexEntity.paramSexEntity.id.eq(QPmUserEntity.pmUserEntity.sex))
                .where(where)
                .orderBy(QPmUserEntity.pmUserEntity.loginName.asc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

        return userModelList;
}

NamedQuery

所有@NamedQuery,@NamedNativeQuery, @SqlResultSetMapping只能注解在已有@Entity类上
不能注解在Model上
完整Entity Class

package cn.tiantianquan.springant.entity;

import cn.tiantianquan.springant.model.PmUserModel;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;

import javax.persistence.*;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;

@Entity
@Table(name = "pm_user")
@NamedNativeQueries({
        @NamedNativeQuery(
                name = "PmUserModelNativeQuery",
                query = "select pu.id, true_name, login_name, pwd, sex, create_time, update_time, is_del,ps.name as sex_str from  pm_user pu left join param_sex ps on ps.id = pu.sex",
                resultSetMapping = "PmUserModelMapping"
        )
})
@NamedQueries({
        @NamedQuery(
                name = "PmUserModelQuery",
                query = "select new cn.tiantianquan.springant.model.PmUserModel(pu.trueName,pu.createTime) from PmUserEntity  pu"
        )
})
@SqlResultSetMappings({
        @SqlResultSetMapping(
                name = "PmUserModelMapping",
                classes = {
                        @ConstructorResult(
                                targetClass = cn.tiantianquan.springant.model.PmUserModel.class,
                                columns = {
                                        //ColumnResult name 相对应的是sql中的列名, type 是sql返回的默认type, columns 中ColumnResult的顺序是
                                        //model构造函数中的参数顺序,与列名无关,不会自动映射
                                        @ColumnResult(name = "id", type = String.class),
                                        @ColumnResult(name = "true_name", type = String.class),
                                        @ColumnResult(name = "login_name", type = String.class),
                                        @ColumnResult(name = "pwd", type = String.class),
                                        @ColumnResult(name = "sex", type = Integer.class),
                                        @ColumnResult(name = "create_time", type = Date.class),
                                        @ColumnResult(name = "update_time", type = Date.class),
                                        @ColumnResult(name = "is_del", type = Integer.class),
                                        @ColumnResult(name = "sex_str", type = String.class)
                                }
                        )
                }
        ),

        @SqlResultSetMapping(
                name = "PmUserModelEntityMapping",
                entities = {
                        @EntityResult(
                                entityClass = PmUserEntity.class,
                                fields = {
                                        @FieldResult(name = "id", column="id"),
                                        @FieldResult(name = "trueName", column = "true_name"),
                                        @FieldResult(name = "loginName", column = "login_name"),
                                        @FieldResult(name = "pwd", column ="pwd"),
                                        @FieldResult(name = "sex", column = "sex"),
                                        @FieldResult(name = "createTime", column = "create_time"),
                                        @FieldResult(name = "updateTime", column = "update_time"),
                                        @FieldResult(name = "isDel", column = "is_del")
                                }
                        )
                },
                columns = {
                        @ColumnResult(name = "sexStr", type = String.class)
                }
        )
})
public class PmUserEntity {
    private String id;
    private String trueName;
    private String loginName;
    private String pwd;
    private Integer sex;
    private LocalDateTime createTime;
    private Timestamp updateTime;
    private boolean isDel;

    @Id
    @Column(name = "id", nullable = false, length = 36)
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Basic
    @Column(name = "true_name", nullable = false, length = 200)
    public String getTrueName() {
        return trueName;
    }

    public void setTrueName(String trueName) {
        this.trueName = trueName;
    }

    @Basic
    @Column(name = "login_name", nullable = false, length = 200)
    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    @Basic
    @Column(name = "pwd", nullable = false, length = 200)
    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Basic
    @Column(name = "sex", nullable = true)
    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    @Basic
    @Column(name = "create_time", nullable = false)
    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }

    @Basic
    @Column(name = "update_time", nullable = false)
    public Timestamp getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Timestamp updateTime) {
        this.updateTime = updateTime;
    }

    @Basic
    @Column(name = "is_del", nullable = false)
    public boolean getIsDel() {
        return isDel;
    }

    public void setIsDel(boolean isDel) {
        this.isDel = isDel;
    }
}

完整Model Class

package cn.tiantianquan.springant.model;

import cn.tiantianquan.springant.entity.PmUserEntity;
import lombok.AllArgsConstructor;
import lombok.Data;

import javax.persistence.*;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;

@Data
public class PmUserModel {
    public PmUserModel() {

    }

    public PmUserModel(String id, String trueName, String loginName, String pwd, Integer sex, Date createTime, Date updateTime, Integer isDel, String sexStr) {
        this.id = id;
        this.trueName = trueName;
        this.loginName = loginName;
        this.pwd = pwd;
        this.sex = sex;
        this.createTime = new Timestamp(createTime.getTime()).toLocalDateTime();
        this.updateTime = new Timestamp(updateTime.getTime()).toLocalDateTime();
        this.sexStr = sexStr;

        this.isDel = isDel == 1;
    }

    public PmUserModel(String trueName, LocalDateTime createTime) {
        this.trueName = trueName;
        this.createTime = createTime;
    }

    private String id;
    private String trueName;
    private String loginName;
    private String pwd;
    private Integer sex;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private boolean isDel;

    private String sexStr;

}

  • NamedNativeQueries 原生SQL查询

注解形式 NamedNativeQueries->NamedNativeQuery
最后需要绑定结果映射resultSetMapping

//查询语句
@NamedNativeQueries({
        @NamedNativeQuery(
                name = "PmUserModelNativeQuery",
                query = "select pu.id, true_name, login_name, pwd, sex, create_time, update_time, is_del,ps.name as sex_str from  pm_user pu left join param_sex ps on ps.id = pu.sex",
                resultSetMapping = "PmUserModelMapping"
        )
})
  • 构造器映射:
  1. 适用于装载非Entity类,如Model类
  2. 构造器 ColumnResult name 相对应的是sql中的列名, type 是sql返回的默认type
  3. columns 中ColumnResult的顺序是model构造函数中的参数顺序,与列名无关,不会自动映射
  4. 构造器映射model类中一定要有相应的构造函数
//构造器映射
        @SqlResultSetMapping(
                name = "PmUserModelMapping",
                classes = {
                        //构造器映射,适用于装载非Entity类,如Model类
                        @ConstructorResult(
                                targetClass = cn.tiantianquan.springant.model.PmUserModel.class,
                                columns = {
                                        //ColumnResult name 相对应的是sql中的列名, type 是sql返回的默认type, columns 中ColumnResult的顺序是
                                        //model构造函数中的参数顺序,与列名无关,不会自动映射
                                        @ColumnResult(name = "id", type = String.class),
                                        @ColumnResult(name = "true_name", type = String.class),
                                        @ColumnResult(name = "login_name", type = String.class),
                                        @ColumnResult(name = "pwd", type = String.class),
                                        @ColumnResult(name = "sex", type = Integer.class),
                                        @ColumnResult(name = "create_time", type = Date.class),
                                        @ColumnResult(name = "update_time", type = Date.class),
                                        @ColumnResult(name = "is_del", type = Integer.class),
                                        @ColumnResult(name = "sex_str", type = String.class)
                                }
                        )
                }
        )
  • 实体映射:
  1. 适用于装载Entity类
    1.@FieldResult 中 name 对应属性名, column 对应列名
  2. 最后的 columns 参数, 指的是与实体或模型都无关的字段, 整个返回对象为 List<Object[]>
    需要自己手动取出相应内容,具体代码见 (代码中拼接sql 并指定setmap的执行方式) (构造器也适用)
//实体映射
 @SqlResultSetMapping(
                name = "PmUserModelEntityMapping",
                entities = {
                        @EntityResult(
                                entityClass = PmUserEntity.class,
                                fields = {
                                        @FieldResult(name = "id", column="id"),
                                        @FieldResult(name = "trueName", column = "true_name"),
                                        @FieldResult(name = "loginName", column = "login_name"),
                                        @FieldResult(name = "pwd", column ="pwd"),
                                        @FieldResult(name = "sex", column = "sex"),
                                        @FieldResult(name = "createTime", column = "create_time"),
                                        @FieldResult(name = "updateTime", column = "update_time"),
                                        @FieldResult(name = "isDel", column = "is_del")
                                }
                        )
                },
                columns = {
                        @ColumnResult(name = "sexStr", type = String.class)
                }
        )
  • 执行

一般执行

        Query q = em.createNamedQuery("PmUserModelNativeQuery");
        return q.getResultList();

在代码中拼接sql 并指定setmap的执行方式

 Query q = em.createNativeQuery("select pu.id, true_name, login_name, pwd, sex, create_time, update_time, is_del,ps.name as sexStr from  pm_user pu left join param_sex ps on ps.id = pu.sex", "PmUserModelEntityMapping");
        List<Object[]> resultList = q.setFirstResult(1).setMaxResults(2).getResultList();
        List<PmUserModel> pmUserModelList = resultList.stream().map(i -> {
            PmUserEntity entity = (PmUserEntity) i[0];
            PmUserModel model = new PmUserModel();
            model.setCreateTime(entity.getCreateTime());
            model.setId(entity.getId());
            model.setSexStr((String) i[1]);
            return model;
        }).collect(Collectors.toList());
        return pmUserModelList ;

createNamedQuery 可追加 setFirstResult起始数据行,setMaxResults最大数据数,来进行分页

JPQL HQL

注意构造器生成时, 一定要把包名写全


        @NamedQuery(
                name = "PmUserModelQuery",
                query = "select new cn.tiantianquan.springant.model.PmUserModel(pu.trueName,pu.createTime) from PmUserEntity  pu"

        )

总结

SQL复杂度从低到高
基础查询 < QueryDSL JPA < HQL = QueryDSL < NamedQueries < NamedNativeQueries
根据复杂度选择相应的查询方式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,440评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,814评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,427评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,710评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,625评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,511评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,162评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,311评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,262评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,278评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,989评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,583评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,664评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,904评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,274评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,856评论 2 339

推荐阅读更多精彩内容