JpaRepository这个是最重要的方法,从父接口中所继承的方法对返回值做适配处理。
JpaRepository层次结构图
SimpleJpaRepository是JpaRepository的实现类,如果想进行扩展可以继承此类。
这个类是核心的类,想了解jpa执行过程需要对这个类进行debug,同时也是Spring Jpa动态代理的实现类
@RepositoryDefinition
是用注解方式声明继承Repository接口,和继承Repository接口的方式等价
@NoRepositoryBeanInterface
相当于你在使用spring data jpa 的时候,每个实体类有需要实现的相同的方法,就可以单独抽取出来,放在一个公共的接口MyRepository中,并这个类继承了jpa的相关Repository接口或类,由MyRepository接口来衔接jpa的相关操作,其他实体类需要实现的操作就直接继承MyRepository接口,不用每次都去继承jpa的相关接口或类,所以这个公共接口就需要这个注解@NoRepositoryBean来标识
https://blog.csdn.net/qq_39818325/article/details/86653947
一、定义查询方法的配置方法
1.Spring Jpa Repository的实现原理是采用动态代理的机制,
@EnableJpaRepositories可以配置方法的查询策略,一般不需要配置,可以规定使用方法指定,也可以使用注解方式,或者两者混合,默认两者混合。
查询方法关键字列表:
可以通过查看PartTree源码来确定表达式,然后确定
2.方法查询策略的属性表达式
Person(private Address addr(private String zipCode))可以使用属性表达式
但是如果主属性中有重复的属性名建树就会失败。
解决方案如下
3.查询结果的处理
这里使用Slice不会执行count,只是知道之后有没有Slice
这里使用first和top来对结果返回行数进行限制。
查询结果不同形式有:List/Stream/Page/Future
3.projections对查询结果的扩展
可以使用数据投影对结果进行操作,也就是对获取的列进行选取
@ToString
@NoArgsConstructor
@Setter
@Getter
@Entity
@Table(name = "tb_employee")
public class Emp {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name",length = 100)
private String name;
@Column(name = "age",length = 3)
private int age;
}
public interface EmpProjections {
String getName();
}
public interface EmpReposiroty extends JpaRepository<Emp,Long> {
Collection<EmpProjections> findByNameContains(String str);
}
@Test
public void test5(){
this.empReposiroty.findByNameContains("hello").stream().forEach(e->{
System.out.println(e.getName());
});
}
//hello1
//hello2
//hello1
//hello2
可以使用spel表达式
4.实现机制
通过QueryExecutorMethodInterceptor这个类的源代码,这个类实现了MethodInterceptor这个接口,也就是说这是一个方法拦截器,当@Repository上的查询方法被调用时,会执行invoke方法。
过程如下
5.注解式查询
@Query排序
@Query分页
对原生sql的支持
@Param起别名
@MappedSuperclass:
https://blog.csdn.net/qq_527235890/article/details/70196396
1.标识符注解在父接口上面,是用来标识父类的
2.表示其不能映射到数据库表中,因为其不是一个完整的实体类,但是它拥有的属性能够映射到其子类所用的数据库表中
3.不能和@Entity和@Table注解混用
@Modifying修改标记允许update
@QueyHints一种老旧是数据库查询
@Procedure存储过程的查询方法
@NamedQueries预定义查询
@Query>@NameQuery>方法自定义查询
三、@Entity实例里面常用注解详解
1.基本注解
@Entity
@Table
@Id定义属性为数据库的主键,一个实体里面必须有一个
@IdClass利用外部类的联合主键
[1]必须实现Serializable接口
[2]必须有默认public无参数的构造方法
[3]必须覆盖equals和hashCode方法
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Getter
@Setter
public class UserBlogKey implements Serializable {
private String title;
private Integer createUserId;
private LocalDateTime createTime;
}
@ToString
@NoArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "tb_userblog")
@IdClass(value = UserBlogKey.class)
public class UserBlogEntity {
@Column(name = "uuid")
private String uuid;
@Id
@Column(name = "title",nullable = false)
private String title;
@Id
@Column(name = "create_user_id",nullable = false)
private Integer createUserId;
@Id
@Column(name = "create_time",nullable = false)
private LocalDateTime createTime;
}
public interface UserBlogRepository extends JpaRepository<UserBlogEntity,UserBlogKey> {
}
@GeneratedValue指定主键生成策略
@Basic表示属性到数据库的映射,如果实体字段上没有任何注解,默认为@Basic
@Transient非持久化属性,数据库映射的时间忽略
@Column
@Temporal设置Date类型的属性映射到对应精度的字段
TemporalType.DATE/TemporalType.TIME/TemporalType.TIMESTAMP
@Emumerated直接映射enum枚举类型的字段
@ToString
@NoArgsConstructor
@Setter
@Getter
@Entity
@Table(name = "tb_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "name")
private String name;
//注意映射的值~!
@Enumerated(EnumType.STRING)
@Column(name = "gender")
private Gender gender;
}
@AllArgsConstructor
@Getter
public enum Gender {
MAIL("男性"),FMAIL("女性");
private String name;
}
public interface UserRepository extends JpaRepository<User,Long> {
}
@Lob映射成clob或者blob
映射的组合使用
2.关联注解
@JoinColum
@JoinColums定义多个字段的关联关系
@OneToOne
@ToString(exclude = "department")
@NoArgsConstructor
@Setter
@Getter
@Entity
@Table(name = "tb_employee")
public class Emp {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name",length = 100)
private String name;
@Column(name = "age",length = 3)
private int age;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn
private Department department;
}
@ToString(exclude = "emp")
@NoArgsConstructor
@Setter
@Getter
@Entity
@Table(name = "tb_department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name",length = 100)
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn
private Emp emp;
}
public interface EmpReposiroty extends JpaRepository<Emp,Long> {
Collection<EmpProjections> findByNameContains(String str);
}
public interface DepartmentRepository extends JpaRepository<Department,Long> {
}
@Autowired
EmpReposiroty empReposiroty;
@Autowired
DepartmentRepository departmentRepository;
@Transactional
@Rollback(false)
@Test
public void test() {
//级联关系的建立比如互入
Emp e1 = new Emp();
e1.setName("hello1");
e1.setAge(22);
Department d1 = new Department();
d1.setName("world1");
d1.setEmp(e1);
e1.setDepartment(d1);
Emp e2 = new Emp();
e2.setName("hello2");
e2.setAge(23);
Department d2 = new Department();
d2.setName("world2");
d2.setEmp(e2);
e2.setDepartment(d2);
//在主键维护方插入,且开启级联操作
this.empReposiroty.save(e1);
this.empReposiroty.save(e2);
System.out.println(this.empReposiroty.findAll());
}
@Test
public void test1() {
Optional<Emp> e1 = this.empReposiroty.findById(1l);
System.out.println(e1.get() + " " + e1.get().getDepartment());
Optional<Department> d1 = this.departmentRepository.findById(1l);
System.out.println(d1.get() + " " + d1.get().getEmp());
}
@OneToMany/@ManyToOne
只有关系维护方才能操纵两者的关系
@ToString(exclude = "lib")
@NoArgsConstructor
@Setter
@Getter
@Entity
@Table(name = "tb_book")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "page")
private int page;
@Column(name = "description")
private String description;
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn
private Library lib;
}
@ToString(exclude = "books")
@NoArgsConstructor
@Setter
@Getter
@Entity
@Table(name = "tb_library")
public class Library {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
//这里mappedBy指的是关系维护的属性,也就是少的一方的属性
//默认的懒加载就是没有左联
@OneToMany(cascade = CascadeType.REMOVE,mappedBy = "lib")
private Set<Book> books=new HashSet<>();
}
public interface BookRepository extends JpaRepository<Book,Long> {
List<Book> findBooksByLib_Id(Long libId);
}
public interface LibraryRepository extends JpaRepository<Library,Long> {
}
@Autowired
BookRepository bookRepository;
@Autowired
LibraryRepository libraryRepository;
@Test
@Transactional
@Rollback(false)
public void test2() {
//1.建立对象 2.生成关系
Library library = new Library();
library.setName("president");
library.setDescription("For President!");
Book book1 = new Book();
book1.setName("hero");
book1.setPage(100);
book1.setDescription("To be a hero");
Book book2 = new Book();
book2.setName("soldier");
book2.setPage(200);
book2.setDescription("Death!Frighting!");
library.setBooks(new HashSet() {{
add(book1);
add(book2);
}});
book1.setLib(library);
book2.setLib(library);
this.libraryRepository.save(library);
book1.setLib(library);
book2.setLib(library);
this.bookRepository.save(book1);
this.bookRepository.save(book2);
}
@Test
@Transactional
@Rollback(false)
public void test3() {
this.libraryRepository.deleteById(1l);
}
@Test
public void test4() {
this.bookRepository.findAll().stream().forEach(e -> {
System.out.println(e + " " + e.getLib());
});
//oneToMany端懒加载是拉不出来,所以要求我们必须拉取出来
//如果进行激进加载,就是连表查询返回结果集
this.libraryRepository.findAll().stream().forEach(e->{
System.out.println(e+" "+this.bookRepository.findBooksByLib_Id(e.getId()));
});
// this.libraryRepository.findAll().stream().forEach(e->{
// System.out.println(e+" "+e.getBooks());
// });
}
@Test
public void test5(){
this.empReposiroty.findByNameContains("hello").stream().forEach(e->{
System.out.println(e.getName());
});
}
@OrderBy关联查询时排序
@JoinTable关联关系表
@ManyToMany
@Getter
@Setter
@NoArgsConstructor
@ToString(exclude = "roles")
@Entity
@Table(name = "tb_menu")
public class Menu {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "url")
private String url;
//Role那一侧关联的映射对象属性
@ManyToMany(mappedBy = "menus",cascade = CascadeType.ALL)
Set<Role> roles=new HashSet<>();
}
@Getter
@Setter
@NoArgsConstructor
@ToString(exclude = "menus")
@Entity
@Table(name = "tb_role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "name")
private String name;
@ManyToMany(cascade = CascadeType.REMOVE)
//JoinTable:中间表,两侧任意一方就可以
//joinColumns:建立当前表在中间表中的外键字段
@JoinTable(name = "t_roles_menus",joinColumns = @JoinColumn(name = "role_id"),inverseJoinColumns = @JoinColumn(name = "menu_id"))
private Set<Menu> menus=new HashSet<>();
}
public interface MenuRepository extends JpaRepository<Menu,Long> {
Set<Menu> findMenusByRolesIs(Role role);
}
public interface RoleRepository extends JpaRepository<Role,Long> {
}
public class TestJpa2 {
@Autowired
RoleRepository roleRepository;
@Autowired
MenuRepository menuRepository;
@Test
public void test1(){
//这里有一些区别,需要我们进行两侧的保存
//或者在操作上开启级联操作
Role role=new Role();
role.setName("role-1");
Menu menu=new Menu();
menu.setName("menu-3");
menu.setUrl("menu-url-3");
role.setMenus(new HashSet(){{
add(menu);
}});
menu.setRoles(new HashSet(){{
add(role);
}});
this.menuRepository.save(menu);
//保存后直接获取主键
System.out.println(menu);
}
@Test
public void test2(){
//懒加载
this.roleRepository.findAll().stream().forEach(e->{
System.out.println(e+" "+this.menuRepository.findMenusByRolesIs(e));
});
}
@Test
@Transactional
@Rollback(false)
public void test3(){
this.roleRepository.deleteById(1l);
}
@Test
@Transactional
@Rollback(false)
public void test4(){
//应先查询再删除
this.menuRepository.deleteById(3l);
}
@Test
public void test5(){
//目标一次性获取信息
// System.out.println(this.menuRepository.findByIdAndRolesAfter(4l));
}
等于说时谁@joinColum谁可以去操作对象,Mappred就是维护对象关系
@EntityGraph
这里注意是接口中直接生成的。