SpringDataJpa学习笔记

SpringDataJpa学习笔记

前言

官方文档:https://docs.spring.io/spring-data/jpa/docs/2.1.6.RELEASE/reference/html/

maven地址:https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa

pom 依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

使用

定义 repository 接口,继承 JpaRepository 接口,指定实体类和主键,添加 @Repository 注解

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
}

原理

@JpaRepository

@JpaRepository extends @PagingAndSortingJpaRepository extends CrudRepository extends Repository

@PagingAndSortingJpaRepository:分页和排序查询

@CrudRepository:CRUD

@Repository:作为一个标识

@JpaSpecificationExecutor:条件查询

动态代理

注入对象全限定名:org.springframework.data.jpa.repository.support.SimpleJpaRepository@2c435625

注入对象类型:class com.sun.proxy.$Proxy107(基于JDK动态代理方式创建的对象)

SimpleJpaRepository

@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {}

接口介绍

继承 Repository 接口

Repository 接口是 Spring Data Jpa 中为我们提供的所有接口中的顶层接口

Repository 提供了两种查询方式的支持

  1. 基于方法名称命名规则的查询方式
  2. 基于 @Query 注解的查询方式
@org.springframework.stereotype.Repository
public interface UserRepositorySelf extends Repository<User, Integer> {
}
基于方法命名规则

规则:findBy + 属性名称(属性名称首字母大写) + 查询条件(首字母大写)

查询条件如下:

KeywordSampleJPQL snippet
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1(parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1(parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1(parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection<Age> ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection<Age> ages)… where x.age not in ?1
TruefindByActiveTrue()… where x.active = true
FalsefindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)
基于 @Query 注解查询
JPQL语句查询

JPQL:通过 Hibernate 的 HQL 演变而来

// 1.通过形参顺序
@Query(value = "from User where username like %?1% and age = ?2")
List<User> queryUserByName(String name, Integer age);
// 2.通过形参名称
@Query(value = "from User where username like %:name% and age = :age")
List<User> queryUsers(String name, Integer age);
原生SQL查询
// 1.通过形参顺序
@Query(value = "select * from t_user where username like ?1 and age = ?2", nativeQuery = true)
List<User> nativeQueryUsers(String username, Integer age);
// 2.通过形参名称
@Query(value = "select * from t_user where username like %:username% and age = :age", nativeQuery = true)
List<User> nativeQueryUsersParam(@Param("username") String username, @Param("age") Integer age);
数据更新
// 1.通过形参顺序,更新时必须在事务中进行
@Query(value = "update User set username = ?1 where id = ?2")
@Modifying //更新
@Transactional
void updateUser(String username, Integer id);
// 2.通过形参名称,更新时必须在事务中进行
@Query(value = "update User set username = :username where id = :id")
@Modifying //更新
@Transactional
void updateUser(@Param("id") Integer id, @Param("username") String username);

继承 CurdRepository 接口

public interface UserCrudRepository extends CrudRepository<User, Integer> {
}

api

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
    // 保存或者修改
	<S extends T> S save(S entity);
    // 保存或者修改集合中的对象
	<S extends T> Iterable<S> saveAll(Iterable<S> entities);
    // 根据id获取
	Optional<T> findById(ID id);
    // id 是否存在
	boolean existsById(ID id);
    // 查询所有
	Iterable<T> findAll();
    // 通过 id 数组查询
	Iterable<T> findAllById(Iterable<ID> ids);
    // 统计记录数
	long count();
    // 根据id删除
	void deleteById(ID id);
    // 根据实体删除
	void delete(T entity);
    // 删除指定的所有
	void deleteAll(Iterable<? extends T> entities);
    // 删除所有
	void deleteAll();
}

继承 PagingAnd SortingRepository 接口

public interface UserPagingAndSortingRepository extends PagingAndSortingRepository<User, Integer> {
}

分页

@GetMapping("/page/{size}/{page}")
public Page<User> pageQuery(@PathVariable(name = "size")Integer size, @PathVariable("page")Integer page){
    Pageable pageable = PageRequest.of(page, size);
    return userPagingAndSortingRepositoryj.findAll(pageable);
}

排序

@PostMapping("/sort")
public List<User> sortQuery(@RequestBody List<String> sort){
    Sort.Order order = Sort.Order.asc(sort.get(0));
    Sort.Order order1 = Sort.Order.desc(sort.get(1));
    Sort by = Sort.by(order, order1);

    return (List<User>) userPagingAndSortingRepositoryj.findAll(by);
}

继承 JpaRepository 接口

JapRepository 接口使我们开发时使用最多的接口。其特点可以帮我们把其他接口的方法的返回值做适配处理。开发更高效。

public interface UserRepository extends JpaRepository<User, Integer> {
}

api

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    // 查询所有
	List<T> findAll();
    // 查询所有,并排序
	List<T> findAll(Sort sort);
    // 根据 ID 集合获取查询结果
	List<T> findAllById(Iterable<ID> ids);
    //  修改或者新增
	<S extends T> List<S> saveAll(Iterable<S> entities);
    // 
	void flush();
    // 
	<S extends T> S saveAndFlush(S entity);
    // 根据集合条件,批量删除
	void deleteInBatch(Iterable<T> entities);
    // 删除所有
	void deleteAllInBatch();
    // 根据id获取
	T getOne(ID id);
    // 
	<S extends T> List<S> findAll(Example<S> example);
    //
	<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

继承 JpaSpecificationExecutor 接口

完成多条件查询,并且支持分页与排序。

注:不允许单独使用必须和 JpaRepository 接口一起使用

多条件查询

方式一:

@GetMapping("users")
public List<User> query1(User user){
    Specification<User> specification = new Specification<User>() {
        /**
             * Predicate:定义了查询条件
             * @param root :根对象,封装了查询条件的对象
             * @param query :定义了基本查询,一般不适用
             * @param criteriaBuilder :创建一个查询条件
             * @return
             */
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            // and查询条件数组
            List<Predicate> ands = new ArrayList<>();
            // Predicate 数组
            Predicate[] predicatesAnd = new Predicate[ands.size()];

            // or查询条件数组
            List<Predicate> ors = new ArrayList<>();
            // Predicate 数组
            Predicate[] predicatesOr = new Predicate[ands.size()];


            ands.add(criteriaBuilder.like(root.get("username"), user.getUsername()));
            ands.add(criteriaBuilder.equal(root.get("age"), user.getAge()));

            ors.add(criteriaBuilder.like(root.get("password"), user.getPassword()));
            ors.add(criteriaBuilder.equal(root.get("id"),user.getId()));

            Predicate and = criteriaBuilder.and(ands.toArray(predicatesAnd));
            Predicate or = criteriaBuilder.or(ors.toArray(predicatesOr));
            return criteriaBuilder.or(and,or);
        }
    };
    return userRepository.findAll(specification);
}

执行的SQL

Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.password as password3_0_, user0_.username as username4_0_ from t_user user0_ 
where 
(user0_.username like ?) and user0_.age=18 or user0_.password like ? or user0_.id=1

方式二:

@RequestMapping("users2")
public List<User> query2(User user){
    Specification<User> specification = new Specification<User>() {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            return criteriaBuilder.or(
                criteriaBuilder.and(
                    criteriaBuilder.like(root.get("username"), user.getUsername()),
                    criteriaBuilder.like(root.get("password"), user.getPassword())),
                criteriaBuilder.or(
                    criteriaBuilder.equal(root.get("id"), user.getId()),
                    criteriaBuilder.equal(root.get("age"), user.getAge())
                )
            );
        }
    };
    return userRepository.findAll(specification);

执行的SQL

Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.password as password3_0_, user0_.username as username4_0_ from t_user user0_ 
where 
(user0_.username like ?) and (user0_.password like ?) or user0_.id=1 or user0_.age=18
分页查询
@RequestMapping("3")
public Page<User> query3(User user, int page, int size){
    Specification<User> specification = new Specification<User>() {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            return criteriaBuilder.like(root.get("username").as(String.class), user.getUsername());
        }
    };
    Pageable pageable = PageRequest.of(page, size);
    return userRepository.findAll(specification, pageable);
}

执行的SQL

总共执行了两条语句

Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.password as password3_0_, user0_.username as username4_0_ from t_user user0_ where user0_.username like ? limit ?, ?

Hibernate: select count(user0_.id) as col_0_0_ from t_user user0_ where user0_.username like ?
排序处理
@RequestMapping("4")
public List<User> query4(User user, String sort){
    Specification<User> specification = new Specification<User>() {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            return criteriaBuilder.like(root.get("username").as(String.class), user.getUsername());
        }
    };

    Sort s = Sort.by(Sort.Order.desc(sort));
    return userRepository.findAll(specification, s);
}

执行的SQL

Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.password as password3_0_, user0_.username as username4_0_ from t_user user0_ 
where user0_.username like ? order by user0_.id desc
分页与排序

将排序对象放入分页对象的构造方法中

@RequestMapping("5")
public Page<User> query5(User user, String sort, int page, int size){
    Specification<User> specification = new Specification<User>() {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            return criteriaBuilder.like(root.get("username").as(String.class), user.getUsername());
        }
    };

    Sort s = Sort.by(Sort.Order.desc(sort));
    Pageable pageable = PageRequest.of(page,size, s);
    return userRepository.findAll(specification, pageable);
}

执行的SQL

Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.password as password3_0_, user0_.username as username4_0_ from t_user user0_ where user0_.username like ? order by user0_.id desc limit ?
Hibernate: select count(user0_.id) as col_0_0_ from t_user user0_ where user0_.username like ?

自定义 Repository 接口

自定义接口

package top.simba1949.dao;

import top.simba1949.common.User;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/2 20:09
 */
public interface MyRepository {

    User myFindById(Integer id);
}

注入的接口继承 MyRepository 接口和 JpaRepository 接口

package top.simba1949.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import top.simba1949.common.User;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/2 20:11
 */
public interface MyDao extends JpaRepository<User,Integer>, MyRepository {
}

实现 MyRepository 接口,名称必须是 注入接口名称+Impl

package top.simba1949.dao;

import top.simba1949.common.User;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/2 20:11
 */
public class MyDaoImpl implements MyRepository {

    // 用于操作数据库对象
    @PersistenceContext(name = "entityManagerFactory")
    private EntityManager em;

    @Override
    public User myFindById(Integer id) {
        User user = em.find(User.class, id);
        return user;
    }
}

一对一关系

假设 用户与角色一对一关系

用户(user)

package top.simba1949.common;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/2 12:49
 */
@Data
@Entity
@Table(name = "t_user")
public class User implements Serializable {
    private static final long serialVersionUID = 1534107220170354097L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "username")
    private String username;
    @Column(name = "password")
    private String password;
    @Column(name = "age")
    private Integer age;
    // @OneToOne 表示一对一的关系,cascade = CascadeType.PERSIST表示完成一个级联操作
    // @JoinColumn 表示维护一个外键
    // @JsonIgnoreProperties(ignoreUnknown = true, value = {"user"}) 防止对象互相嵌套获取
    @OneToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "role_id")
    @JsonIgnoreProperties(ignoreUnknown = true, value = {"user"})
    private Role role;
}

角色(role)

package top.simba1949.common;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.ToString;

import javax.persistence.*;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/3 14:36
 */
@Data
@Entity
@Table(name = "t_role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "role_name")
    private String roleName;

    // @JsonIgnoreProperties(ignoreUnknown = true, value = {"role"}) 防止对象互相嵌套获取
    @ToString.Exclude
    @JsonIgnoreProperties(ignoreUnknown = true, value = {"role"})
    @OneToOne(mappedBy = "role")
    private User user;
}

一对多关系

级联保存只能从维护关系的表或者对象发起,才会生效

假设 一个角色可以给多个用户,一个用户只能拥有一个角色

用户(user)多方

package top.simba1949.common;

import com.fasterxml.jackson.annotation.*;
import lombok.Data;
import lombok.ToString;

import javax.persistence.*;
import java.io.Serializable;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/3 15:53
 */
@Data
@Entity
@Table(name = "t_user")
public class OneToManyUser implements Serializable {
    private static final long serialVersionUID = -601018800979166102L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "username")
    private String username;
    @Column(name = "password")
    private String password;
    @Column(name = "age")
    private Integer age;

    // @JsonIgnoreProperties(ignoreUnknown = true, value = {"users"}) 防止对象嵌套
    // @ManyToOne(cascade = CascadeType.ALL) 多对一 ,cascade = CascadeType.ALL 级联操作
    // @JoinColumn(name = "role_id") 指定外键
    @ToString.Exclude
    @JsonIgnoreProperties(ignoreUnknown = true, value = {"users"})
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "role_id")
    private OneToManyRole oneToManyRole;

}

角色(role)一方

package top.simba1949.common;

import com.fasterxml.jackson.annotation.*;
import lombok.Data;
import lombok.ToString;

import javax.persistence.*;
import java.io.Serializable;
import java.util.List;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/3 15:52
 */
@Data
@Entity
@Table(name = "t_role")
public class OneToManyRole implements Serializable {
    private static final long serialVersionUID = 974402828851777226L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "role_name")
    private String roleName;

    // @JsonIgnoreProperties(ignoreUnknown = true, value = {"role"}) 防止对象嵌套
    // @OneToMany(mappedBy = "oneToManyRole", cascade = CascadeType.PERSIST) 一对多
    // cascade = CascadeType.PERSIST 级联操作
    // 最好使用list集合,set集合会出现问题
    @ToString.Exclude
    @JsonIgnoreProperties(ignoreUnknown = true, value = {"role"})
    @OneToMany(mappedBy = "oneToManyRole", cascade = CascadeType.PERSIST)
    private List<OneToManyUser> users;
}

多对多关系

假设用户与角色多对多关系,一个角色拥有多个用户,一个用户拥有多个角色

级联保存只能从维护关系的表或者对象发起,才会生效

用户(user)多方

package top.simba1949.common;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.ToString;

import javax.persistence.*;
import java.io.Serializable;
import java.util.List;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/3 17:58
 */
@Data
@Entity
@Table(name = "t_user")
public class ManyToManyUser implements Serializable {
    private static final long serialVersionUID = -8624304894035432160L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "username")
    private String username;
    @Column(name = "password")
    private String password;
    @Column(name = "age")
    private Integer age;

    // anyToMany(mappedBy = "users", cascade = CascadeType.ALL) 多对多,
    // mappedBy = "users"对应对象的属性,
    // cascade = CascadeType.ALL 级联操作
    @ToString.Exclude
    @JsonIgnoreProperties(ignoreUnknown = true, value = {"users"})
    @ManyToMany(mappedBy = "users", cascade = CascadeType.ALL)
    private List<ManyToManyRole> roles;
}

角色(role)多方

package top.simba1949.common;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.ToString;

import javax.persistence.*;
import java.io.Serializable;
import java.util.List;

/**
 * @author simba1949@outlook.com
 * @date 2019/5/3 17:58
 */
@Data
@Entity
@Table(name = "t_role")
public class ManyToManyRole implements Serializable {
    private static final long serialVersionUID = 1375110139795350779L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "role_name")
    private String roleName;

    // @JoinTable(name = ""),name指定中间表,
    // joinColumns = @JoinColumn(name = "role_id") 当前表在中间表的外键名
    // inverseJoinColumns = @JoinColumn(name = "user_id")) 表示另外一表在中间表的外键
    @ToString.Exclude
    @JsonIgnoreProperties(ignoreUnknown = true, value = {"roles"})
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "t_user_role", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "user_id"))
    private List<ManyToManyUser> users;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Simba1949

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值