SpringBoot + Jpa practical tutorial
Introduction to JPA
JPA (Java Persistence API), Object Relational Mapping (ORM) framework specification, is a Java persistence specification. jpa can generate database tables through entity classes. At the same time, it comes with many methods for adding, deleting, modifying and checking. Most of the sql statements do not need to be written by ourselves. After the configuration is completed, you can directly call the method, which is very convenient.
Simple JPA usage example
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 configuration
# 数据库连接配置
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. Create an entity class object for mapping database tables
@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 = 50)
@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 = 1L;
}
4. Create a persistent interface DAO, 继承JpaRepository
which is used to operate on the database
@Repository
public interface DictionaryDao extends JpaRepository<DbDictionary, String> {
}
5. So far, the basic configuration of JPA has been completed. There are many built-in methods for adding, deleting, modifying and checking. We don’t need to write sql statements ourselves, just call them directly.
Relevant annotations in JPA entity classes
@Entity
: Indicates that it is an entity class@Table(name = "dict_info")
: The corresponding data table name, used together with the @Entity annotation, but if the table name is the same as the entity class name, @Table can be omitted@GenericGenerator(name = "jpa-uuid", strategy = "uuid")
: Custom hibernate primary key generation strategy@Id
: Indicates that the current field is the primary key@GeneratedValue(generator = "jpa-uuid")
: Specify the primary key generation strategy as uuid@Column(name = "DICTNAME")
: When the attribute of the entity class has a different name from the column of the database table it maps to, you need to use the @Column annotation@CreatedDate
: creation time@LastModifiedDate
: update time@Temporal(TemporalType.TIMESTAMP)
: The entity class will be encapsulated into the Date type of the complete time "yyyy-MM-dd hh:MM:ss"@Transient
: Indicates that this attribute is not a mapping to a field in a database table, and the ORM framework will ignore this attribute
JPA Persistence Layer Keyword Description
The usage mode of JPA Data has helped me integrate some daily keyword usage, which can be used directly through query!
keywords | method naming | sql where clause |
---|---|---|
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 (?) |
swimming | findByIdNotIn(Collection<?> c) | where id not in (?) |
True | findByAaaTue | where aaa = true |
False | findByAaaFalse | where aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
Actual combat: JPA enterprise development example
1. Entities inherit basic common properties
/**
* 实体继承映射类基础 ,保存实体的通用属性
*
* @date: 2022-05-29
* @author: Buckletime
*/
@Data
@Accessors(chain = true)
@MappedSuperclass //实体继承映射
public abstract class BaseEntity implements Serializable {
/**
* 创建者
*/
@Basic
@Column(length = 50)
private String creator;
/**
* 修改者
*/
@Basic
@Column(length = 50)
private String modifier;
/**
* 创建时间
*/
@Basic
@Column(name = "create_time")
@CreatedDate
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@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+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
2. Query
2.1 Condition query
There are two ways to query conditions, one is to directly use the keywords provided by the persistence layer, and the other is to write the query SQL yourself.
// 根据名称和性别查询用户
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 Query sorting
List<T> findAll(Sort sort);
//按创建时间倒序排列
Sort.by("createTime").descending()
2.3 Pagination query
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 Dynamic condition query
For dynamic condition query Specification
, DAO needs to inherit JpaSpecificationExecuto
the r interface
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 Multi-table joint query
@Query(nativeQuery = true, value = "SELECT satellite, count(id), COALESCE(sum(file_size), 0) 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 Return custom 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. Modification and deletion
When modifying and deleting, you need to add @Modifying
and @Transactional
comment.
@Query(nativeQuery = true, value = "UPDATE db_order_info SET download_count = (SELECT download_count + 1) WHERE id = :orderId ")
@Modifying
@Transactional
int updateDownloadTimes(String orderId);
@Modifying
@Transactional
void deleteByName(String name);
Step on the pit
1. The delete method must be annotated with @Transactional and @Modifying
2. When customizing the delete method, if the basic type or package type is passed, void deleteByxxx(String s) must be used instead of void deleteAllByxxx(String s).
Because deleteAllByxxx(String s) will be recognized as a query statement by jpa, only use deleteAllByxxx(List<String> s) when the incoming parameter is a list
It is recommended to use native SQL. The built-in delete or deleteAll will query first, and then perform deletions on the query results one by one. It is not a single SQL that deletes the operation, so it is recommended to write delete by yourself