快速入门JPA&SpringData整合教程入门到精通(part3)

第三部分

复杂查询-SpecTest

package org.example.test;

import org.example.dao.CustomerDao;
import org.example.entity.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.persistence.criteria.*;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpecTest {
    @Autowired
    private CustomerDao customerDao;

    /**
     * 根据条件查询单个对象
     */
    @Test
    public void testSpec(){
        /**匿名内部类
         * 自定义查询条件
         * 1、实现Specification接口(提供泛型,查询的对象类型)
         * 2、实现toPredicate方法(构造查询条件)
         * 3、需要借助方法参数中的两个参数(
         *     root:获取需要查询的对象属性
         *     CriteriaBuilder:构建查询条件
         *  )
         *
         *  查询条件 1、查询方式 cb对象
         *          2、比较的属性 root对象
         */
        Specification<Customer> spec = new Specification<Customer>() {
                @Override
                public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    return null;
                }
            };
        customerDao.findOne(spec);
    }

    @Test
    public void testSpec1(){
        Specification<Customer> spec = (root,query,cb)->{
            //1.获取比较的属性
            Path<Object> custName = root.get("custName");
            //2.构造查询条件
            Predicate predicate = cb.equal(custName, "海之蓝");//进行精准匹配
            return predicate;};
        Customer one = customerDao.findOne(spec);
        System.out.println(one);
    }

    @Test
    public void testSpec2(){
        Customer customer = customerDao.findOne((root, query, cb) -> {
            //1.获取比较的属性
            Path<Object> custName = root.get("custName");
            //2.构造查询条件
            Predicate predicate = cb.equal(custName, "海之蓝");//进行精准匹配 (比较的属性,比较的值)
            return predicate;
        });
        System.out.println(customer);
    }
    /**
     * 多条件查询
     */
    @Test
    public void testSpec3(){
       Customer customer= customerDao.findOne((root,query,cb)->{
            Path<Object> custName = root.get("custName");
            Path<Object> custIndustry = root.get("custIndustry");
            //条件1
            Predicate con1 = cb.equal(custName, "青岛啤酒");
           //条件2
            Predicate con2 = cb.equal(custIndustry, "啤酒行业");
            //连接多条件
            Predicate predicate = cb.and(con1, con2);
            return predicate;
        });
        System.out.println(customer);
    }
    /**
     * 根据客户名 模糊查询 返回客户列表
     * like gt lt le ge 得到path对象,根据path指定比较的参数类型,再去进行比较
     * 指定参数类型:path.as(类型的字节码对象)
     */
    @Test
    public void  testSpec4(){
        Specification<Customer> spec  = (root, query, builder) -> {
            Path<Object> custName = root.get("custName");
            Expression<String> expression = custName.as(String.class);
            Predicate predicate = builder.like(expression, "%蓝");
            return predicate;
        };

        List<Customer> list = customerDao.findAll(spec);
        for (Customer customer : list) {
            System.out.println(customer);
        }
        //添加排序条件
        //第一个参数 排序方式(升,降序)
        //第二个参数 排序的属性名称
        Sort sort = new Sort(Sort.Direction.DESC,"custLevel" );
        List<Customer> list1 = customerDao.findAll(spec, sort);
        for (Customer customer : list1) {
            System.out.println(customer);
        }
    } 
     /**
     * 分页查询
     * findAll(Specification,Pageable)
     */
    @Test
    public void testSpec5(){
        //不给它条件
        Specification<Customer> spec = null;
        PageRequest pageRequest = new PageRequest(2, 5);
        Page<Customer> pages = customerDao.findAll(spec, pageRequest);
        System.out.println(pages.getTotalElements());//总条数
        System.out.println(pages.getTotalPages());//总页数
        System.out.println(pages.getNumber());//当前页码
        System.out.println(pages.getNumberOfElements());//当前页 的实际条数
        System.out.println(pages.getSize());//每页多少条
        List<Customer> list = pages.getContent();
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }
}

Customer.java

package org.example.entity;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

/**
 * @Entity声明实体类
 * @Table配置实体类和表的映射关系
 */
@Entity
@Table(name = "cst_customer")
public class Customer {
/*
    @Id :声明主键的配置
    @GeneratedValue:配置主键的生成策略
     strategy
        GenerationType.IDENTITY 自增 (数据库要支持主键自增 mysql)
        GenerationType.SEQUENCE 序列 (数据库要支持序列 oracle)
        GenerationType.TABLE jpa提供的一种机制,通过一张数据库表的形式帮助完成主键自增
        GenerationType.auto 由程序自动的帮我们选择主键生成策略
     @Column 配置属性和字段的映射关系
           name 数据库中字段的名称
 */

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cust_id")
    private Long custId;
    @Column(name = "cust_name")
    private String custName;
    @Column(name = "cust_source")
    private String custSource;
    @Column(name = "cust_level")
    private String custLevel;
    @Column(name = "cust_industry")
    private String custIndustry;
    @Column(name = "cust_phone")
    private String custPhone;
    @Column(name = "cust_address")
    private String custAddress;

    /**1、声明关系  一个客户有多个联系人
     * @OneToMany 配置一对多关系
     *        targetEntity :目标关系的类对象
     * 2、配置外键
     *@JoinColumn
     *  name :当前外键字段
     *  referencedColumnName 当前外键参照主表的主键字段名称
     *  一的一方添加了外键配置,对客户而言,具备了维护外键的作用
     */
   /* @OneToMany(targetEntity = LinkMan.class)
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
    //注释此代码的目的是放弃外键维护权
     mappedBy:多的一方 配置关系的属性名称
     cascade :配置级联 (也可以设置多的一方的映射关系的注解上)
       CascadeType.all 所有的crud (推荐)
                    merge 更新
                    PERSIST 保存
                    remove  删除
        fetch:配置关联对象的加载方式
                   FetchType.EAGER 立即加载
                   FetchType.LAZY 懒加载
   */
    @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
    private Set<LinkMan> linkMans = new HashSet<>();

    public Long getCustId() {
        return custId;
    }

    public void setCustId(Long custId) {
        this.custId = custId;
    }

    public String getCustName() {
        return custName;
    }

    public void setCustName(String custName) {
        this.custName = custName;
    }

    public String getCustSource() {
        return custSource;
    }

    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    public String getCustLevel() {
        return custLevel;
    }

    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    public String getCustIndustry() {
        return custIndustry;
    }

    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }

    public String getCustPhone() {
        return custPhone;
    }

    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    public String getCustAddress() {
        return custAddress;
    }

    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }

    public Set<LinkMan> getLinkMans() {
        return linkMans;
    }

    public void setLinkMans(Set<LinkMan> linkMans) {
        this.linkMans = linkMans;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "custId=" + custId +
                ", custName='" + custName + '\'' +
                ", custSource='" + custSource + '\'' +
                ", custLevel='" + custLevel + '\'' +
                ", custIndustry='" + custIndustry + '\'' +
                ", custPhone='" + custPhone + '\'' +
                ", custAddress='" + custAddress + '\'' +
                ", linkMans=" + linkMans +
                '}';
    }
}

LinkMan.java

package org.example.entity;

import javax.persistence.*;

/**
 * 联系人的实体(多的实体类)
 */
@Entity
@Table(name = "cst_linkman")
public class LinkMan {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "lkm_id")
    private Long lkmId;//联系人编号
    @Column(name = "lkm_name")
    private String lkmName;//联系人姓名
    @Column(name = "lkm_gender")
    private String lkmGender;//联系人性别
    @Column(name = "lkm_phone")
    private String lkmPhone;//联系人办公电话
    @Column(name = "lkm_mobile")
    private String lkmMobile;//联系人手机
    @Column(name = "lkm_email")
    private String lkmEmail;//联系人邮箱
    @Column(name = "lkm_position")
    private String lkmPosition;//联系人职位
    @Column(name = "lkm_memo")
    private String lkmMemo;//联系人备注

    /**
     * 一个联系人属于一个客户
     * 配置多对一关系
     * 多的一方也会维护外键
     */
    @ManyToOne(targetEntity = Customer.class,fetch = FetchType.LAZY)
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
    private Customer customer;

    public Long getLkmId() {
        return lkmId;
    }

    public void setLkmId(Long lkmId) {
        this.lkmId = lkmId;
    }

    public String getLkmName() {
        return lkmName;
    }

    public void setLkmName(String lkmName) {
        this.lkmName = lkmName;
    }

    public String getLkmGender() {
        return lkmGender;
    }

    public void setLkmGender(String lkmGender) {
        this.lkmGender = lkmGender;
    }

    public String getLkmPhone() {
        return lkmPhone;
    }

    public void setLkmPhone(String lkmPhone) {
        this.lkmPhone = lkmPhone;
    }

    public String getLkmMobile() {
        return lkmMobile;
    }

    public void setLkmMobile(String lkmMobile) {
        this.lkmMobile = lkmMobile;
    }

    public String getLkmEmail() {
        return lkmEmail;
    }

    public void setLkmEmail(String lkmEmail) {
        this.lkmEmail = lkmEmail;
    }

    public String getLkmPosition() {
        return lkmPosition;
    }

    public void setLkmPosition(String lkmPosition) {
        this.lkmPosition = lkmPosition;
    }

    public String getLkmMemo() {
        return lkmMemo;
    }

    public void setLkmMemo(String lkmMemo) {
        this.lkmMemo = lkmMemo;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    @Override
    public String toString() {
        return "LinkMan{" +
                "lkmId=" + lkmId +
                ", lkmName='" + lkmName + '\'' +
                ", lkmGender='" + lkmGender + '\'' +
                ", lkmPhone='" + lkmPhone + '\'' +
                ", lkmMobile='" + lkmMobile + '\'' +
                ", lkmEmail='" + lkmEmail + '\'' +
                ", lkmPosition='" + lkmPosition + '\'' +
                ", lkmMemo='" + lkmMemo + '\'' +
                '}';
    }
}

LinkManDao.java

package org.example.dao;


import org.example.entity.LinkMan;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface LinkManDao extends JpaRepository<LinkMan,Long>, JpaSpecificationExecutor<LinkMan> {

}

OneToManyTest.java

package org.example.test;

import org.example.dao.CustomerDao;
import org.example.dao.LinkManDao;
import org.example.entity.Customer;
import org.example.entity.LinkMan;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class OneToManyTest {
    @Autowired
    private CustomerDao customerDao;

    @Autowired

    private LinkManDao linkManDao;

    @Test
    @Transactional
    @Rollback(value = false)
    public void test1(){

        Customer customer = new Customer();
        customer.setCustLevel("白酒行业");
        customer.setCustName("小糊涂");

        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小王");
        linkMan.setLkmGender("女");

        /**
         * 配置了客户到联系人的关系
         *  两条insert,一条update
         */
        customer.getLinkMans().add(linkMan);

        customerDao.save(customer);
        linkManDao.save(linkMan);
    }

    @Test
    @Transactional
    @Rollback(value = false)
    public void test2(){

        Customer customer = new Customer();
        customer.setCustLevel("白酒行业");
        customer.setCustName("小糊涂");

        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小王");
        linkMan.setLkmGender("女");

        /**
         * 多对一 只有两条insert语句
         */
        linkMan.setCustomer(customer);

        customerDao.save(customer);
        linkManDao.save(linkMan);
    }


    @Test
    @Transactional
    @Rollback(value = false)
    public void test3(){

        Customer customer = new Customer();
        customer.setCustLevel("白酒行业");
        customer.setCustName("小糊涂");

        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小王");
        linkMan.setLkmGender("女");

        /**
         * 一到多 多发送一条update
         * 由于一的一方可以维护外键,会发送update语句
         * 解决此问题:只需要在一的一方放弃维护权即可
         */
        customer.getLinkMans().add(linkMan);

        /**
         * 多对一 只有两条insert语句
         */
        linkMan.setCustomer(customer);

        customerDao.save(customer);
        linkManDao.save(linkMan);
    }


    /**
     * 级联添加 保存一个客户的同时保存客户的所有联系人
     * 需要在操作主体的实体类上,配置casacde属性
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void test4(){
        Customer customer = new Customer();
        customer.setCustLevel("白酒行业");
        customer.setCustName("小糊涂");

        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小王");
        linkMan.setLkmGender("女");

        LinkMan man2 = new LinkMan();
        man2.setLkmName("小yang");
        man2.setLkmGender("男");

        linkMan.setCustomer(customer);
        man2.setCustomer(customer);
        customer.getLinkMans().add(linkMan);
        customer.getLinkMans().add(man2);

        customerDao.save(customer);

    }


    /**
     * 级联删除 删除一个客户的同时删除客户的所有联系人
     * 需要在操作主体的实体类上,配置casacde属性
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void testDelete(){
        Customer customer = customerDao.findOne(1L);
        customerDao.delete(customer);
    }
}

User.java

package org.example.entity;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "sys_user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long userId;

    @Column(name = "user_name")
    private String userName;

    @Column(name = "user_age")
    private Integer userAge;

    /**
     * 用户到角色的多对多关系
     * 1、声明表关系配置
     *  @ManyToMany(targetEntity = Role.class)
     * 2、配置中间表(包含两个外键)
     *  @JoinTable 配置中间表的名称
     *
     */
    @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
    @JoinTable(name = "sys_user_role",
             //joinColumns 当前对象在中间表的外键
             joinColumns = { @JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
            //inverseJoinColumns 对方对象在中间表的外键
             inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")}
    )
    private Set<Role>  roleSet = new HashSet<>();

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userAge=" + userAge +
                ", roleSet=" + roleSet +
                '}';
    }

    public Set<Role> getRoleSet() {
        return roleSet;
    }

    public void setRoleSet(Set<Role> roleSet) {
        this.roleSet = roleSet;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getUserAge() {
        return userAge;
    }

    public void setUserAge(Integer userAge) {
        this.userAge = userAge;
    }
}

Role.java

package org.example.entity;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "sys_role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id")
    private Long roleId;
    @Column(name = "role_name")
    private String roleName;

    @ManyToMany(mappedBy = "roleSet")

    private Set<User> userSet = new HashSet<>();


    @Override
    public String toString() {
        return "Role{" +
                "roleId=" + roleId +
                ", roleName='" + roleName + '\'' +
                ", userSet=" + userSet +
                '}';
    }

    public Set<User> getUserSet() {
        return userSet;
    }

    public void setUserSet(Set<User> userSet) {
        this.userSet = userSet;
    }

    public Long getRoleId() {
        return roleId;
    }

    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
}

UserDao.java

package org.example.dao;


import org.example.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface UserDao extends JpaRepository<User,Long> , JpaSpecificationExecutor<User> {
}

RoleDao.java

package org.example.dao;


import org.example.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface RoleDao extends JpaRepository<Role,Long>, JpaSpecificationExecutor<Role> {
}

ManyToManyTest.java

package org.example.test;

import org.example.dao.RoleDao;
import org.example.dao.UserDao;
import org.example.entity.Role;
import org.example.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ManyToManyTest {
    @Autowired
    private UserDao userDao;
    @Autowired
    private RoleDao roleDao;

    /**
     * 保存一个用户和一个角色
     * 多对多放弃维护中间表的权力:谁被选择,谁被放弃,role被选择,role被放弃
     */
    @Test
    @Transactional
    @Rollback(false)
    public void testAdd(){
        User user = new User();
        user.setUserName("小王");

        Role role = new Role();
        role.setRoleName("普通用户");

        //配置 用户->角色 的关系,可以对中间表中的数据进行维护
        user.getRoleSet().add(role);

        //配置 角色->用户 的关系,可以对中间表中的数据进行维护
        role.getUserSet().add(user);
        userDao.save(user);
        roleDao.save(role);
    }


    /**
     * 级联 保存一个user的同时,保存user的关联角色
     */
    @Test
    @Transactional
    @Rollback(false)
    public void testCascade(){
        User user = new User();
        user.setUserName("小王");

        Role role = new Role();
        role.setRoleName("普通用户");

        //配置 用户->角色 的关系,可以对中间表中的数据进行维护
        user.getRoleSet().add(role);

        //配置 角色->用户 的关系,可以对中间表中的数据进行维护
        role.getUserSet().add(user);
        userDao.save(user);
    }

    /**
     * 级联 删除id=1的user的同时,删除user的关联角色
     */
    @Test
    @Transactional
    @Rollback(false)
    public void testRemove(){
        User user = userDao.findOne(1L);
        userDao.delete(user);

    }

}

ObjectQueryTest.java

package org.example.test;

import org.example.dao.CustomerDao;
import org.example.dao.LinkManDao;
import org.example.entity.Customer;
import org.example.entity.LinkMan;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import java.util.Iterator;
import java.util.Set;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ObjectQueryTest {
    @Autowired
    private CustomerDao customerDao;
    @Autowired
    private LinkManDao linkManDao;

    /**
     * 测试对象导航查询
     * 查询一个对象的时候,查询出它的关联对象
     */
    @Test
    @Transactional //解决 could not initialize proxy - no Session
    public void testQuery1(){
        Customer one = customerDao.getOne(1L);//
       // Customer one = customerDao.findOne(1L);
        Set<LinkMan> linkMans = one.getLinkMans();
        Iterator<LinkMan> iterator = linkMans.iterator();
        while (iterator.hasNext()){
            LinkMan next = iterator.next();
            System.out.println(next);
        }
    }

    /**
     * 测试对象导航查询
     * 查询一个对象的时候,查询出它的关联对象
     */
    @Test
    @Transactional //解决 could not initialize proxy - no Session
    public void testQuery2(){
        Customer one = customerDao.findOne(1L);
        Set<LinkMan> linkMans = one.getLinkMans();
        Iterator<LinkMan> iterator = linkMans.iterator();
        while (iterator.hasNext()){
            LinkMan next = iterator.next();
            System.out.println(next);
        }
        /**
         * 默认使用的是延迟加载的方式查询的
         * 调用get方法并不会立即发送查询sql,而是在使用关联对象的时候查询
         *
         *怎样使用立即查询
         * 修改配置,fetch 需要配置到多表映射关系的注解上
         *     @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL,
         *     fetch = FetchType.EAGER )
         * 一般不建议使用 立即查询
         */
    }

    /**
     * 测试对象导航查询
     * 查询联系人的时候查询客户
     * 从多的一方查询一的一方
     * 默认加载方式:立即加载
     */
    @Test
    @Transactional
    public void testQuery3() {
        LinkMan one = linkManDao.findOne(2L);
        Customer customer = one.getCustomer();
        System.out.println(customer);
    }
}

总结

以上就是今天学习的内容,喜欢的朋友们可以点赞,收藏,关注哦!感谢
上一篇:mysql 执行计划


下一篇:细说ReactiveCocoa的冷信号与热信号(三):怎么处理冷信号与热信号