Detailed SpringDataJpa

JpaRepository this is the most important method, inherited from the parent interface method return values ​​do an adaptation process.

JpaRepository hierarchy diagram

SimpleJpaRepository is JpaRepository implementation class, if you want to expand can be inherited.

This class is the core class, want to understand the need for this jpa execution classes debug, but also the realization of Spring Jpa dynamic proxy class

@RepositoryDefinition

Repository interfaces are inherited, and inheritance Repository interfaces declarative manner equivalent to a comment

@NoRepositoryBeanInterface

When you use the equivalent spring data jpa of each entity class has to be achieved in the same manner, it can be extracted out separately and placed in a common interface MyRepository, and the related class inherits Repository interfaces or class jpa by MyRepository interface adapter jpa related operations, and other entities operating on the class needs to implement the direct successor MyRepository interfaces do not always go to inherit the interface or class jpa, so this common interface will need to identify this comment @NoRepositoryBean

https://blog.csdn.net/qq_39818325/article/details/86653947

First, the configuration method defined query method

1.Spring The principle Jpa Repository is the use of dynamic proxy mechanism,

@EnableJpaRepositories can configure the query policy method, generally does not require configuration, you can require the use of specified methods, you can use annotation mode, or a mixture of both, the default mix of both.

Query method keyword list:

Expression can be determined by looking at PartTree source, then OK

2. The method to query property expression strategy

Person (private Address addr (private String zipCode)) can use the property expression

But if there are duplicate attribute name of the main achievements attribute will fail.

Solutions are as follows

3. processing query results

这里使用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

这里注意是接口中直接生成的。

Guess you like

Origin blog.csdn.net/qq_29164145/article/details/90480205