Spring Data Jpa总结--查询方式、多表关系

Spring Data Jpa基本说明

操作步骤

  1. 创建实体类,建立与数据表的关联
  2. 编写一个符合Jpa规范的Dao层接口
  3. 完成CRUD操作

接口说明

  • JpaRepository<实体类类型, 主键类型>:接口中封装了一些基本的增删查改方法

在这里插入图片描述

  • JpaSpecificationExecutor<实体类类型>:完成一些复杂操作,如分页查询,可完成动态查询,即自定义查询条件

    @Test
    public void testSpec(){
          
          //查询
    
        //自定义查询条件
        Specification<Customer> spec = new Specification<Customer>() {
          
          
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
          
          
                //1. 获取比较的属性
                Path custName = root.get("custName");
                //2. 构造查询条件
                Predicate predicate = criteriaBuilder.equal(custName, "zhangsan");
                return predicate;
            }
        };
    
        Customer customer = customerDao.findOne(spec);
        System.out.println(customer);
    }
    
    @Test
    public void testLike(){
          
          //模糊查询
        Specification<Customer> spec = new Specification<Customer>() {
          
          
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
          
          
                Path custName = root.get("custName");
                Predicate like = criteriaBuilder.like(custName.as(String.class), "zhang%");
                return like;
            }
        };
        Sort sort = new Sort(Sort.Direction.DESC, "custId");
        List<Customer> customers = customerDao.findAll(spec, sort);
        for (Customer customer : customers) {
          
          
            System.out.println(customer);
        }
    }
    
    
    @Test
    public void testPage(){
          
          //分页
        Specification spec = null;
        Pageable pageable = new PageRequest(0, 2);//(页码,每页条数)
        Page<Customer> customers = customerDao.findAll(pageable);
        for (Customer customer : customers) {
          
          
            System.out.println(customer);
        }
    
        System.out.println(customers.getTotalElements());
        System.out.println(customers.getTotalPages());
        System.out.println(customers.getContent());
    }
    

开发环境搭建

导入maven依赖

<properties>
    <spring.version>4.2.4.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.9</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>

    <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>

    <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>

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/data/jpa
		http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <!--spring 和 spring data jpa 的配置-->
    <!--1. 创建entityManagerFactory对象交给spring容器管理-->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--配置扫描的包(实体类所在包)-->
        <property name="packagesToScan" value="cn.itcast.domain"/>
        <!--jpa实现厂家-->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        </property>

        <!--jpa供应商适配器-->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--是否自动创建数据表-->
                <property name="generateDdl" value="false" />
                <!--数据库类型-->
                <property name="database" value="MYSQL" />
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
                <!--是否显示SQL-->
                <property name="showSql" value="true" />
            </bean>
        </property>

        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>

        <!--注入jpa的配置信息
            auto:自动创建数据库
            create:每次重新创建数据库
            update:有表不会重新创新
        -->
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <!--2. 创建数据库连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"/>
        <property name="password" value="password"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///jpa"/>
    </bean>

    <!--3. 整合spring data jpa-->
    <jpa:repositories base-package="cn.itcast.dao" transaction-manager-ref="transactionManager"
                      entity-manager-factory-ref="entityManagerFactory"/>

    <!--4. 配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <!--5. 配置包扫描-->
    <context:component-scan base-package="cn.itcast"/>
</beans>

创建实体类

@Entity //声明实体类
@Table(name="cst_customer") //建立实体类和表的映射关系
public class Customer {
    
    
    
    @Id//声明当前私有属性为主键
    @GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略
    @Column(name="cust_id") //指定和表中cust_id字段的映射关系
    private Long custId;
    
    @Column(name="cust_name") //指定和表中cust_name字段的映射关系
    private String custName;
    
    @Column(name="cust_source")//指定和表中cust_source字段的映射关系
    private String custSource;
	......
}

Spring Data Jpa的查询方式

  • 除了使用JpaRepository等接口中定义好的方法查询外,还有以下几个查询方法

JPQL方式查询

public interface CustomerDao extends JpaRepository<Customer, Long>,JpaSpecificationExecutor<Customer> {
    
        
    //@Query 使用jpql的方式查询。
    @Query(value="from Customer")
    public List<Customer> findAllCustomer();
    
    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引
    @Query(value="from Customer where custName = ?1")
    public Customer findCustomer(String custName);
    
    @Query(value="update Customer set custName = ?1 where custId = ?2")
    @Modifying//@Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询
    public void updateCustomer(String custName,Long custId);
}

本地SQL查询

/**
     * nativeQuery : 使用本地sql的方式查询
     */
@Query(value="select * from cst_customer",nativeQuery=true)
public void findSql();

方法命名规则查询

  • 按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。
//方法命名方式查询(根据客户名称查询客户)
public Customer findByCustName(String custName);
Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is, Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull, Null findByAge(Is)Null … where x.age is null
IsNotNull, NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

多表设计

Jpa中的一对多

  • 在一对多关系中,我们习惯把一的一方称之为主表,把多的一方称之为从表。在数据库中建立一对多的关系,需要使用数据库的外键约束。

  • 外键:指的是从表中有一列,取值参照主表的主键
    在这里插入图片描述

  • 实体类关系的建立以及映射配置

    //配置客户和联系人的一对多关系,一个客户可以有多个联系人
    @OneToMany(targetEntity=LinkMan.class)
    @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
    private Set<LinkMan> linkmans = new HashSet<>();
    //getter、setter
    
    //多对一关系映射:多个联系人对应客户
    @ManyToOne(targetEntity=Customer.class)
    @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
    private Customer customer;//用它的主键,对应联系人表中的外键
    //getter、setter
    

    当建立了双向的关联关系后,先保存主表,再保存从表,会产生2条insert和1条update,而实际开发中我们只需要2条insert。

    解决方法就是"一"的一方放弃维护权。

    @OneToMany(mappedBy="customer")
    
  • 映射的注解说明

    @OneToMany:

    作用:建立一对多的关系映射

    属性:

    ​ targetEntityClass:指定多的多方的类的字节码

    ​ mappedBy:指定从表实体类中引用主表对象的名称。

    ​ cascade:指定要使用的级联操作

    ​ fetch:指定是否采用延迟加载

    ​ orphanRemoval:是否使用孤儿删除

    @ManyToOne

    作用:建立多对一的关系

    属性:

    ​ targetEntityClass:指定一的一方实体类字节码

    ​ cascade:指定要使用的级联操作

    ​ fetch:指定是否采用延迟加载

    ​ optional:关联是否可选。如果设置为false,则必须始终存在非空关系。

    @JoinColumn

    作用:用于定义主键字段和外键字段的对应关系。

    属性:

    ​ name:指定外键字段的名称

    ​ referencedColumnName:指定引用主表的主键字段名称

    ​ unique:是否唯一。默认值不唯一

    ​ nullable:是否允许为空。默认值允许。

    ​ insertable:是否允许插入。默认值允许。

    ​ updatable:是否允许更新。默认值允许。

    ​ columnDefinition:列的定义信息。

Jpa中的多对多

  • 多对多的表关系建立靠的是中间表,其中用户表和中间表的关系是一对多,角色表和中间表的关系也是一对多
    在这里插入图片描述

  • 实体类关系的建立以及映射配置

    //多对多关系映射
    //在Role类中添加
    @ManyToMany
    @JoinTable(name="user_role_rel",//中间表的名称
               //中间表user_role_rel字段关联sys_role表的主键字段role_id
               joinColumns={
          
          @JoinColumn(name="role_id",referencedColumnName="role_id")},
               //中间表user_role_rel的字段关联sys_user表的主键user_id
               inverseJoinColumns={
          
          @JoinColumn(name="user_id",referencedColumnName="user_id")}
              )
    private Set<SysUser> users = new HashSet<>();
    
    //在被动的一方要放弃维护权,避免保存中存在主键冲突的问题
    //User类
    @ManyToMany(mappedBy="users")
    private Set<SysRole> roles = new HashSet<>();
    
  • 注解说明

    @ManyToMany

    ​ 作用:用于映射多对多关系

    ​ 属性:

    ​ cascade:配置级联操作。

    ​ fetch:配置是否采用延迟加载。从一方查多方,默认延迟加载;从多方查一方,默认立即加载

    ​ targetEntity:配置目标的实体类。映射多对多的时候不用写。

    @JoinTable

    作用:针对中间表的配置

    属性:

    ​ nam:配置中间表的名称

    ​ joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段

    ​ inverseJoinColumn:中间表的外键字段关联对方表的主键字段

    @JoinColumn

    作用:用于定义主键字段和外键字段的对应关系。

    属性:

    ​ name:指定外键字段的名称

    ​ referencedColumnName:指定引用主表的主键字段名称

    ​ unique:是否唯一。默认值不唯一

    ​ nullable:是否允许为空。默认值允许。

    ​ insertable:是否允许插入。默认值允许。

    ​ updatable:是否允许更新。默认值允许。

    ​ columnDefinition:列的定义信息。

猜你喜欢

转载自blog.csdn.net/weixin_44863537/article/details/109291642