SpringDataJpa快速上手
公司最近的新项目使用的是JPA,迫于之前没有使用过,因此作成一个快速上手手顺
介绍
JPA 又叫 Spring Data JPA,是spring组件的一部分,相比 mybatis 来说,可以认为是一个全自动 ORM 框架
快速开始
创建一个springboot工程,引入web,mysql driver,jpa,lombok,test等依赖
pom如下:
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
</dependencies>
创建表的实体类:
package fun.psgame.jpa.demo.doman;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Getter
@Setter
@Entity
@Table(name = "tb_user")
public class User {
@Id
private Long id;
@Column(name = "username")
private String username;
@Column(name = "address")
private String address;
}
创建 Repository 类:
package fun.psgame.jpa.demo.dao;
import fun.psgame.jpa.demo.doman.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}
创建controller进行测试:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserRepository userRepository;
@RequestMapping("/test")
public Object test() {
return this.userRepository.findAll();
}
}
接着就可以使用 Repository 了。
进阶
查询
普通查询
根据方法名规则查询
关键词 | 描述 |
---|---|
find..By read..By get..By query..By search..By stream..By | 返回domain类型、集合类型、Streamable子类型或Optional类型 |
exists..By | 是否存在,返回boolean类型 |
count..By | 查询数量 |
delete..By remove..By | 无返回或者返回删除数量 |
..First<number> ..Top<number>.. | 限制数量 |
..Distinct.. | 结果去重 |
谓语修饰词有Distinct
`AndOr
Is/EqualBetween
(Greater)LessThan(Equal)After
BeforeIsNull/Null
IsNotNull/NotNullStartingWith
EndingWithContaining
OrderByNot
InNotIn
True`IngoreCase
添加方法是会有提示,如果IDEA没有提示请安装JPA Buddy
插件
@Query查询
也可以添加自定义方法可以使用@Query
来写sql,sql中可以用两种方式访问传过来的参数一种是?1
`?2这种通过参数序号来访问的。另一种是通过具名参数,需要在参数上添加
@Param("username"),然后通过
:username`的方式使用。
查询时可以不写前面的select *
,表名可以直接写类名
动态查询
Example方式
该方式只支持查询,并且只支持字符串参数,不能用Date之类的参数
(相比mybatis-plus差太多了)
Repository 继承QueryByExampleExecutor<T>
就有Example为参数的方法了
例子:
User user = new User();
user.setId(2L);
user.setUsername("柳岩");
user.setAddress("山东省青岛市");
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnorePaths("id")
.withMatcher("address", ExampleMatcher.GenericPropertyMatchers.endsWith())
.withMatcher("address", m -> m.endsWith())
.withStringMatcher(ExampleMatcher.StringMatcher.ENDING);
// 也可不使用matcher
Example<User> example = Example.of(user, matcher);
List<User> all = this.userRepository.findAll(example);
难用得一批,不推荐
Specification方式
Repository 继承JpaSpecificationExecutor<T>
例子:
Specification<User> specification = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// root 用来获取各个字段
// criteriaBuilder 相当于where 用来添加各种条件
// query 又来组合order by、where
// 条件集合
List<Predicate> list = new ArrayList<>();
// 1
Path<Object> idPath = root.get("id");
Expression<Long> idExpression = idPath.as(Long.class);
Predicate predicate = criteriaBuilder.greaterThan(idExpression, 1L);
//2
Predicate predicate1 = criteriaBuilder.like(root.get("username").as(String.class), "%柳岩%");
list.add(predicate);
list.add(predicate1);
Predicate and = criteriaBuilder.and(list.toArray(new Predicate[0]));
Order order = criteriaBuilder.desc(idExpression);
// 条件 1 和 2
return query.where(and).orderBy(order).getRestriction();
}
};
List<User> userList = this.userRepository.findAll(specification);
这种方式还行,但是很难支持分组和聚合函数
ps:还可以使用entityManager方式获取lambda的三个参数:
手动使用jpa
首先注入:
@Autowired
private EntityManager entityManager;
然后:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Object> query = cb.createQuery();
Root<User> root = query.from(User.class);
这样也获取到三个参数了。
QueryDSL
需要引入额外的依赖,并且需要生成QUser类进行查询
多表查询
多表需要配置关联关系
使用@OneToOne
`@OneToMany@ManyToMany
@JoinColum`等注解配置关系
TODO
项目不用JPA了,暂时放置。
个人感觉JPA在多表关联方面有些弱,特别是写统计相关的sql时,不太好处理,更别说有时候是动态表名,比如按年份分表之后不太好处理,要么写 Hibernate 的插件,动态修改表(参考此文),要么引入sharding jdbc 进行处理。