一: 实体类的常用注解
2.1 @Entity 标识这个 pojo 是一个 jpa 实体
2.2 @Table(name = "表名") 指定类对应的数据库表名
2.3 @Id 标记某一字段为表主键
2.4 @GeneratedValue 标记主键生成策略
2.5 @Column 标记为字段,有如下属性
2.5.1 name 对应数据库的字段名,默认为 属性名
2.5.2 unique 是否唯一,默认 false
2.5.3 nullable 是否可以为空 默认为 true
2.5.4 inserttable 是否可以插入,即提交 insert 语句时是否持久化的数据库
2.5.5 updateable 是否可以跟新,即提交 update 语句时是否能修改该字段
2.5.6 length 字段长度
2.5.7 precision 和 scale 多少位数字,保留几位小数
2.5.8 secondaryTable 从表名,该字段不在当前表,可以指定其它从表的名称
2.5.9 columnDefinition 定义建表时创建此列的DDL,使用时,其它属性将失效
2.5.9.1 columnDefinition="TEXT" 设置为文本类型
2.6 @Temporal(TemporalType.DATE) 设置为时间类型
2.6.1 TemporalType.DATE yyyy-mm-dd
2.6.2 TemporalType.TIME hh:mm:ss
2.6.3 TemporalType.TIMESTAMP yyyy-mm-dd hh:mm:ss
2.7 @JoinColumn 外联表字段
2.8.1 name 外键的名称,类似 column 的 name
2.8 @ManyToOne 单向多对一,会在当前类的对应表中生成外键
2.7.1 fetch 抓取策略,( SpringBoot 中 FetchType.LAZY 报错, FetchType.EAGER 无效,还是两条 SQL)
2.7.1.1 FetchType.EAGER 查询时使用左外联,参考 left Join
2.7.1.2 FetchType.LAZY 查询时使用懒加载,即会发送两条 SQL
2.7.2 mapperBy 多方外键的数据库字段名称参照一方的哪一个字段
2.7.3 属性 cascade
2.7.3.1 CascadeType.PERSIST 支持级联保存
2.9 @OneToMany 单向一对多,会在关联类中的对用表生成外键 (少用,性能较低)
2.9.1 必须配置 JoinColumn(name='id'),否则会生成关联表
2.9.2 属性 cascade
2.9.2.1 CascadeType.PERSIST 支持级联保存
2.9.2.2 CascadeType.REMOVE 支持级联删除 即删除 一方同时删除关联的多方
2.10 @OrderBy(" id DESC ") 排序字段,只有在多对一且是,使用 list 时才能使用
二: 持久层 @Repository
1,Repository<T, T> 基础接口, 第一个 T 实体类 第二个T 主键类型 如 <User, Long>
1.1 提供了以方法名为查询条件方法
Keyword | Sample | JPQL snippet |
---|---|---|
And |
findByLastnameAndFirstname |
… where x.lastname = ?1 and x.firstname = ?2 |
Or |
findByLastnameOrFirstname |
… where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals |
findByFirstname,findByFirstnameIs,findByFirstnameEquals |
… where x.firstname = 1? |
Between |
findByStartDateBetween |
… where x.startDate between 1? and ?2 |
LessThan |
findByAgeLessThan |
… where x.age < ?1 |
LessThanEqual |
findByAgeLessThanEqual |
… where x.age <= ?1 |
GreaterThan |
findByAgeGreaterThan |
… where x.age > ?1 |
GreaterThanEqual |
findByAgeGreaterThanEqual |
… where x.age >= ?1 |
After |
findByStartDateAfter |
… where x.startDate > ?1 |
Before |
findByStartDateBefore |
… where x.startDate < ?1 |
IsNull |
findByAgeIsNull |
… where x.age is null |
IsNotNull,NotNull |
findByAge(Is)NotNull |
… where x.age not null |
Like |
findByFirstnameLike |
… where x.firstname like ?1 |
NotLike |
findByFirstnameNotLike |
… where x.firstname not like ?1 |
StartingWith |
findByFirstnameStartingWith |
… where x.firstname like ?1 (parameter bound with appended % ) |
EndingWith |
findByFirstnameEndingWith |
… where x.firstname like ?1 (parameter bound with prepended % ) |
Containing |
findByFirstnameContaining |
… where x.firstname like ?1 (parameter bound wrapped in % ) |
OrderBy |
findByAgeOrderByLastnameDesc |
… where x.age = ?1 order by x.lastname desc |
Not |
findByLastnameNot |
… where x.lastname <> ?1 |
In |
findByAgeIn(Collection<Age> ages) |
… where x.age in ?1 |
NotIn |
findByAgeNotIn(Collection<Age> age) |
… where x.age not in ?1 |
True |
findByActiveTrue() |
… where x.active = true |
False |
findByActiveFalse() |
… where x.active = false |
IgnoreCase |
findByFirstnameIgnoreCase |
… where UPPER(x.firstame) = UPPER(?1) |
简单的列子, 以上的 findBy 也可以改为 getBy 或者 readBy
package com.hwq.jpa.entity; import lombok.Getter; import lombok.Setter; import javax.persistence.*; @Entity @Setter @Getter public class Status { @Id @GeneratedValue @JoinColumn Long id; Long pId; @Column(length = 20) String name; }
package com.hwq.jpa.dao; import com.hwq.jpa.entity.Status; import org.springframework.data.repository.Repository; @org.springframework.stereotype.Repository // 注意两个 Repository 不要冲突 public interface StatusDao extends Repository<Status, Long> { Status getById(Long id); // 根据 id Status 类 }
2, CrudRepository<T, T> 提供了简单的增删改查的方法, 继承自 Repository<T, T>
3, PagingAndSortingRepository<T, T> 提供了分页和排序的方法, 继承自 CrudRepository<T, T>
4,JpaRepository<T, T> 继承自 PagingAndSortingRepository<T, T>
5,JpaSpecificationExecutor<T> 条件查询
简单的例子,依然使用上面的实体类
package com.hwq.jpa.dao; import com.hwq.jpa.entity.Status; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; @Repository public interface StatusDao extends JpaRepository<Status, Long>, JpaSpecificationExecutor<Status> { }
package com.hwq.jpa.controller; import com.hwq.jpa.dao.StatusDao; import com.hwq.jpa.entity.Status; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.*; import org.springframework.data.domain.Sort.Order; import org.springframework.data.jpa.domain.Specification; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.persistence.criteria.*; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @RequestMapping("/status") public class StatusController { @Autowired StatusDao statusDao; @RequestMapping("/insert") public Status insert(Status status) { // 保存或者修改的方法 // 当存在主键时为修改,不存在为保存 return statusDao.save(status); } @RequestMapping("select") public Map<String, Object> select(Integer page, Integer size) { // 实例化 排序类, Sort 可以传入多个 Order // Direction.DESC 降序 // Direction.ASC 升序 // "id" 排序字段 Order order1 = new Order(Direction.DESC, "id"); Sort sort = new Sort(order1); // 实例化分页类 // page 查询的当前页数 // size 查询的每一页的最大记录数 PageRequest pageAble = new PageRequest(page, size, sort); // 调用 findAll 方法 Page<Status> result = statusDao.findAll(pageAble); // 获取需要的数据 Map<String, Object> map = new HashMap<String, Object>(); map.put("rows", result.getTotalElements()); // 获取总记录数 map.put("page", result.getNumber()); // 当前是第几页 map.put("pages", result.getTotalPages()); // 总共多少页 map.put("data", result.getContent()); // 当前页的数据 map.put("size", result.getNumberOfElements()); // 当前页的记录数 return map; } @RequestMapping("/select-if") public Map<String, Object> selectIf(Integer page, Integer size) { Order order1 = new Order(Direction.DESC, "id"); Sort sort = new Sort(order1); PageRequest pageAble = new PageRequest(page, size, sort); Specification<Status> statusSpecification = new Specification<Status>() { @Override public Predicate toPredicate(Root<Status> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Predicate predicate = null; // 最终返回的对象, 由 cb 创建 Path path = root.get("id"); // 定位到实体类的 id predicate = cb.gt(path, 1); // WHERE id > 1 return predicate; } }; // 调用 findAll 方法 Page<Status> result = statusDao.findAll(statusSpecification, pageAble); // 获取需要的数据 Map<String, Object> map = new HashMap<String, Object>(); map.put("rows", result.getTotalElements()); // 获取总记录数 map.put("page", result.getNumber()); // 当前是第几页 map.put("pages", result.getTotalPages()); // 总共多少页 map.put("data", result.getContent()); // 当前页的数据 map.put("size", result.getNumberOfElements()); // 当前页的记录数 return map; } }
6,自定义的 Repository 方法《 注意以下三点 》《 无特殊情况,少用 》
6.1 必须创建一个任意的 接口 XxxDao
6.2 定义的 XxxRepository 继承 XxxDao
6.3 实现 XxxDao 的类名称必须为 XxxRepositoryImpl
6.3.1 实现类中可以使用 EntityManager 完美接入 JPA 的内容
简单的例子, 依然使用最开始的实体类为
package com.hwq.jpa.repository.dao; import com.hwq.jpa.entity.Status; public interface StatusDao { Status selectStatusById(Long id); }
package com.hwq.jpa.repository; import com.hwq.jpa.entity.Status; import com.hwq.jpa.repository.dao.StatusDao; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Repository; @Repository public interface StatusRepository extends JpaRepository<Status, Long>, JpaSpecificationExecutor<Status>, StatusDao { }
package com.hwq.jpa.repository; import com.hwq.jpa.entity.Status; import com.hwq.jpa.repository.dao.StatusDao; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; public class StatusRepositoryImpl implements StatusDao { @PersistenceContext EntityManager entityManager; @Override public Status selectStatusById(Long id) { Status status = entityManager.find(Status.class, id); return status; } }