目录
- JPA 介绍
- JPA 简单使用示例
- JPA 实体类中相关注解说明
- JPA 持久层关键字说明
- 实战-JPA企业开发示例
- 1. 实体继承基础通用属性
- 2. 查询
- 2.1 条件查询
- 2.2 查询排序
- 2.3 分页查询
- 2.4 动态条件查询
- 2.5 多表联查
- 2.6 返回自定义Vo
- 3. 修改和删除
- 踩坑
JPA 介绍
JPA(Java Persistence API),对象关系映射(ORM)框架规范,是一种Java持久化规范。jpa可以通过实体类生成数据库的表,同时自带很多增删改查方法,大部分sql语句不需要我们自己写,配置完成后直接调用方法即可,很方便。
JPA 简单使用示例
1. pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data JPA 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql驱动 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2. application.properties配置
# 数据库连接配置
spring.datasource.url = jdbc:mysql://localhost:3306/manageserver?serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
# jpa配置
# 自动更新数据库表
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
# 是否在控制台显示Hibernate的sql
spring.jpa.show-sql = false
3. 创建实体类对象,用于映射数据库表
@Table(name="db_dictionary")
@Data
@Entity
public class DbDictionary implements Serializable {
@Id
@GenericGenerator(name = "faceset_generator", strategy = "uuid")
@GeneratedValue(generator = "faceset_generator")
@Column
private String id;
/**
* 类型名称
*/
@Size(max =)
@Column
@NotNull
private String type;
/**
* 中文
*/
@Column
@NotNull
private String name;
/**
* 代码
*/
@Column
@NotNull
private String code;
/**
* 顺序
*/
private Integer sort;
/**
* 描述信息
*/
@Column
private String remark;
private static final long serialVersionUID =L;
}
4. 创建持久化接口DAO,继承JpaRepository,用于对数据库进行操作
@Repository
public interface DictionaryDao extends JpaRepository<DbDictionary, String> {
}
5. 至此,JPA基本配置已经完成,这里自带很多内置的增删改查方法,不用我们自己写sql语句,直接调用即可。
JPA 实体类中相关注解说明
- @Entity:表明是一个实体类
- @Table(name = "dict_info"):对应的数据表名,与@Entity注解一块使用,但是如果表名和实体类名相同的话,@Table可以省略
- @GenericGenerator(name = "jpa-uuid", strategy = "uuid"):自定义hibernate主键生成策略
- @Id:表示当前字段为主键
- @GeneratedValue(generator = "jpa-uuid"):指定主键生成策略为uuid
- @Column(name = "DICTNAME"):当实体类的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明
- @CreatedDate:创建时间
- @LastModifiedDate:更新时间
- @Temporal(TemporalType.TIMESTAMP):实体类会封装成完整的时间“yyyy-MM-dd hh:MM:ss”的 Date类型
- @Transient:表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性
JPA 持久层关键字说明
JPA Data的使用模式已经帮我集成了日常一些关键字用法,通过查询可以直接使用!
关键字 | 方法命名 | 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(?) |
实战-JPA企业开发示例
1. 实体继承基础通用属性
/**
* 实体继承映射类基础 ,保存实体的通用属性
*/
@Data
@Accessors(chain = true)
@MappedSuperclass //实体继承映射
public abstract class BaseEntity implements Serializable {
/**
* 创建者
*/
@Basic
@Column(length =)
private String creator;
/**
* 修改者
*/
@Basic
@Column(length =)
private String modifier;
/**
* 创建时间
*/
@Basic
@Column(name = "create_time")
@CreatedDate
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 修改时间
*/
@Basic
@Column(name = "update_time")
@LastModifiedDate
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
2. 查询
2.1 条件查询
条件查询有两种方式,一是直接使用持久层提供的关键字,二是自己写查询SQL。
// 根据名称和性别查询用户
User findByNameAndSex(String name, String sex);
@Query(nativeQuery = true, value = "select * from user where name = :name and sex = :sex")
User findByNameAndSex(@Param("name") String name, @Param("sex") String sex);
2.2 查询排序
List<T> findAll(Sort sort);
//按创建时间倒序排列
Sort.by("createTime").descending()
2.3 分页查询
Page<T> findAll(Pageable pageable);
/*获取分页参数*/
public PageRequest getPageRequest() {
return getPageRequest(Sort.unsorted());
}
/*获取分页和排序参数*/
public PageRequest getPageRequest(Sort sort) {
ServletRequestAttributes attributes = getServletRequestAttributes();
if (StringUtils.hasText(attributes.getRequest().getParameter("page")) && StringUtils.hasText(attributes.getRequest().getParameter("size"))) {
int page = Integer.parseInt(attributes.getRequest().getParameter("page"));
int size = Integer.parseInt(attributes.getRequest().getParameter("size"));
return PageRequest.of(page, size, sort);
}
return PageRequest.of(Constants.zero, Constants.ten);
}
2.4 动态条件查询
动态条件查询Specification,DAO需要再继承JpaSpecificationExecutor接口
List<T> findAll(@Nullable Specification<T> spec);
Specification<ProjectionInfo> spec = (Specification<ProjectionInfo>) (root, query, cb) -> {
List<Predicate> predicateList = new ArrayList<>();
// 时间
if (null != startTime && null != endTime) {
predicateList.add(cb.between(root.get("createTime"), startTime, endTime));
}
// 数字
if (searchDto.getCloud() != null) {
predicateList.add(cb.le(root.<Integer>get("cloudPercent"), searchDto.getCloud()));
}
// 字符串
if (searchDto.getName() != null) {
predicateList.add(cb.equal(root.get("name"), searchDto.getName()));
}
// 列表
if (StrUtil.isNotEmpty(searchDto.getSatellite())) {
String[] satellites = searchDto.getSatellite().split(",");
Expression<String> exp = root.<String>get("satellite");
predicateList.add(exp.in(Arrays.asList(satellites)));
}
Predicate[] pre = new Predicate[predicateList.size()];
pre = predicateList.toArray(pre);
return query.where(pre).getRestriction();
};
2.5 多表联查
@Query(nativeQuery = true, value = "SELECT satellite, count(id), COALESCE(sum(file_size),) FROM t_mas_orbit_info" +
" WHERE create_time BETWEEN :startTime AND :endTime " +
" GROUP BY satellite")
List<Object[]> satelliteDataIncreased(@Param("startTime") Date startTime,
@Param("endTime") Date endTime);
2.6 返回自定义Vo
@Query(value = "SELECT new cn.piesat.dispatch.model.vo.FileDataVO(p.id, p.fileName,p.stationCode,p.fileSize, p.fileDate, p.createTime, p.state, p.filePath,p.forwardTime) " +
" FROM DbZxjProductInfoDTO p ")
List<FileDataVO> getFileList();
3. 修改和删除
进行修改和删除时,需要添加@Modifying、@Transactional注解。
@Query(nativeQuery = true, value = "UPDATE db_order_info SET download_count = (SELECT download_count +) WHERE id = :orderId ")
@Modifying
@Transactional
int updateDownloadTimes(String orderId);
@Modifying
@Transactional
void deleteByName(String name);
踩坑
1.删除的方法上一定要加@Transactional和@Modifying注解
2.自定义删除方法的时候如果传的是基本类型或者包装类型一定要用 void deleteByxxx(String s) 而不是 void deleteAllByxxx(String s)。
因为deleteAllByxxx(String s)会被jpa识别为查询语句,只有传入参数是列表时才是用deleteAllByxxx(List<String> s)
推荐使用原生sql,自带的delete或者deleteAll会先进行查询,然后在查询结果上面挨个执行删除,并不是一条sql执行完删除操作,所以还是建议自己写delete