tips
-
@Service,@Repository,@Entity
-
JpaRepository后的泛型:<对象名,主键类型>
-
@Table、@Id、@Column
-
@JoinColumn中字段是否正确
-
测试时toString是否重写,测试完成后删除
-
Contoller中路径解析(@PathVaeiable)是否加上
-
插入、删除与更新要加上**@Transactional与@Modifying**
-
@Param中为字符串类型
-
@Query中若使用sql查询要写values,若为Jpql记得在语句前后加上“ ”
一、Jpql方式查询
注意:Jpql语句中的字段名为对象中中定义的,不是数据库表中的
1. 查询
//查询全部
//不能使用select *,省略即可
@Query("from user where name = ?")
public User findUser(String name);
//查询部分字段,可以使用select
@Query("select name, sex from user where name = ?")
public User findUser(String name);
2. 更新(需要添加事务)
//更新需要写update字段,并加上@Modifying代表更新操作
@Query("update User set name =?1 where id = ?2")
@Modifying
public void findUser(String name, int id);
3. 删除(需要添加事务)
//更新需要写delete字段,并加上@Modifying代表更新操作
@Query("delete from User set where id = ?1")
@Modifying
public void findUser(int id);
4. Jpql无插入操作
5. 索引参数
多个参数时,可不加但顺序要一致
在占位符号后加上索引,即可随意顺序
@Query("from user where name = ?2 ,sex=?1")
public User findUser(int sex, String name);
6. 命名参数
通过给参数起别名(@Param),sql中使用 ” :+参数名“ 来接收参数
@Query("from user where name = :name ,sex= :sex")
public User findUser(@Param("sex") int sex, @Param("name")String name);
7. 对象参数
通过 “ :#{#对象.属性} ”,即可获取对象中的参数
@Query(value = "insert into user(name,sex,phone)
values(:#{#user.name},:#{#user.sex},:#{#user.phone})", nativeQuery = true)
@Modifying
public void insertUser(@Param("user") User user);
二、Sql方式查询
注意:sql语句中的字段名为数据库中定义的,不是对象中的
1. 使用@Query注解
2. value中写sql语句
3. nativeQuery设置为true
@Query(value = "select * from user where name = ?1",nativeQuery=true)
public User findUser(String name);
4. CRUD
语句均与sql语句相同,但插入删除与更新需要添加事务与**@Modifying注解**
5. 参数传递与Jpql一致
三、动态查询(Specification)
(一)单条件查询
1. dao层继承接口
继承JpaSpecificationExecutor接口并传入类名
public interface UserRepository extends JpaSpecificationExecutor<User>{}
2. service实现接口
匿名内部类实现Specification,重写toPredicate方法
root:需要查询的对象的“属性”名称,不是数据库中的字段名称
cb(criteriaBuilder):构造查询条件的,内部封装了许多查询条件
Specification<User> spec =new Specification<User>() { @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { return null; }};
3.通过root获取对象属性
获取到之后封装成Path对象
Path<Object> name = root.get("name");
4.通过cb构造查询条件
选择想要匹配的条件的方法(equal时)
第一个参数:需要比较的属性(一个path对象)
第二个参数:需要比较的值
Predicate res = cb.equal(name, "张三");
gt、lt、ge、le、like等条件时,要加上类型(".as( )")
第一个参数:需要比较的属性(一个path对象),并指定类型(防止“1”与1弄乱)
第二个参数:需要比较的值
Predicate res = cb.like(name.as(String.class), "张三");
5.返回Predicate对象
return res;
6. 在接口实现外调用findOne/All方法
注意:findOne方法是 JpaSpecificationExecutor 里的,不是 JpaRepository 里的
Optional<User> one = userRep.findOne(spec); System.out.println(one.get());
(二)多条件查询
1. 同单条件
2. 同单条件
3. 通过root获取对象属性
直接使用root获取多个属性,并分别分装成Path对象
Path<Object> name = root.get("name"); Path<Object> sex = root.get("sex");
4. 通过cb构造查询条件
每个Path构造一个
Predicate p1 = cb.equal(name, "张三"); Predicate p2 = cb.equal(sex, "17");
5. 将多个查询条件进行组合
且关系:cb.and(p1, p2) 或关系:cb.or(p1, p2)
6. 同单条件
(三)代码
//单条件Specification<User> spec =new Specification<User>() { @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { Path<Object> name = root.get("name"); Predicate res = cb.equal(name, "张三"); return res; }};//Optional<User> one = userRep.findOne(spec);//多条件Specification<User> doublespec =new Specification<User>() { @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { Path<Object> name = root.get("name"); Path<Object> sex = root.get("sex"); Predicate p1 = cb.equal(name, "张三"); Predicate p2 = cb.equal(sex, "17"); Predicate res = cb.and(p1, p2); return res; }};Optional<User> one = userRep.findOne(doublespec);System.out.println(one.get());
(四)排序
接口中的匿名类不用改
在第六步调用的findAll方法中添加一个sort对象(与分页时类似)
Sort sort = Sort.by(Sort.Direction.DESC, "sex"); Optional<User> one = userRep.findAll(spec,sort); System.out.println(one.get());
(五)分页
与排序类似
创建PageRequest对象,放入findAll方法中
可以只传入PageRequest对象,代表没有条件,分页全表
Sort sort = Sort.by(Sort.Direction.DESC, "sex"); PageRequest page = PageRequest.of(0, 5, sort); Optional<User> one = userRep.findAll(spec,page);
四、一对多
1. 在一的一方创建多的集合属性
2. 在集合属性上声明关系
@OneToMany:配置一对多关系 targetEntity:指定对方字节码对象(class文件)
3. 在集合属性上配置外键
@JoinColumn:配置外键 name:对方实体外键字段(多的一方) referencedColumnName:本实体主键字段(一的一方)
4. 在多的一方创建一的对象属性
5. 在对象属性上声明关系
@ManyToOne:配置多对一关系 targetEntity:指定对方字节码对象(class文件)
6. 在对象属性上配置外键
@JoinColumn:配置外键 name:本实体外键字段(多的一方) referencedColumnName:对方(主表)主键字段(一的一方)
7.级联操作
在添加的主体的关联属性(OneToMany)上加@cascade
8.tips
在toString中不要出现联系的属性(list与对象),不然会报内存溢出。
添加关系后若想要单表查询,只要不去调用联系的属性(list与对象)的get方法即可实现。
当调用联系的属性(list与对象)的get方法时才会触发多表联查。
五、多对多
1. 创建一个集合存放对方的对象
2. 声明表关系
@ManyToMany:多对多 targetEntity:对方对象的字节码文件
3. 配置中间表(两个对象均要配置)
@JoinTable:配置中间表 ---joinColumns:当前对象在中间表中的外键 --@JoinColumn:配置中间表的外键 --name:外键的名称(随便取) --referencedColumnName:本对象主键字段 ---inverseJoinColumns:对方对象在中间表中的外键 --@JoinColumn:配置中间表的外键 --name:外键的名称(随便取) --referencedColumnName:对方对象主键字段
六、分页
1. 创建PageRequest对象
PageRequest page = PageRequest.of();
2. 传入参数
第一个参数:当前查询的页数(从0开始)
第二个参数:每页查询的数量
第三个参数:排序对象(可不填)
PageRequest page = PageRequest.of(0, 5);
3.创建Sort对象
Sort sort = Sort.by();
4.传入参数
第一个参数:排序方式
第二个参数:按照哪个字段排序
Sort sort = Sort.by(Sort.Direction.DESC, "sex");
PageRequest page = PageRequest.of(0, 5, sort);