Spring Data JPA基本增刪改查和JPQL查詢(含完整程式碼和視訊連線)

玄之不玄發表於2021-01-29
  • 問題:SpringDataJPA怎麼使用?

一、考察目標

  • 主要考核SpringDataJPA的用法

二、題目分析

spring data jpa 的使用步驟(下面有具體實現細節)

  • 1.建立maven工程並匯入依賴

  • 2.新增配置

  • 3.實體類新增註解

  • 4.編寫dao介面

  • 5.編寫測試類

三、應用場景

  • spring data jpa 是針對jpa規範中具體實現的在封裝,hibernate框架就是jpa規範的具體實現。

四、總結

主要考察的是:

  • 1.spring data jpa 的環境搭建
  • 2.spring data jpa 的常用註解
  • 3.spring data jpa 的dao編寫要求

其中spring data jpa 的使用步驟

首先看一下專案的結構

點選即可進入視訊學習網站

1.匯入依賴

  • 在pom.xml檔案匯入以下依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.itcast</groupId>
    <artifactId>jpa-day2</artifactId>
    <version>1.0-SNAPSHOT</version>

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

2.配置

  • 在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:lang="http://www.springframework.org/schema/lang"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
       http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.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.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"/>
                <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 name="password" value = "root"/>
        <property name="jdbcUrl" value="jdbc:mysql:///jpa"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    </bean>

    <!-- 3.整合 spring datajpa -->
    <jpa:repositories base-package="cn.itcast.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>

    <!-- 5。宣告式事務 -->

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

3.實體類新增註解

package cn.itcast.domain;

import javax.persistence.*;

/**
 * 客戶的實體類
 *      配置對映關係
 *              1.實體類和表的對映關係
 *              2.實體類中屬性和表中欄位的對映關係
 * @Entity:宣告實體類
 * @Table:配置實體類和表的對映關係
 *      name:配置資料庫表的名稱
 */

@Entity
@Table(name = "cst_customer")
public class Customer {

    /**
     * @Id:宣告主鍵的配置
     * @GeneratedValue:配置主鍵的生成策略
     *      strategy
     *          GenerationType.IDENTITY:自增,mysql
     *              *底層資料庫必須支援自動增長(底層資料庫支援的自動增長方式,對id自增)
     *          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;//客戶地址

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

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

4.編寫Dao介面

package cn.itcast.dao;

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

import java.util.List;

/**
 * 符合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);

    /**
     * 案列:根據客戶名稱和客戶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);

    /**
     * 使用jpql完成更新操作
     *      案例:根據id更新客戶的名稱
     *          更新4好客戶的名稱,將名稱改為“黑馬程式設計師”
     *  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);


    /**
     *使用sql的形式查詢
     *      查詢全部的客戶
     *  sql:select * from cst_customer
     *  Query:配置sql查詢
     *      value : sql語句
     *      nativeQuery : 查詢方式
     *          true:sql查詢
     *          false:jpql查詢
     * @return
     */
//    @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);

    /**
     * 方法名的約定
     *      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);
}

5.測試用例

package cn.itcast.test;

import cn.itcast.dao.CustomerDao;
import cn.itcast.domain.Customer;
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.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置資訊
public class CustomerDaoTest {
    @Autowired
    private CustomerDao customerDao;

    /**
     * 根據id查詢
     */
    @Test
    public void testFindOne(){
        Customer customer = customerDao.findOne(3L);
        System.out.println(customer);
    }

    /**
     * sava : 儲存或者更新
     *      根據傳遞的物件是否存在主鍵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(4l);
        customer.setCustName("黑馬程式設計師很厲害");
        customerDao.save(customer);
    }

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

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

    /**
     * 測試統計查詢:查詢客戶的總數量
     *          cont:統計總條數
     */
    @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);
    }

    /**
     * 根據id從資料庫查詢
     *      @Transactional:保證getOne正常執行
     *
     * findOne:
     *      em.find()           :立即載入
     * getOne:
     *      em.getReference     :延遲載入
     *      *返回的時客戶的動態代理物件
     *      *什麼時候用,什麼時候查詢
     */
    @Test
    @Transactional
    public void testGetOne() {
        Customer customer = customerDao.getOne(4l);
        System.out.println(customer);
    }
}


JPQL測試用例

package cn.itcast.test;

import cn.itcast.dao.CustomerDao;
import cn.itcast.domain.Customer;
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;

import java.util.Arrays;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置資訊
public class JpqlTest {
    @Autowired
    private CustomerDao customerDao;

    @Test
    public void testFindJPQL() {
        Customer customer = customerDao.findJpql("傳智播客");
        System.out.println(customer);
    }

    @Test
    public void testFindCustNameAndId() {
        Customer customer = customerDao.findCustNameAndId(1L, "傳智播客");
        System.out.println(customer);
    }

    /**
     * 測試jpql的更新操作
     * *springDataJpa中使用jpql完成 更新/刪除操作
     *      *需要手動新增事務的支援
     *      *預設會執行結束之後,回滾事務
     * @Rollback:設定是否自動回滾
     *      false | true
     */
    @Test
    @Transactional//新增事務的支援
    @Rollback(value = false)
    public void testUpdateCustomer() {
        customerDao.updateCustomer(4L, "黑馬程式設計師");
    }

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

    //測試方法命名規則的查詢
    @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("傳智播客%", "it教育");
        System.out.println(customer);
    }
}

如果覺得有收穫,不妨花個幾秒鐘點個贊,歡迎關注我的公眾號玩程式設計地碼農,目前專注於寫java相關、資料結構與演算法和計算機基礎等。

相關文章