GVKun编程网logo

java – Spring Data JPA更新方法(spring data jpa 更新数据)

12

如果您对java–SpringDataJPA更新方法和springdatajpa更新数据感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解java–SpringDataJPA更新方法的各种细节,并

如果您对java – Spring Data JPA更新方法spring data jpa 更新数据感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解java – Spring Data JPA更新方法的各种细节,并对spring data jpa 更新数据进行深入的分析,此外还有关于12 Spring Data JPA:springDataJpa 的运行原理以及基本操作(上)、12 Spring Data JPA:springDataJpa的运行原理以及基本操作(下)、JAVA Spring Data JPA中的动态查询代码详解、java – @PreUpdate不适用于Spring Data JPA的实用技巧。

本文目录一览:

java – Spring Data JPA更新方法(spring data jpa 更新数据)

java – Spring Data JPA更新方法(spring data jpa 更新数据)

我仍然在寻找Spring的Data JPA中的更新方法来更新在关系数据库中持久存在的给定Object.我只找到了解决方案,我不得不通过@Query注释指定某种UPDATE查询(与@Modifying相比),例如:

@Modifying
@Query("UPDATE User u SET u.firstname = ?1,u.lastname = ?2 WHERE u.id = ?3")
public void update(String firstname,String lastname,int id);

为了构建Query,我还必须传递单个参数而不是整个对象.但这正是我想做的事情(传递整个对象).

所以,我想要找到的是这样的方法:

public void update(Object obj);

是否可以基于Spring Data JPA构建这样的更新方法?它必须如何注释?

谢谢!

最佳答案
如果目标是修改实体,则不需要任何更新方法.您从数据库中获取对象,修改它,JPA自动保存它:

User u = repository.findOne(id);
u.setFirstName("new first name");
u.setLastName("new last name");

如果你有一个分离的实体并想要合并它,那么使用CrudRepository的save()方法:

User attachedUser = repository.save(detachedUser);

12 Spring Data JPA:springDataJpa 的运行原理以及基本操作(上)

12 Spring Data JPA:springDataJpa 的运行原理以及基本操作(上)

spring data jpa
day1:orm 思想和 hibernate 以及 jpa 的概述和 jpa 的基本操作

day2:springdatajpa 的运行原理

day2:springdatajpa 的基本操作

day3:多表操作,复杂查询

day2:springdatajpa 的运行原理以及基本操作 (上)


 

 第一 springDataJpa 的概述

 Spring Data JPA 让我们解脱了 DAO 层的操作,基本上所有 CRUD 都可以依赖于它来实现,在实际的工作工程中,推荐使用 Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的 ORM 框架时提供了极大的方便,同时也使数据库层操作

更加简单,方便解耦。

 SpringData Jpa 极大简化了数据库访问层代码。 如何简化的呢? 使用了 SpringDataJpa,我们的 dao 层中只需要写接口,就自动具有了增删改查、分页查询等方法。

 1.3  Spring Data JPA 与 JPA 和 hibernate 之间的关系

Spring Data JPA 是 Spring 提供的一套对 JPA 操作更加高级的封装,是在 JPA 规范下的专门用来进行数据持久化的解决方案。

JPA 是一套规范,内部是有接口和抽象类组成的。hibernate 是一套成熟的 ORM 框架,而且 Hibernate 实现了 JPA 规范,所以也可以称 hibernate 为 JPA 的一种实现方式。

 

01-springDataJpa,jpa,hibernate关系

 

 


 

 07. 入门案例

 

第二 springDataJpa的入门操作
    案例:客户的基本CRUD
    i.搭建环境
        创建工程导入坐标
        配置spring的配置文件(配置spring Data jpa的整合)
        编写实体类(Customer),使用jpa注解配置映射关系
    ii.编写一个符合springDataJpa的dao层接口
        * 只需要编写dao层接口,不需要编写dao层接口的实现类
        * dao层接口规范
            1.需要继承两个接口(JpaRepository,JpaSpecificationExecutor)
            2.需要提供响应的泛型

  入门案例用到的 method  

* 
        findOne(id) :根据id查询
        save(customer):保存或者更新(依据:传递的实体类对象中,是否包含id属性)
        delete(id) :根据id删除
        findAll() : 查询全部

  

 2.2   搭建 Spring Data JPA 的开发环境

 2.2.1     引入 Spring Data JPA 的依赖坐标

 

<properties>
        <spring.version>4.3.6.RELEASE</spring.version>
        <hibernate.version>5.3.5.Final</hibernate.version>
        <slf4j.version>1.7.12</slf4j.version>
        <log4j.version>1.2.17</log4j.version>
        <c3p0.version>0.9.1.2</c3p0.version>
        <mysql.version>8.0.17</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.9.2</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>${hibernate.version}</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.5</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>
        <!-- el end -->
    </dependencies>

 

 

 


 

spring 框架的配置文件 

applicationcontext.xml 

<?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="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--配置的扫描的包(实体类所在的包) -->
        <property name="packagesToScan" value="cn.bjut.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>

        <!--jpa的方言 :高级的特性 -->
        <property name="jpaDialect" >
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>
    </bean>

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

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

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

    <!-- 4.txAdvice-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 5.aop-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* cn.bjut.service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
    </aop:config>

    <!--5.声明式事务 -->

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

 

09 - 入门案例:创建客户实体类并配置映射关系

 

package cn.bjut.domain;

import javax.persistence.*;

/**
 * 1.实体类和表的映射关系
 *      @Eitity
 *      @Table
 * 2.类中属性和表中字段的映射关系
 *      @Id
 *      @GeneratedValue
 *      @Column
 */
@Entity
@Table(name = "cst_customer")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="cust_id")
    private Long custId;
    @Column(name="cust_address")
    private String custAddress;
    @Column(name="cust_industry")
    private String custIndustry;
    @Column(name="cust_level")
    private String custLevel;
    @Column(name="cust_name")
    private String custName;
    @Column(name="cust_phone")
    private String custPhone;
    @Column(name="cust_source")
    private String custSource;
    
    //=====下面是toString()方法和get/set方法=====//

 

 10 - 入门案例:编写符合 spring Data JPA 规范的 dao 层接口

  创建一个接口

  cn.bjut.dao.CustomerDao

  

package cn.bjut.dao;


import cn.bjut.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

/**
 * 符合SpringDataJpa的dao层接口规范
 *      JpaRepository<操作的实体类类型,实体类中主键属性的类型>
 *          * 封装了基本CRUD操作
 *      JpaSpecificationExecutor<操作的实体类类型>
 *          * 封装了复杂查询(分页)
 */
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {


}

 

然后创建一个测试类 

cn.bjut.test.CustomerDaoTest

  

@RunWith(SpringJUnit4ClassRunner.class) //声明spring提供的单元测试环境
@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息
public class CustomerDaoTest {
    @Autowired
    private CustomerDao customerDao;

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

}

 

  直接在接口中定义查询方法,如果是符合规范的,可以不用写实现,目前支持的关键字写法如下:

  

 

 

Spring Data JPA 框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。

假如创建如下的查询:findByUserDepUuid (),框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析,假设查询实体为 Doc
1:先判断 userDepUuid (根据 POJO 规范,首字母变为小写)是否为查询实体的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,继续第二步;
2:从右往左截取第一个大写字母开头的字符串此处为 Uuid),然后检查剩下的字符串是否为查询实体的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则重复第二步,继续从右往左截取;最后假设 user 为查询实体的一个属性;
3:接着处理剩下部分(DepUuid),先判断 user 所对应的类型是否有 depUuid 属性,如果有,则表示该方法最终是根据 “Doc.user.depUuid” 的取值进行查询;否则继续按照步骤 2 的规则从右往左截取,最终表示根据 “Doc.user.dep.uuid” 的值进行查询。
4: 可能会存在一种特殊情况,比如 Doc 包含一个 user 的属性,也有一个 userDep 属性,此时会存在混淆。可以明确在属性之间加上 "_" 以显式表达意图,比如 "findByUser_DepUuid ()" 或者 "findByUserDep_uuid ()"
特殊的参数: 还可以直接在方法的参数上加入分页或排序的参数,比如:
Page<UserModel> findByName(String name, Pageable pageable);
List<UserModel> findByName(String name, Sort sort);
 
也可以使用 JPA 的 NamedQueries,方法如下:
1:在实体类上使用 @NamedQuery,示例如下:
@NamedQuery(name = "UserModel.findByAge",query = "select o from UserModel o where o.age >= ?1")
2:在自己实现的 DAO 的 Repository 接口里面定义一个同名的方法,示例如下:
public List<UserModel> findByAge(int age);
3:然后就可以使用了,Spring 会先找是否有同名的 NamedQuery,如果有,那么就不会按照接口定义的方法来解析。
 
 

 

 12 - 入门案例:完成客户的添加和修改

 

/**
     * save : 保存或者更新
     *      根据传递的对象是否存在主键id,
     *      如果没有id主键属性:保存
     *      存在id主键属性,根据id查询数据,更新数据
     */
    @Test
    public void testSave() {
        Customer customer  = new Customer();
        customer.setCustName("程序员");
        customer.setCustLevel("vip");
        customer.setCustIndustry("it教育");
        customerDao.save(customer);
    }

    @Test
    public void testUpdate() {
        Customer customer  = new Customer();
        customer.setCustId(3l);
        customer.setCustName("程序员很厉害");
        customerDao.save(customer);
    }

 

 13 - 入门案例:完成客户的删除 

    @Test
    public void testDelete () {
        customerDao.delete(3l);
    }

 

 14 - 入门案例:查询所有客户 

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

 

 18 - 执行过程:执行过程已经内部处理流程的总结 

 

 

 

 

 

 

====================

未完待续。。

12 Spring Data JPA:springDataJpa的运行原理以及基本操作(下)

12 Spring Data JPA:springDataJpa的运行原理以及基本操作(下)

spring data jpa
day1:orm思想和hibernate以及jpa的概述和jpa的基本操作

day2:springdatajpa的运行原理

day2:springdatajpa的基本操作

day3:多表操作,复杂查询

day2:springdatajpa的运行原理以及基本操作 (下)


 

 环境搭建及前面的代码在: day2:springdatajpa的运行原理

    

第四 复杂查询
    i.借助接口中的定义好的方法完成查询
        findOne(id):根据id查询
    ii.jpql的查询方式
        jpql : jpa query language  (jpq查询语言)
        特点:语法或关键字和sql语句类似
            查询的是类和类中的属性
            
        * 需要将JPQL语句配置到接口方法上
            1.特有的查询:需要在dao接口上配置方法
            2.在新添加的方法上,使用注解的形式配置jpql查询语句
            3.注解 : @Query

    iii.sql语句的查询
            1.特有的查询:需要在dao接口上配置方法
            2.在新添加的方法上,使用注解的形式配置sql查询语句
            3.注解 : @Query
                value :jpql语句 | sql语句
                nativeQuery :false(使用jpql查询) | true(使用本地查询:sql查询)
                    是否使用本地查询
                    
    iiii.方法名称规则查询

 

@RunWith(SpringJUnit4ClassRunner.class) //声明spring提供的单元测试环境
@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息
public class CustomerDaoTest {
    @Autowired
    private CustomerDao customerDao;

 

19-spring Data JPA查询:调用接口方法查询(count,exists)

/**
     * 测试统计查询:查询客户的总数量
     *      count:统计总条数
     */
    @Test
    public void testCount() {
        long count = customerDao.count();//查询全部的客户数量
        System.out.println(count);
    }

    /**
     * 测试:判断id为4的客户是否存在
     *      1. 可以查询以下id为4的客户
     *          如果值为空,代表不存在,如果不为空,代表存在
     *      2. 判断数据库中id为4的客户的数量
     *          如果数量为0,代表不存在,如果大于0,代表存在
     */
    @Test
    public void  testExists() {
        boolean exists = customerDao.exists(4l);
        System.out.println("id为4的客户 是否存在:"+exists);
    }

 

20-spring Data JPA查询:调用接口方法查询(findOne和getOne的区别)

/**
     * 根据id从数据库查询
     *      @Transactional : 保证getOne正常运行
     *
     *  findOne:
     *      em.find()           :立即加载
     *  getOne:
     *      em.getReference     :延迟加载
     *      * 返回的是一个客户的动态代理对象
     *      * 什么时候用,什么时候查询
     */
    @Test
    @Transactional
    public void  testGetOne() {
        Customer customer = customerDao.getOne(2l);
        System.out.println(customer);
    }

 

 

第4章     Spring Data JPA的查询方式

4.1    使用Spring Data JPA中接口定义的方法进行查询

在继承JpaRepository,和JpaRepository接口后,我们就可以使用接口中定义的方法进行查询

 

 

 

 

 


 

 

4.2    使用JPQL的方式查询 

 21-spring Data JPA查询:JPQL查询引入

 使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询。

 

    ii.jpql的查询方式
        jpql : jpa query language  (jpq查询语言)
        特点:语法或关键字和sql语句类似
             查询的是类和类中的属性
            
        * 需要将JPQL语句配置到接口方法上
            1.特有的查询:需要在dao接口上配置方法
            2.在新添加的方法上,使用注解的形式配置jpql查询语句
            3.注解 : @Query

 

22-jpql:使用jpql完成基本查询 

package cn.bjut.dao;


import cn.bjut.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;

/**
 * 符合SpringDataJpa的dao层接口规范
 *      JpaRepository<操作的实体类类型,实体类中主键属性的类型>
 *          * 封装了基本CRUD操作
 *      JpaSpecificationExecutor<操作的实体类类型>
 *          * 封装了复杂查询(分页)
 */
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {

    /**
     * 案例:根据客户名称查询客户
     *      使用jpql的形式查询
     *  jpql:from Customer where custName = ?
     *
     *  配置jpql语句,使用的@Query注解
     */
    @Query(value="from Customer where custName = ?")
    public Customer findJpql(String custName);


}

 

 新建一个测试类  

 JpqlTest

@RunWith(SpringJUnit4ClassRunner.class) //声明spring提供的单元测试环境
@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息
public class JpqlTest {
    @Autowired
    private CustomerDao customerDao;

 

  23-jpql:多占位符的赋值 

/**
     * 案例:根据客户名称和客户id查询客户
     *      jpql: from Customer where custName = ? and custId = ?
     *
     *  对于多个占位符参数
     *      赋值的时候,默认的情况下,占位符的位置需要和方法参数中的位置保持一致
     *
     *  可以指定占位符参数的位置
     *      ? 索引的方式,指定此占位的取值来源
     */
    @Query(value = "from Customer where custName = ?2 and custId = ?1")
    public Customer findCustNameAndId(Long id,String name);

 

 24-jpql:使用jpql完成更新操作 

此外,也可以通过使用 @Query 来执行一个更新操作,为此,我们需要在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询。

  

/**
     * 使用jpql完成更新操作
     *      案例 : 根据id更新,客户的名称
     *          更新3号客户的名称,将名称改为“初级程序员”
     *
     *  sql  :update cst_customer set cust_name = ? where cust_id = ?
     *  jpql : update Customer set custName = ? where custId = ?
     *
     *  @Query : 代表的是进行查询
     *      * 声明此方法是用来进行更新操作
     *  @Modifying
     *      * 当前执行的是一个更新操作
     *
     */
    @Query(value = " update Customer set custName = ?2 where custId = ?1 ")
    @Modifying
    public void updateCustomer(long custId,String custName);
springDataJpa中使用jpql完成 更新/删除操作
需要手动添加事务的支持
默认会执行结束之后,回滚事务
/**
     * 测试jpql的更新操作
     *  * springDataJpa中使用jpql完成 更新/删除操作
     *         * 需要手动添加事务的支持
     *         * 默认会执行结束之后,回滚事务
     *   @Rollback : 设置是否自动回滚
     *          false | true
     */
    @Test
    @Transactional //添加事务的支持
    @Rollback(value = false)
    public void testUpdateCustomer() {
        customerDao.updateCustomer(3l,"初级程序员");
    }

   

 4.3  使用SQL语句查询 

    iii.sql语句的查询
            1.特有的查询:需要在dao接口上配置方法
            2.在新添加的方法上,使用注解的形式配置sql查询语句
            3.注解 : @Query
                value :jpql语句 | sql语句
                nativeQuery :false(使用jpql查询) | true(使用本地查询:sql查询)
                    是否使用本地查询

 

 25-sql查询:查询全部 

 

/**
     * 使用sql的形式查询:
     *     查询全部的客户
     *  sql : select * from cst_customer;
     *  Query : 配置sql查询
     *      value : sql语句
     *      nativeQuery : 查询方式
     *          true : sql查询
     *          false:jpql查询
     *
     */
    //@Query(value = " select * from cst_customer" ,nativeQuery = true)
    @Query(value="select * from cst_customer where cust_name like ?1",nativeQuery = true)
    public List<Object []> findSql(String name);

 

  26-sql查询:条件全部 

//测试sql查询
    @Test
    public void testFindSql() {
        List<Object[]> list = customerDao.findSql("传智播客%");
        for(Object [] obj : list) {
            System.out.println(Arrays.toString(obj));
        }
    }

 

 

4.4    方法命名规则查询

按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。

 

  具体的关键字,使用方法和生产成SQL如下表所示

  

         

Keyword

Sample

JPQL

   

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

   

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

   

Is,Equals

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

findByAgeIsNull

… 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 ages)

… where x.age in ?1

   

NotIn

findByAgeNotIn(Collection age)

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

   

 


 

 27-方法命名规则查询:基本查询 

 28-方法命名规则查询:模糊匹配

 29-方法命名规则查询:多条件查询

 

/**
     * 方法名的约定:
     *      findBy : 查询
     *            对象中的属性名(首字母大写) : 查询的条件
     *            CustName
     *            * 默认情况 : 使用 等于的方式查询
     *                  特殊的查询方式
     *
     *  findByCustName   --   根据客户名称查询
     *
     *  再springdataJpa的运行阶段
     *          会根据方法名称进行解析  findBy    from  xxx(实体类)
     *                                      属性名称      where  custName =
     *
     *      1.findBy  + 属性名称 (根据属性名称进行完成匹配的查询=)
     *      2.findBy  + 属性名称 + “查询方式(Like | isnull)”
     *          findByCustNameLike
     *      3.多条件查询
     *          findBy + 属性名 + “查询方式”   + “多条件的连接符(and|or)”  + 属性名 + “查询方式”
     */
    public Customer findByCustName(String custName);


    public List<Customer> findByCustNameLike(String custName);

    //使用客户名称模糊匹配和客户所属行业精准匹配的查询
    public Customer findByCustNameLikeAndCustIndustry(String custName,String custIndustry);

  测试类中的代码如下 

  

//测试方法命名规则的查询
    @Test
    public void testNaming() {
        Customer customer = customerDao.findByCustName("传智播客");
        System.out.println(customer);
    }


    //测试方法命名规则的查询
    @Test
    public void testFindByCustNameLike() {
        List<Customer> list = customerDao.findByCustNameLike("传智播客%");
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }


    //测试方法命名规则的查询
    @Test
    public void testFindByCustNameLikeAndCustIndustry() {
        Customer customer = customerDao.findByCustNameLikeAndCustIndustry("传智播客1%", "it教育");
        System.out.println(customer);
    }

 

 

========================

end

JAVA Spring Data JPA中的动态查询代码详解

JAVA Spring Data JPA中的动态查询代码详解

spring data jpa大大的简化了我们持久层的开发,但是实际应用中,我们还是需要动态查询的。

比如,前端有多个条件,这些条件很多都是可选的,那么后端的SQL,就应该是可以定制的,在使用hibernate的时候,可以通过判断条件来拼接SQL(HQL),当然,Spring Data JPA在简化我们开发的同时,也是提供了支持的。

通过实现Criteria二实现的动态查询,需要我们的Repo接口继承JpaSpecificationExecutor接口,这是个泛型接口。

然后查询的时候,传入动态查询参数,分页参数等即可。

使用起来很简单,不过为了知其所以然,先介绍一下Criteria API。

立即学习“Java免费学习笔记(深入)”;

Criteria API

如果编译器能够对查询执行语法正确性检查,那么对于 Java 对象而言该查询就是类型安全的。Java™Persistence API (JPA) 的 2.0 版本引入了 Criteria API,这个 API 首次将类型安全查询引入到 Java 应用程序中,并为在运行时动态地构造查询提供一种机制。本文介绍如何使用 Criteria API 和与之密切相关的 Metamodel API 编写动态的类型安全查询。

在使用Spring Data JPA的时候,只要我们的Repo层继承JpaSpecificationExecutor接口就可以使用Specification进行动态查询了,我们先看下JpaSpecificationExecutor接口:

public interface JpaSpecificationExecutor<T> { 
 T findOne(Specification<T> spec); 
 List<T> findAll(Specification<T> spec); 
 Page<T> findAll(Specification<T> spec, Pageable pageable); 
 List<T> findAll(Specification<T> spec, Sort sort); 
 long count(Specification<T> spec); 
}
登录后复制

可以看到提供了5个方法,方法的参数和返回值已经很明显的表达了其意图。其中的参数,Pageable和Sort应该是比较简单的,分别是分页参数和排序参数,而重点就是Specification参数,先看下这个接口的定义:

public interface Specification<T> { 
 Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); 
}
登录后复制

其中就一个方法,返回的是动态查询的数据结构。


javax.persistence.criteria.Predicate toPredicate(javax.persistence.criteria.Root<T> root,
javax.persistence.criteria.CriteriaQuery<?> query,
javax.persistence.criteria.CriteriaBuilder cb);
登录后复制

这里使用的都是Java EE中的规范,具体实现本人采用的是Hibernate,当然也可以选择其他实现了JPA规范的数据持久层框架。
这里需要再次回过头看看Criteria API中的一些东西:

Criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。

CriteriaQuery接口:代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用

Root接口:代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似

1:Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型。

2:查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得。

3:Criteria查询,可以有多个查询根。

4:AbstractQuery是CriteriaQuery 接口的父类,它提供得到查询根的方法。CriteriaBuilder接口:用来构建CritiaQuery的构建器对象Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合

其中支持的方法非常之强大,下面给出一个示例,大家可以参考一下,同样的,可以根据示例,自己可以写出更为复杂的查询:

Repo接口:

public interface DevHREmpConstrastDao 
 extends JpaRepository<DevHREmpConstrast, Long>,JpaSpecificationExecutor<DevHREmpConstrast>
登录后复制

查询实例1:

/** 
 * 条件查询时动态组装条件 
 */ 
private Specification<DevHREmpConstrast> where( 
  final String corg,final String name,final String type,final String date,final String checker){ 
 return new Specification<DevHREmpConstrast>() { 
  @Override 
  public Predicate toPredicate(Root<DevHREmpConstrast> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
   List<Predicate> predicates = new ArrayList<Predicate>(); 
   //机构 
   if(corg!=null&&!corg.equals("")){ 
    List<String> orgIds = organizationDao.findByName("%"+corg+"%"); 
    if(orgIds.size()>0&&orgIds.size()<1000) 
     predicates.add(root.<String>get("confirmOrgNo").in(orgIds));//confirmOrgNo 
   } 
   //名字 
   if(name!=null&&!name.equals("")){ 
    List<String> userIds = userDao.findByName(name); 
    if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
     predicates.add(root.<String>get("hrUserName").in(userIds)); 
   } 
   //类型 
   if(type!=null&&!type.equals("")) 
    predicates.add(cb.equal(root.<String>get("hrUpdateType"),type)); 
   //日期 
   if(date!=null&&!date.equals("")){ 
    //处理时间 
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 
    Date startDate; 
    Date endDate; 
    try { 
     startDate = format.parse(date); 
    } catch (ParseException e) { 
     startDate = new Date(946656000000L);//2000 01 01 
    } 
    endDate = startDate; 
    Calendar calendar = Calendar.getInstance() ; 
    calendar.setTime(endDate); 
    calendar.add(Calendar.DATE, 1); 
    endDate = calendar.getTime(); 
    calendar = null; 
    predicates.add(cb.between(root.<Date>get("insDate"),startDate,endDate)); 
   } 
   //审核人 
   if(checker!=null&&!checker.equals("")){ 
    List<String> userIds = userDao.findByName(checker); 
    if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
     predicates.add(root.<String>get("confirmUserId").in(userIds)); 
   } 
   return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); 
  } 
 }; 
}
登录后复制

查询实例2:

/** 
 * 条件查询时动态组装条件 
 */ 
 private Specification<DevHREmpConstrast> where( 
   final String corg,final String name,final String type,final String date,final String checker){ 
  return new Specification<DevHREmpConstrast>() { 
   @Override 
   public Predicate toPredicate(Root<DevHREmpConstrast> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
    List<Predicate> predicates = new ArrayList<Predicate>(); 
    //机构 
    if(corg!=null&&!corg.equals("")){ 
     List<String> orgIds = organizationDao.findByName("%"+corg+"%"); 
     if(orgIds.size()>0&&orgIds.size()<1000) 
      predicates.add(root.<String>get("confirmOrgNo").in(orgIds));//confirmOrgNo 
    } 
    //名字 
    if(name!=null&&!name.equals("")){ 
     List<String> userIds = userDao.findByName(name); 
     if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
      predicates.add(root.<String>get("hrUserName").in(userIds)); 
    } 
    //类型 
    if(type!=null&&!type.equals("")) 
     predicates.add(cb.equal(root.<String>get("hrUpdateType"),type)); 
    //日期 
    if(date!=null&&!date.equals("")){ 
     //处理时间 
     SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 
     Date startDate; 
     Date endDate; 
     try { 
      startDate = format.parse(date); 
     } catch (ParseException e) { 
      startDate = new Date(946656000000L);//2000 01 01 
     } 
     endDate = startDate; 
     Calendar calendar = Calendar.getInstance() ; 
     calendar.setTime(endDate); 
     calendar.add(Calendar.DATE, 1); 
     endDate = calendar.getTime(); 
     calendar = null; 
     predicates.add(cb.between(root.<Date>get("insDate"),startDate,endDate)); 
    } 
    //审核人 
    if(checker!=null&&!checker.equals("")){ 
     List<String> userIds = userDao.findByName(checker); 
     if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
      predicates.add(root.<String>get("confirmUserId").in(userIds)); 
    } 
    return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); 
   } 
  }; 
 }
登录后复制

然后调用dao层方法传入where()方法返回的参数即可。

以上就是JAVA Spring Data JPA中的动态查询代码详解的详细内容,更多请关注php中文网其它相关文章!

java – @PreUpdate不适用于Spring Data JPA

java – @PreUpdate不适用于Spring Data JPA

我有一个实体:

@Entity
@EntityListeners(MyEntityListener.class)
class MyEntity{ ... }

而听众:

class MyEntityListener{
    @PrePersist
    @PreUpdate
    public void doSomething(Object entity){ ... }
}

我正在为此实体(1.4.1)和EclipseLink使用Spring Data生成的DAO.代码行为如下:

MyEntity entity = new Entity();
entity = dao.save(entity); // the doSomething() is called here
// change something it the entity and save it again
dao.save(entity); // the doSomething() is NOT called here,checked with breakpoint

问题已经是described by someone in 2009,但是,他们没有提出任何解决方案.我想知道是否有人有想法如何解决它?

最佳答案
正如您所说,如果实体是从DB分离或再次获取的,则第二次调用回调方法.

我无法准确解释它,但可以想到here所描述的场景,在第二次save()调用之前没有识别脏字段,因此未调用@PreUpdate回调.或者它可能只是您的EclipseLink版本中的一个错误.

UPDATE

在JPA 2.0规范中,我发现了以下内容,这正是您的行为(3.5.2实体生命周期回调方法的语义):

Note that it is implementation-dependent as to whether PreUpdate and
PostUpdate call- backs occur when an entity is persisted and
subsequently modified in a single transaction or when an entity is
modified and subsequently removed within a single transaction.
Portable applications should not rely on such behavior.

今天关于java – Spring Data JPA更新方法spring data jpa 更新数据的分享就到这里,希望大家有所收获,若想了解更多关于12 Spring Data JPA:springDataJpa 的运行原理以及基本操作(上)、12 Spring Data JPA:springDataJpa的运行原理以及基本操作(下)、JAVA Spring Data JPA中的动态查询代码详解、java – @PreUpdate不适用于Spring Data JPA等相关知识,可以在本站进行查询。

本文标签: