SpringDataJpa大全

本文最后更新于:2020年9月10日 下午

SpringDataJPA概念

img

  1. Spring Data JPA 是 Spring 基于 ORM 框架、JPA规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作
  2. Spring Data JPA 提供了包括增删改查等在内的常用功能,且易于扩展,大大提高了开发效率

SpringDataJPA快速入门

img

1. 项目配置

1.1 在pom.xml中添加相关依赖
1.2 在applicationContext.xml配置相应的配置
1.3 创建实体类和实体类对应的DAO接口

2. Spring Data JPA DAO流程分析

img

底层用的动态代理,完成接口的实现类对象,根据方法名查询,更加简单便捷

3. Dao层接口基础方法

  • 继承JpaRepository后的方法列表

    img

  • 继承JpaSpecificationExecutor的方法列表

    img

  • 基础查询
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class CustomerDaoTest {
    @Autowired
    private CustomerDao customerDao;

    /**
     * 根据id查询
     */
    @Test
    public void testFindOne(){
        Customer c = customerDao.findOne(2l);
        System.out.println(c);
    }

    /**
     * 保存与更新   是否传id主键属性
     */
    @Test
    public void testSave(){
        Customer customer = new Customer();
        customer.setCustName("洪湖");
        customerDao.save(customer);
    }
    @Test
    public void testUpdate(){
        Customer customer = new Customer();
        customer.setCustId(4l);
        customer.setCustName("大洪湖");
        customerDao.save(customer);
    }

    /**
     * 删除用户
     */
    @Test
    public void testDelete(){
        customerDao.delete(4l);
    }

    /**
     * 查询所有用户
     */
    @Test
    public void testFindAll(){
        List<Customer> list = customerDao.findAll();
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }

    /**
     * 查询客户总数量
     */
    @Test
    public void testCount(){
        long count = customerDao.count();
        System.out.println(count);
    }

    /**
     * 判断用户是否存在
     */
    @Test
    public void testExists(){
        boolean exists=customerDao.exists(3l);
        System.out.println("是否存在:"+exists);
    }

    /**
     * 根据id从数据库查询
     *      findOne
     *          em.find();              立即加载
     *      getOne()
     *          em.getReference();      延迟加载    什么时候用  什么时候查询
     */
    @Test
    @Transactional
    public void testGetOne(){
        Customer customer = customerDao.getOne(3l);
        System.out.println(customer);
    }

}
  • 基本能完成简单的crud和排序,分页等功能

4.JPQL

img

query注解

  • Dao层接口配置
/**
 * springDataJPA规范  需要继承两个接口
 * JpaRepository接口   * 基本的增删查改操作
 * JpaSpecificationExecutor接口    * 封装了复杂查询操作
 */
public interface CustomerDao extends JpaRepository<Customer,Long>,JpaSpecificationExecutor<Customer>{
    /**
     * 根据客户名称 查询客户
     * jpql
     *
     */
    @Query(value = "from Customer where custName = ?")
    public Customer findJpql(String custName);

    /**
     * 多条件查询
     * jpql
     */
    @Query(value = "from Customer where custId = ? and custName = ?")
    public Customer findTwoJpql(long custId,String custName);

    /**
     * 更新操作
     * jpql
     */
    @Query(value = "update Customer set custName = ? where custId = ?")
    @Modifying
    public void updateJpql(String custName,long custId);

    /**
     * sql语句  查询
     */
    @Query(value = "select * from cst_customer",nativeQuery = true)
    public List<Object[]> findSql();

    /**
     * sql语句  查询
     */
    @Query(value = "select * from cst_customer WHERE cust_name LIKE ?",nativeQuery = true)
    public List<Object[]> findSqlFindName(String name);
    
     /**
     * 方法名称查询
     */
    public Customer findByCustName(String custName);

    /**
     * 模糊查询
     * @param custName
     * @return
     */
    public List<Customer> findByCustNameLike(String custName);

    /**
     * 精确查询
     * @param custName
     * @param custLevel
     * @return
     */
    public Customer findByCustNameLikeAndCustLevel(String custName,String custLevel);
}
  • 测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class JpqlTest {
    @Autowired
    private CustomerDao customerDao;

    /**
     * JPQL精准查询
     */
    @Test
    public void testFindJPQL(){
        Customer customer = customerDao.findJpql("深圳计划");
        System.out.println(customer);
    }

    /**
     * JPQL多条件查询
     */
    @Test
    public void  testFindTwoJPQL(){
        Customer c = customerDao.findTwoJpql(2l, "深圳计划");
        System.out.println(c);
    }

    /**
     * JPQL更新操作
     * 需要添加事务  不然会回滚
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  testUpdateJPQL(){
        customerDao.updateJpql("大深圳计划",2l);
    }

    /**
     * sql语句查询
     */
    @Test
    public void testSql(){
        List<Object[]> list = customerDao.findSql();
        for (Object[] objects : list) {
            System.out.println(Arrays.toString(objects));
        }
    }

    /**
     * sql语句模糊查询
     */
    @Test
    public void testSqlFindName(){
        List<Object[]> list = customerDao.findSqlFindName("%计划");
        for (Object[] objects : list) {
            System.out.println(Arrays.toString(objects));
        }
    }
      /**
     * 方法名称查询
     */
    @Test
    public void findByCustName(){
        Customer c = customerDao.findByCustName("福州计划");
        System.out.println(c);
    }

    /**
     * 模糊查询
     */
    @Test
    public void findByCustNameLike(){
        List<Customer> list = customerDao.findByCustNameLike("%计划");
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }

    /**
     * sql多条件查询
     */
    @Test
    public void findByCustNameLikeAndCustLevel(){
        Customer c = customerDao.findByCustNameLikeAndCustLevel("%计划", "1");
        System.out.println(c);
    }
}

Specifications动态查询

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

    /**
     * 根据条件查询单个对象
     */
    @Test
    public void testSpec(){
        /**
         * 匿名内部类
         * 自定义查询条件
         *      root 需要查询对象的属性
         *      CriteriaBuilder 构造查询条件的【模糊匹配,精准匹配等】
         *
         */
        Specification<Customer> spec=new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //获取比较的属性
                Path<Object> custName = root.get("custName");
                //构造查询  【进行精准匹配】
                //1.比较的属性  2.比较的值
                Predicate p = cb.equal(custName, "福州计划");
                return p;
            }
        };
        Customer customer = customerDao.findOne(spec);
        System.out.println(customer);
    }

    /**
     *  多条件查询
     */
    @Test
    public void testSpec1(){
        /**
         * root 获取属性
         * cb  构造查询
         */
        Specification<Customer> spec=new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> custName = root.get("custName");
                Path<Object> custLevel = root.get("custLevel");
                //精准匹配
                Predicate p1 = criteriaBuilder.equal(custName, "大深圳计划");
                Predicate p2 = criteriaBuilder.equal(custLevel, "1");
                Predicate p = criteriaBuilder.and(p1, p2);
                return p;
            }
        };
        Customer c = customerDao.findOne(spec);
        System.out.println(c);
    }

    /**
     *  模糊查询
     */
    @Test
    public void testSpec2(){
        /**
         * root 获取属性
         * cb  构造查询
         */
        Specification<Customer> spec=new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> custName = root.get("custName");
                Predicate p = criteriaBuilder.like(custName.as(String.class), "%计划");
                return p;
            }
        };
        //排序对象   1.排序方式【倒序或者正序】 排序属性名
        Sort sort = new Sort(Sort.Direction.DESC,"custId");
        List<Customer> list = customerDao.findAll(spec, sort);
        for (Customer c : list) {
            System.out.println(c);
        }
    }

    /**
     * 分页查询
     */
    @Test
    public void testSpec3(){
        Specification spec=null;
        //1.当前页码  2.每页显示条数
        Pageable pageable =new PageRequest(0,2);
        Page<Customer> p = customerDao.findAll(spec, pageable);
        System.out.println(p.getContent());//获得数据集合列表
        System.out.println(p.getTotalElements());//总条数
        System.out.println(p.getTotalPages()); //总页数
    }

}

5.多表关系

一对多映射

  • LinkMan实体类
/**
 * 配置联系人到客户多对一关系
 * 声明关系
 *          @ManyToOne  一对多
 *              targetEntity:对方对象的字节码
 *    配置外键
 *          @JoinColumn  配置外键
 *              name 外键字段名称
 *              referencedColumnName 参见主表的字段名称
 */
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;
  • Customer实体类
//配置客户和联系人之间的关系  一对多
/**
 * 注解配置多表关系
 *    声明关系
 *          @OneToMany  一对多
 *              targetEntity:对方对象的字节码
 *    配置外键
 *          @JoinColumn  配置外键
 *              name 外键字段名称
 *              referencedColumnName 参见主表的字段名称
 *
 *  @OneToMany(targetEntity = LinkMan.class)
 *  @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
 *      放弃外键维护权   使用 mappedBy:对方配置关系的属性名称
 *  cascade 配置级联
 *      CascadeType.All         所有
 *                  MERGE       更新
 *                  PERSIST     保存
 *                  REMOVE      删除
 */
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
private Set<LinkMan> linkMens=new HashSet<LinkMan>();
  • 测试类
@Autowired
private CustomerDao customerDao;
@Autowired
private LinkManDao linkManDao;

/**
 * 级联添加  保存一个客户的同时  保存客户的所有的联系人
 */
@Test
@Transactional  //设置事务
@Rollback(value = false)
public void testCascadeAdd(){
    Customer customer=new Customer();
    customer.setCustName("阿里");
    LinkMan man=new LinkMan();
    man.setLkmName("淼哥");
    man.setCustomer(customer);
    customer.getLinkMens().add(man);
    customerDao.save(customer);
}
/**
 * 级联删除
 */
@Test
@Transactional  //设置事务
@Rollback(value = false)//不回滚
public void testCascadeDelete(){
    Customer c = customerDao.findOne(1l);
    //删除一号客户
    customerDao.delete(c);
}

 /**
 *  一查多
 *      加载方式:延迟加载
 * 对象导航查询 【查询一个对象时,通过此对象查询所有的关联对象】
 */
@Test
@Transactional
public void testQuery1(){
    Customer customer = customerDao.getOne(1l);
    Set<LinkMan> set = customer.getLinkMens();
    for (LinkMan man : set) {
        System.out.println(man);
    }
}

/**
 *  多查一
 *    加载方式:立即加载
 */
@Test
@Transactional
public void testQuery2(){
    LinkMan linkMan = linkManDao.findOne(2l);
    Customer customer = linkMan.getCustomer();
    System.out.println(customer);
}

多对多映射

  • User实体类
/**
 *  用户到角色
 *  配置多对多关系
 *      1.表明表关系的配置
 *      2.配置中间表(包含两个外键)
 *      @ManyToMany
 *           targetEntity 对方实体类字节码
 *      @JoinTable
 *           joinColumns  当前表在中间表的外键
 *                  name: 外键名
 *                  referencedColumnName:参照主表的主键名
 *           inverseJoinColumns  对方表在中间表的外键
 */
@ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
@JoinTable(name = "sys_user_role",
    joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
    inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")}
)
private Set<Role> roles=new HashSet<Role>();
  • Role实体类
 /**
 *  角色到用户
 *  配置多对多关系
 *      1.表明表关系的配置
 *      2.配置中间表(包含两个外键)
 *      @ManyToMany
 *           targetEntity 对方实体类字节码
 *      @JoinTable
 *           joinColumns  当前表在中间表的外键
 *                  name: 外键名
 *                  referencedColumnName:参照主表的主键名
 *           inverseJoinColumns  对方表在中间表的外键
 *  放弃外键维护权   使用 mappedBy:对方配置关系的属性名称
 *      @ManyToMany(targetEntity = User.class)
 *      @JoinTable(name = "sys_user_role",
 *      joinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")},
 *      inverseJoinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")}
)
 */
@ManyToMany(mappedBy = "roles")
private Set<User> users=new HashSet<User>();
  • 测试类
/**
     * 级联操作 添加
     */
    @Test
    @Transactional
    @Rollback(false)
    public void testCasCadeAdd(){
        User user = new User();
        user.setUserName("淼哥");
        Role role = new Role();
        role.setRoleName("java软件工程师");
        // 一对一
        user.getRoles().add(role);
        //一对一 主键重复
        //role.getUsers().add(user);
        userDao.save(user);
    }
    /**
     * 级联操作 删除
     */
    @Test
    @Transactional
    @Rollback(false)
    public void testCasCadeDelete(){
        User user = userDao.findOne(1l);
        userDao.delete(user);
    }