Springdata_自己的小小总结03

由于企业开发时,搜索的条件内容个数不确定,使用Specifications动态查询解决此问题

看一下第一到第四个视频

一、Specifications动态查询

JpaSpecificationExecutor 方法列表

T findOne(Specification spec); //查询单个对象

List findAll(Specification spec); //查询列表

//查询全部,分页
//pageable:分页参数
//返回值:分页pageBean(page:是springdatajpa提供的)
Page findAll(Specification spec, Pageable pageable);

//查询列表
//Sort:排序参数
List findAll(Specification spec, Sort sort);

long count(Specification spec);//统计查询

Specification :查询条件
自定义我们自己的Specification实现类
实现
//root:查询的根对象(查询的任何属性都可以从根对象中获取)
//CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用)
//CriteriaBuilder:查询的构造器,封装了很多的查询条件
Predicate toPredicate(Root root, CriteriaQuery<?> query, CriteriaBuilder cb); //封装查询条件


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:META-INF/persistence.xml")
public class TestSpec {
    @Autowired
    CustomerDao customerDao;

    /**
     * 自定义查询条件
     *      1.实现Specification接口(提供泛型:查询的对象类型)
     *      2.实现toPredicate方法(构造查询条件)
     *      3.需要借助方法参数中的两个参数(
     *          root:获取需要查询的对象属性
     *          CriteriaBuilder:构造查询条件的,内部封装了很多的查询条件(模糊匹配,精准匹配)
     *       )
     *  案例:根据客户名称查询,查询客户名为传智播客的客户
     *          查询条件
     *              1.查询方式
     *                  cb对象
     *              2.比较的属性名称
     *                  root对象
     *
     */
    @Test
    public void test01(){
        Specification<Customer> spec =new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //获取比较的属性
                Path<Object> custAddress = root.get("custAddress");
                //第一个参数是指定比较属性的属性名
                //第二个参数是指定具体精准查询的值
                Predicate p = cb.equal(custAddress, "三道沟");
                return p;
            }
        };
        Customer one = customerDao.findOne(spec);
        System.out.println(one);
    }

    /**
     * 多个精准条件查询
     */
    @Test
    public void test02(){
        Specification<Customer> spec =new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Path<Object> custAddress = root.get("custAddress");
                Path<Object> custLevel = root.get("custLevel");
                Predicate p1 = cb.equal(custAddress, "三道沟");
                Predicate p2 = cb.equal(custLevel, "22");
                //以与的形式,进行查询     cb.or 以或的形式查询
                Predicate pp = cb.and(p1, p2);
                return pp;
            }
        };
        List<Customer> all = customerDao.findAll(spec);
        System.out.println(all);
    }
    /**
     * 案例:完成根据客户名称的模糊匹配,返回客户列表
     * 客户名称以 ’传智播客‘ 开头
     * <p>
     * equal :直接的到path对象(属性),然后进行比较即可
     * gt,lt,ge,le,like : 得到path对象,根据path对象指定比较的参数类型,再去进行比较
     * 指定参数类型:path.as(类型的字节码对象)
     */
    @Test
    public void test03(){
        Specification<Customer> spec =new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Path<Object> custAddress = root.get("custAddress");
                Predicate like = cb.like(custAddress.as(String.class), "三%");
                return like;
            }
        };
        List<Customer> all = customerDao.findAll(spec);
        System.out.println(all);


        //添加排序
        //创建排序对象,需要调用构造方法实例化sort对象
        //第一个参数:排序的顺序(倒序,正序)
        //   Sort.Direction.DESC:倒序
        //   Sort.Direction.ASC : 升序
        //第二个参数:排序的属性名称
        //Sort sort = new Sort(Sort.Direction.DESC, "custId");
        //List<Customer> list = customerDao.findAll(spec, sort);
        //for (Customer customer : list) {
        //    System.out.println(customer);
        //}
    }

    /**
     * 分页查询
     * Specification: 查询条件
     * Pageable:分页参数
     * 分页参数:查询的页码,每页查询的条数
     * findAll(Specification,Pageable):带有条件的分页
     * findAll(Pageable):没有条件的分页
     * 返回:Page(springDataJpa为我们封装好的pageBean对象,数据列表,共条数)
     */
    @Test
    public void test04(){
        Specification<Customer> spec= new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Path<Object> custAddress = root.get("custAddress");
                Predicate p1 = cb.equal(custAddress, "三道沟");

                return p1;
            }
        };
        //PageRequest对象是Pageable接口的实现类
        /**
         * 创建PageRequest的过程中,需要调用他的构造方法传入两个参数
         *      第一个参数:当前查询的页数(从0开始)
         *      第二个参数:每页查询的数量
         */
        Pageable p =new PageRequest(0,4);//不带排序的查询的分页
        Sort s = new Sort(Sort.Direction.DESC,"custId");//排序对象
        Pageable p2 = new PageRequest(0,4,s);//带排序的查询的分页
        //Page<Customer> page = customerDao.findAll(spec, p);//带条件的查询
        Page<Customer> all = customerDao.findAll(p2);//不带条件的查询
        //page.getContent();//得到数据列表
        //page.getTotalPages();//得到总页数
        //page.getTotalElements();//得到总页数
        System.out.println(all.getContent());
    }
}

二、多表之间的关系和操作多表的操作步骤

     i、表关系

**一对一:**
**一对多:**
	一的一方:主表
	多的一方:从表
	外键:需要再从表上新建一列作为外键,他的取值来源于主表的主键
**多对多:**
	中间表:中间表中最少应该由两个字段组成,这两个字段做为外键指向两张表的主键,又组成了联合主键

讲师对学员:一对多关系

     ii、实体类中的关系

包含关系:可以通过实体类中的包含关系描述表关系
继承关系

     iii、分析步骤

1.明确表关系
2.确定表关系(描述 外键|中间表)
3.编写实体类,再实体类中描述表关系(包含关系)
4.配置映射关系

三、完成多表操作

     i.一对多操作

1)、主表的实体类

扫描二维码关注公众号,回复: 10049571 查看本文章
//配置客户和联系人之间的关系(一对多关系)
    /**
     * 使用注解的形式配置多表关系
     *      1.声明关系
     *          @OneToMany :配置一对多的关系
     *              targetEntity :对方对象的字节码对象
     *      2.配置外键(中间表)
     *              @JoinColumn:配置外键
     *                  name: 外键字段名称
     *                  referencedColumnName:参照主表的主键字段名称
     *  在客户实体类上(一的一方)添加了外键的配置,所以对于客户而言,也具备了维护外键的作用
     */
    @OneToMany(targetEntity = LinkMan.class)
    //name =“外键”     referencedColumnName =“主键”
    @JoinColumn(name = "lkm_cust_id",referencedColumnName ="cust_id" )
    private Set<LinkMan> linkMens = new HashSet<LinkMan>();

2)、从表的实体类

/**
     * 配置联系人到客户的多对一关系
     *      使用注解的形式配置多对一关系
     *      1.配置表关系
     *           @ManyToOne:配置多对一的关系
     *              targetEntity:对方的实体类字节码
     *      2.配置外键(表)
     * 配置外键的过程,配置到了多的一方,就会在多的一方维护外键
     */
    @ManyToOne(targetEntity = Customer.class)
     //name =“外键”     referencedColumnName =“主键”
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
    private Customer customer;

xml中需要添加内容

<!-- 2.配置entityManagerFactory -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

<!--注入jpa的配置信息
            加载jpa的基本配置信息和jpa实现方式(hibernate)的配置信息
            hibernate.hbm2ddl.auto:自动创建数据库表
                create:每次都会重新创建数据库表
                update:有表不会重新创建,没有表会重新创建表-->
        <property name="jpaProperties">
                <props>
                    <prop key="hibernate.hbm2ddl.auto">create</prop>
                </props>
        </property>
    </bean>

测试代码


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:META-INF/persistence.xml")
public class OneToMany {
    @Autowired
    CustomerDao customerDao;

    @Autowired
    LinkManDao linkManDao;

    /**
     * 保存一个客户,保存一个联系人
     * 问题是:多表的外键为空???
     * 原因是:在保存的时候,两张表没有产生关系
     */
    @Test
    @Transactional
    @Rollback(false)//不加Rollback的话,springdata JPA 会默认自动回滚
    public void saveDemo1(){
        Customer customer =new Customer();
        customer.setCustName("小程程");
        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小鹏鹏");
        //在保存的时候,让两张表产生关系
        //customer.getLinkMans().add(linkMan);

        linkMan.setCustomer(customer);
        customerDao.save(customer);
    }
    /**
     * 如果两张表,保存的时候,互相都产生关系会发生什么?
     *如果两个都添加的话,会多出下面的一条SQL语句
     * update cst_linkman set lkm_cust_id=? where lkm_id=?
     *      解决办法是:只需要在一的一方放弃维护权即可
     */
    @Test
    @Transactional
    @Rollback(false)//不加Rollback的话,springdata JPA 会默认自动回滚
    public void saveDemo2(){
        Customer customer =new Customer();
        customer.setCustName("小程程");
        LinkMan linkMan1 = new LinkMan();
        linkMan1.setLkmName("小鹏鹏");
        /**
         * 配置了两张表保存时的关系
         *  在多表那一方添加
         */
        customer.getLinkMans().add(linkMan1);

        /**
         *也可以在一表那一方添加
         */
        //linkMan1.setCustomer(customer);
        customerDao.save(customer);
        linkManDao.save(linkMan1);
    }
}

解决办法是:只需要在一的一方放弃维护权即可

	/**
     * 放弃维护权
     * 		mappedBy=  对方配置关系的属性名称
     */
    @OneToMany(mappedBy = "customer")
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();

级联:
操作一个对象的同时操作他的关联对象
级联操作:
1.需要区分操作主体
2.需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系的注解上)
3.cascade(配置级联)
级联添加
案例:当我保存一个客户的同时保存联系人
级联删除
案例:当我删除一个客户的同时删除此客户的所有联系人

	/**
     * 级联操作
     *      级联添加
     *        需要在主表的关系注解上加cascade = CascadeType.ALL
     *        @OneToMany(mappedBy = "customer" ,cascade = CascadeType.ALL)
     *        private Set<LinkMan> linkMans = new HashSet<LinkMan>();
     */
    @Test
    @Transactional
    @Rollback(false)//不加Rollback的话,springdata JPA 会默认自动回滚
    public void saveDemo3(){
        Customer customer =new Customer();
        customer.setCustName("小冉冉");
        LinkMan linkMan1 = new LinkMan();
        linkMan1.setLkmName("小胖胖");
        /**
         * 配置了两张表保存时的关系
         *  在多表那一方添加
         */
        customer.getLinkMans().add(linkMan1);

        /**
         *也可以在一表那一方添加
         */
        linkMan1.setCustomer(customer);
        customerDao.save(customer);
    }
	/**
     * 级联操作
     *      级联删除
     *        需要在主表的关系注解上加cascade = CascadeType.ALL
     * 			cascade是在多表的关系的注解上都可以加
     *        @OneToMany(mappedBy = "customer" ,cascade = CascadeType.ALL)
     *        private Set<LinkMan> linkMans = new HashSet<LinkMan>();
     */
    @Test
    @Transactional
    @Rollback(false)//不加Rollback的话,springdata JPA 会默认自动回滚
    public void saveDemo4(){
        //查询1号客户
        Customer one = customerDao.findOne(7l);
        //删除1号客户
        customerDao.delete(one);
    }


ii.多对多操作

案例:用户和角色(多对多关系)
    用户:
    角色:
分析步骤
    1.明确表关系
        多对多关系
    2.确定表关系(描述 外键|中间表)
        中间间表
    3.编写实体类,再实体类中描述表关系(包含关系)
        用户:包含角色的集合
        角色:包含用户的集合
    4.配置映射关系
dao层接口

//role 的接口
public interface RoleDao extends JpaRepository<Role,Long>, JpaSpecificationExecutor<Role> {

}
//user 的接口
public interface UserDao extends JpaRepository<User,Long>, JpaSpecificationExecutor<User> {

}

实体类

//Role的实体类
@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;
    /**
     * 被动的一方放弃维护权,mappedBy = 对方中本类的属性名称
     * @ManyToMany(mappedBy = "roles")
     */
    @ManyToMany(mappedBy = "roles")
    private Set<User> users = new HashSet<User>();

省去getter 和 setter。。。。







//User的实体类
@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="age")
    private Integer age;

    //添加Role集合

    // 2-2
    /**
     * 1. 确定关系注解
     * 2. 确定由哪方维护外键关系
     * 3. 在维护关系一方,添加外键关系信息
     *
     *  声明表关系   targetEntity = Role.class  指向对方实体类的字节码对象
     * @ManyToMany(targetEntity = Role.class)
     * 级联操作
     *  @ManyToMany(cascade = CascadeType.ALL)
     *
     *  JoinTable:中间表名
     *  joinColumns:本方在中间表的外键名
     *  inverseJoinColumns:对方在中间表的外键名
     */
//    @ManyToMany(targetEntity = Role.class)
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "role_user",joinColumns = {@JoinColumn(name = "user_id"/*,referencedColumnName = "user的主键"*/)},inverseJoinColumns = {@JoinColumn(name = "role_id"/*,referencedColumnName = "role的主键"*/)})
    Set<Role> roles = new HashSet<Role>();
    //省去getter 和setter方法....

测试代码


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:META-INF/persistence.xml")
public class TestSpec {

    @Autowired
    private UserDao userDao;
    @Autowired
    private RoleDao roleDao;

    /**
     * 保存一个用户,保存一个角色
     *
     *  多对多放弃维护权:被动的一方放弃
     */
    @Test
    @Transactional
    @Rollback(false)
    public void  testAdd() {
        User user = new User();
        user.setUserName("zs");

        Role role = new Role();
        role.setRoleName("管理员");

        //1.建立关系
        user.getRoles().add(role);
        role.getUsers().add(user);
        //2.保存User和Role
        userDao.save(user);
        roleDao.save(role);

    }


    //测试级联添加(保存一个用户的同时保存用户的关联角色)
    @Test
    @Transactional
    @Rollback(false)
    public void  testCasCadeAdd() {
        User user = new User();
        user.setUserName("zs");

        Role role = new Role();
        role.setRoleName("管理员");

        //用户关联角色
        user.getRoles().add(role);
        //role维护关键
        role.getUsers().add(user);

        //保存用户
        userDao.save(user);


    }

    /**
     * 案例:删除id为1的用户,同时删除他的关联对象
     */
    @Test
    @Transactional
    @Rollback(false)
    public void  testCasCadeRemove() {
        userDao.delete(2L);
    }
}

POM文件参照上面

iii.多表的查询

1.对象导航查询
查询一个对象的同时,通过此对象查询他的关联对象
案例:客户和联系人
从一方查询多方
* 默认:使用延迟加载(****)
从多方查询一方
* 默认:使用立即加载


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:META-INF/persistence.xml")
public class ObjectQueryTest {
	
    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private LinkManDao linkManDao;

    //could not initialize proxy - no Session
    //测试对象导航查询(查询一个对象的时候,通过此对象查询所有的关联对象)
    @Test
    //@Transactional // 解决在java代码中的no session问题
    public void  testQuery1() {
        //查询id为1的客户
        Customer customer = customerDao.getOne(1l);
        //对象导航查询,此客户下的所有联系人
        Set<LinkMan> linkMans = customer.getLinkMans();

        for (LinkMan linkMan : linkMans) {
            System.out.println(linkMan);
        }
    }

    /**
     * 对象导航查询:
     *      默认使用的是延迟加载的形式查询的
     *          调用get方法并不会立即发送查询,而是在使用关联对象的时候才会查询
     *      延迟加载!
     * 修改配置,将延迟加载改为立即加载
     *      fetch,需要配置到多表映射关系的注解上(@ManyToOne(fetch = "
     *                                                             EAGER :立即加载
     *                                                             LAZY :延迟加载"))
     *
     */

    @Test
    @Transactional // 解决在java代码中的no session问题
    public void  testQuery2() {
        //查询id为1的客户
        Customer customer = customerDao.findOne(1l);
        //对象导航查询,此客户下的所有联系人
        Set<LinkMan> linkMans = customer.getLinkMans();

        System.out.println(linkMans.size());
    }

    /**
     * 从联系人对象导航查询他的所属客户
     *      * 默认 : 立即加载
     *  延迟加载:
     *
     */
    @Test
    @Transactional // 解决在java代码中的no session问题
    public void  testQuery3() {
        LinkMan linkMan = linkManDao.findOne(2l);
        //对象导航查询所属的客户
        Customer customer = linkMan.getCustomer();
        System.out.println(customer);
    }

    /**
     * Specification的多表查询
     */
    @Test
    public void testFind() {
        Specification<LinkMan> spec = new Specification<LinkMan>() {
            public Predicate toPredicate(Root<LinkMan> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                /**
                 * Join代表连接查询,通过root对象获取
                 * JoinType.INNER
                 * JoinType.LEFT
                 * JoinType.RIGHT
                 */
                Join<LinkMan, Customer> join = root.join("customer", JoinType.LEFT);
                return cb.like(join.get("custName").as(String.class),"百度");
            }
        };
        List<LinkMan> list = linkManDao.findAll(spec);
        for (LinkMan linkMan : list) {
            System.out.println(linkMan);
        }

        linkManDao.findOne(1l);

    }

}

POM文件

    <properties>
        <spring.version>5.0.2.RELEASE</spring.version>
        <hibernate.version>5.0.7.Final</hibernate.version>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <c3p0.version>0.9.1.2</c3p0.version>
        <mysql.version>5.1.6</mysql.version>
    </properties>

    <dependencies>
        <!-- junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- spring beg -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring对orm框架的支持包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring end -->

        <!-- hibernate beg -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <!-- hibernate end -->

        <!-- c3p0 beg -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>${c3p0.version}</version>
        </dependency>
        <!-- c3p0 end -->

        <!-- log end -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- spring data jpa 的坐标-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- el beg 使用spring data jpa 必须引入 -->
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>2.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>
        <!-- el end -->
    </dependencies>
</project>
发布了59 篇原创文章 · 获赞 1 · 访问量 744

猜你喜欢

转载自blog.csdn.net/weixin_43983411/article/details/103530350