主頁 > 後端開發 > SpringBoot(15)ORM ( Object Relation Mapping )和JPA—Java持久層API

SpringBoot(15)ORM ( Object Relation Mapping )和JPA—Java持久層API

2022-07-21 07:21:56 後端開發

1.認識ORM

??ORM ( Object Relation Mapping )是物件/關系映射,它提供了概念性的、易于理解的資料模型,將資料庫中的表和記憶體中的物件建立映射關系,它是隨著面向物件的軟體開發方法的發展而產生的,面向物件的開發方法依然是當前主流的開發方法,

??物件和關系型資料是業務物體的兩種表現形式,業務物體在記憶體中表現為物件,在資料庫中表現為關系型資料,記憶體中的物件不會被永久保存,只有關系型資料庫(或NoSQL資料庫,或檔案) 中的物件會被永久保存,

??物件/關系映射(ORM)系統一般以中間件的形式存在,因為記憶體中的物件之間存在關聯和繼承關系,而在資料庫中,關系型資料無法直接表達多對多的關聯和繼承關系,物件、資料庫通過ORM 映射的關系如圖所示,

??

2.JPA

??2.1認識 Spring Data

??Spring Data是Spring的一個子專案,旨在統一和簡化各型別資料的持久化存盤方式,而不拘泥于是關系型資料庫還是NoSQL資料庫,無論是哪種持久化存盤方式,資料訪問物件(Data Access Objects, DAO)都會提供對物件的增加、洗掉、修改和查詢的方法,以及排序和分頁方法等,Spring Data 提供了基于這些層面的統一介面(如:CrudRepository、PagingAndSorting- Repository),以實作持久化的存盤,Spring Data包含多個子模塊,主要分為主模塊和社區模塊,

??1)主要模塊

  • Spring Data Commons:提供共享的基礎框架,適合各個子專案使用,支持跨資料庫持久化,
  • Spring Data JDBC:提供了對 JDBC 的支持,其中封裝了 JDBCTemplate
  • Spring Data JDBC Ext:提供了對JDBC的支持,并擴展了標準的JDBC,支持Oracle RAD、高級佇列和高級資料型別,
  • Spring Data JPA:簡化創建JPA資料訪問層和跨存盤的持久層功能,
  • Spring Data KeyValue:集成了Redis和Riak,提供多個常用場景下的簡單封裝,便于構建 key-value 模塊,
  • Spring Data LDAP:集成了 Spring Data repository 對 Spring LDAP 的支持,
  • Spring Data MongoDB:集成了對資料庫 MongoDB 支持,
  • Spring Data Redts:集成了對 Redis 的支持,
  • Spring Data REST:集成了對 RESTful 資源的支持,
  • Spring Data for Apache Cassandra :集成了對大規模、高可用資料源 Apache Cassandra 的支持,
  • Spring Data for Apace Geode:集成了對 Apache Geode 的支持,
  • Spring Data for Apache Solr:集成了對 Apache Solr 的支持
  • Spring Data for Pivotal GemFire:集成了對 Pivotal GemFire 的支持,

??(2)社區模塊

  • Spring Data Aerospike:集成了對 Aerospike 的支持
  • Spring Data ArangoDB:集成了對 ArangoDB 的支持
  • Spring Data Couchbase:集成了對 Couchbase 的支持
  • Spring Data Azure Cosmos DB:集成了對 Azure Cosmos 的支持,
  • Spring Data Cloud Datastore:集成了對 Google Datastore 的支持,
  • Spring Data Cloud Spanner:集成了對 Google Spanner 的支持,
  • Spring Data DynamoDB:集成了對 DynamoDB 的支持,
  • Spring Data Elasticsearch:集成了對搜索引擎框架 Elasticsearch 的支持,
  • Spring Data Hazelcast:集成了對 Hazelcast 的支持,
  • Spring Data Jest:集成了對基于 Jest REST client 的 Elasticsearch 的支持,
  • Spring Data Neo4j:集成了對Neo4j資料庫的支持,
  • Spring Data Vault:集成了對 Vault 的支持,

??2.2認識JPA

??JPA (Java Persistence API )是Java的持久化API,用于物件的持久化,它是一個非常強大的ORM持久化的解決方案,免去了使用JDBCTemplate開發的撰寫腳本作業,JPA通過簡單約定好介面方法的規則自動生成相應的JPQL陳述句,然后映射成POJO物件,

??JPA是一個規范化介面,封裝了Hibernate的操作作為默認實作,讓用戶不通過任何配置即可完成資料庫的操作,JPA、Spring Date和Hibernate的關系如圖所示,

??

??Hibernate 主要通過 hibernate-annotation、hibernate-entitymanager、hibernate-core 三個組件來操作資料,

  • hibernate-annotation: 是Hibernate 支持 annotation 方式配置的基礎,它包括標準的 JPA annotations、Hibernate 自身特殊功能的 annotation
  • hibernate-core:是Hibernate的核心實作,提供了 Hibernate所有的核心功能,
  • hibernate-entitymanager:實作了標準的 JPA,它是 hibernate-core 和 JPA 之間的配接器,它不直接提供ORM的功能,而是對hibernate-core 行封裝,使得Hibernate符合JPA的規范,

??可使用以下代碼來創建物體類

@Data
@Entity
public class User{
    private int id;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String name;
    private int age;
}

??對比JPA與JDBCTemplate創建物體的方式可以看出:JPA的實作方式簡單明了,不需要重寫映射(支持自定義映射),只需要設定好屬性即可,id的自増由資料庫自動管理,也可以由程式管理,其他的作業JPA自動處理好了,

??2.3使用JPA

??(1)添加JPA和MySQL資料庫的依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

??(2)配置資料庫連接資訊

 ??Spring Boot專案使用MySQL等關系型資料庫,需要配置連接資訊,可以在 application.yml檔案中進行配置,以下代碼配置了與MySQL資料庫的連接資訊:

spring:
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  jooq:
    sql-dialect: org.hibernate.dialect.Mysql5InnoDBDialect
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
    username: root
    password: 123456

??

代碼解釋如下,

  • spring.datasource.username :要填寫的資料庫用戶名,
  • spring.datasource.password :要填寫的資料庫密碼,
  • spring.jpa.show-sql= true:開發工具的控制臺是否顯示SQL陳述句,建議打開,
  • spring.jpa.properties.hibernate.hbm2ddl.auto : hibernate 的配置屬性,其主要作用 是:自動創建、更新、驗證資料庫表結構,該引數的幾種配置見下表

??

??2.4了解JPA注解和屬性

??(1)JPA的常用注解

??

??

??(2)映射關系的注解

??

??(3)映射關系的屬性

??

??

??在 Spring Data JPA 中,要控制 Session 的生命周期:否則會出現"could not initialize proxy

??[xxxx#18]-no Session”錯誤,可以在組態檔中配置以下代碼來控制Session的生命周期:

open-in-view: true
properties:
  hibernate:
    enable_lazy_load_no_trans: true

??2.5 實體:用JPA構建物體資料表

package com.itheima.domain;

import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.awt.*;
import java.io.Serializable;
import java.util.Arrays;

@Entity
@Data
public class Article implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    /**
     * Description: IDENTITY代表由資料庫控制,auto代表由Spring Boot應用程式統一控制(有多個表時,id 的自增值不一定從1開始)
     */
    private long id;
    @Column(nullable = false,unique = true)
    @NotEmpty(message = "標題不能為空")
    private String title;
    /**
     *	Description:列舉型別
     */
    @Column(columnDefinition = "enum('圖','圖文','文')")
    private String type;//型別
    /**
     *	Description: Boolean 型別默認false
     */
    private Boolean available= Boolean.FALSE;
    @Size(min = 0,max = 20)
    private String keyword;
    @Size(max = 255)
    private String description;
    @Column(nullable = false)
    private String body;
    /**
     * Description:創建虛擬欄位
     */
    @Transient
    private List keywordlists;
    public List getKeywordlists(){
        return (List) Arrays.asList(this.keyword.trim().split("|"));
    }
    public void setKeywordlists(List keywordlists) {
        this.keywordlists = keywordlists;
    }
}

 ??2.6認識JPA的介面

??JPA提供了操作資料庫的介面,在開發程序中繼承和使用這些介面,可簡化現有的持久化開發 作業,可以使Spring找到自定義介面,并生成代理類,后續可以把自定義介面注入Spring容器中進行管理,在自定義介面程序中,可以不寫相關的SQL操作,由代理類自動生成,

??(1)JPA 介面 JpaRepository

??JpaRepository 繼承自 PagingAndSortingRepository, 該介面提供了 JPA 的相關實用功能, 以及通過Example進行查詢的功能,Example物件是JPA提供用來構造查詢條件的物件,該介面的關鍵代碼如下:

??public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, Query By ExampleExecutor<T> {}

??在上述代碼中,T表示物體物件,ID表示主鍵,ID必須實作序列化,

??JpaRepository提供的方法見下表

??

??(2)分頁排序介面 PagingAndSortingRepository

??PagingAndSortingRepository繼承自CrudRepository提供的分頁和排序方法,其關鍵代碼如下:

??@NoRepositoryBean

??public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {

????lterable<T> findAll(Sort var1);

????Page<T> findAII(Pageable var1);

??}

其方法有如下兩種,

  • lterable<T> findAII(Sort sort):排序功能,它按照"sort"制定的排序回傳資料,
  • Page<T> findAII(Pageable pageable):分頁查詢(含排序功能),

??(3)資料操作介面 CrudRepository

??CrudRepository介面繼承自Repository介面,并新增了增加、洗掉、修改和查詢方法,

?? CrudRepository提供的方法見下表

??

??(4)分頁介面 Pageable 和 Page

@RequestMapping("/article")
public ModelAndView articleList(@RequestParam(value = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/start",defaultValue = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/0") Integer start,
                                @RequestParam(value = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/limit",defaultValue = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/10") Integer limit){
    start = start < 0?0:start;
    Sort sort = new Sort(Sort.Direction.DESC,"id");
    Pageable pageable = PageRequest.of(start, limit, sort);
    Page<Article> page = articleRepository.findAll(pageable);
    ModelAndView mav = new ModelAndView("admin/article/list");
    mav.addObject("page",page);
    return mav;
}

??(5)排序類Sort

??Sort類專門用來處理排序,最簡單的排序就是先傳入一個屬性列,然后根據屬性列的值進行排序,默認情況下是升序排列,它還可以根據提供的多個欄位屬性值進行排序,例如以下代碼是通過 Sort.Order物件的List集合來創建Sort物件的:

List<Sort.Order> orders = new ArrayList<Sort.Order>();
orders.add(new Sort.Order(Sort.Direction.DESC,"id"));
orders.add(new Sort.Order(Sort.Direction.ASC,"view"));
Pageable pageable = PageRequest.of(start,limit,sort);
Pageable pageable = PageRequest.of(start,limit,Sort.by(orders));

Sort排序的方法還有下面幾種:

  • 直接創建Sort物件,適合對單一屬性做排序,
  • 通過Sort.Order物件創建Sort物件,適合對單一屬性做排序,
  • 通過屬性的List集合創建Sort物件,適合對多個屬性采取同一種排序方式的排序,
  • 通過Sort.Order物件的List集合創建Sort物件,適合所有情況,比較容易設定排序方式,
  • 忽略大小寫排序,
  • 使用JpaSort.unsafe進行排序,
  • 使用聚合函式進行排序,

3.JPA的查詢方式

??3.1使用約定方法名

??約定方法名一定要根據命名規范來寫,Spring Data會根據前綴、中間連接詞(Or、And、Like、NotNull等類似SQL中的關鍵詞)、內部拼接SQL代理生成方法的實作,約定方法名的方法見下表

??

??介面方法的命名規則也很簡單,只要明白And、Or、Is、Equal、Greater、StartingWith等英文單詞的含義,就可以寫介面方法,具體用法如下:

package com.itheima.domain;
import org.springframework.data.repository.Repository;
import java.util.List;
public interface UserRepository extends Repository<User,Long> {
    List<User> findByEmailOrName(String email,String name);
}

上述代碼表示,通過email或name來查找User物件,

約定方法名還可以支持以下幾種語法:

  • User findFirstByOrderByNameAsc()
  • Page<User> queryFirst100ByName(String name, Pageable pageable) 
  • Slice<User> findTop100ByName(String name, Pageable pageable)
  • List<User> findFirst100ByName(String name, Sort sort)
  • List<User> findTop100ByName(String name, Pageable pageable) 

??3.2用JPQL進行查詢

??JPQL語言(Java Persistence Query Language)是一種和SQL非常類似的中間性和物件化查詢語言,它最侄訓被編譯成針對不同底層資料庫的SQL語言,從而屏蔽不同資料庫的差異,

??JPQL語言通過Query介面封裝執行,Query介面封裝了執行資料庫查詢的相關方法,呼叫 EntityManager的Query、NamedQuery及NativeQuery方法可以獲得查詢物件,進而可呼叫 Query介面的相關方法來執行查詢操作,

??JPQL是面向物件進行查詢的語言,可以通過自定義的JPQL完成UPDATE和DELETE操作,JPQL不支持使用INSERT,對于UPDATE或DELETE操作,必須使用注解@Modifying 進行修飾,

??(1)下面代碼表示根據name值進行查找

public interface UserRepository extends JpaRepository<User,Long> {
    @Query("select u from User u where u.name = ?1")
    User findByName(String name);
}

??(2)下面代碼表示根據name值逬行模糊查找

public interface UserRepository extends JpaRepository<User,Long> {
    @Query("select u from User u where u.name like %?1")
    List<User> findByName(String name);
}

??3.3用原生SQL進行查詢

??1)根據ID查詢用戶

@Override
@Query(value = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/select * from user u where u.id = :id", nativeQuery = true)
Optional<User> findById(@Param("id") Long id);

??(2)查詢所有用戶

@Query(value = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/select * from user", nativeQuery = true)
List<User> findAllNative();

??(3)根據email查詢用戶

@Query(value = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/select * from user where email = ?1", nativeQuery = true)
User findByEmail(String email);

??(4)根據name查詢用戶,并回傳分頁物件Page

@Query(value = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/select * from user where name = ?1",
    countQuery = "select count(*) from user where name = ?1",
    nativeQuery = true)
Page<User> findByName(String name, Pageable pageable);

??(5)根據名字來修改email的值

@Modifying
@Query("update user set email = :email where name = :name")
Void updateUserEmaliByName(@Param("name") String name,@Param("email") String email);

??3.4 用 Specifications 進行查詢

??如果要使 Repository 支持 Specification 查詢,則需要在 Repository 中繼承 JpaSpecification- Executor介面,具體使用見如下代碼:

package com.itheima.executor;
import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.junit4.SpringRunner;
import javax.persistence.criteria.*;
@SpringBootTest
@RunWith(SpringRunner.class)
public class testJpaSpecificationExecutor {
    @Autowired
    private ArticleRepository articleRepository;
    @Test
    public void testJpaSpecificationExecutor(){
        int pageNo = 0;
        int pageSize = 5;
        PageRequest pageable = PageRequest.of(pageNo,pageSize);
        Specification<Article> specification = new Specification<Article>(){
            @Override
            public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path path = root.get("id");
                Predicate predicate1 = criteriaBuilder.gt(path,2);
                Predicate predicate2 = criteriaBuilder.equal(root.get("num"),42283);
                Predicate predicate = criteriaBuilder.and(predicate1,predicate2);
                return predicate;
            }
        };
        Page<Article> page = articleRepository.findAll(specification,pageable);
        System.out.println("總記錄數:"+page.getTotalElements());
        System.out.println("當前第:"+(page.getNumber()+1)+"頁");
        System.out.println("總頁數:"+page.getTotalPages());
        System.out.println("當前頁面的List:"+page.getContent());
        System.out.println("當前頁面的記錄數:"+page.getNumberOfElements());
    }
}

??

代碼解釋如下,

  • CriteriaQuery介面: specific的頂層查詢物件,它包含查詢的各個部分,比如,select、from、 where、group by、order by等,CriteriaQuery物件只對物體型別或嵌入式型別的Criteria 查詢起作用,
  • root:代表查詢的物體類是Criteria查詢的根物件,Criteria查詢的根定義了物體型別,能為將來的導航獲得想要的結果,它與SQL查詢中的From子句類似,Root實體是型別化的, 且規定了 From子句中能夠出現的型別,查詢根實體通過傳入一個物體型別給 AbstractQuery.from 方法獲得,
  • query:可以從中得到Root物件,即告知JPA Criteria查詢要查詢哪一個物體類,還可以添加查詢條件,并結合EntityManager物件得到最終查詢的TypedQuery物件,
  • CriteriaBuilder物件:用于創建Criteria相關物件的工廠,可以從中獲取到Predicate 物件,
  • Predicate型別:代表一個查詢條件,

運行上面的測驗代碼,在控制臺會輸出如下結果(確保資料庫己經存在資料):

Hibernate: select card0_.id as id1_0_, card0_.num as num2_0_ from card card0_ where card0_.id>2 and card0_.num=422803 limit ?
Hibernate: select count(cardO_.id) as col_0_0_ from card card0_ where cardO_Jd>2 and card0_.num=422803 
總記錄數:6
當前第:1頁 總頁數:2 當前頁面的 List: 
[Card(id=4, num二422803), Card(id=8, num=422803), Card(id=10, num=422803), Card(id=20t num=422803), Card(id=23, num=422803)] 
當前頁面的記錄數:5

??3.5 用 ExampleMatcher 進行查詢

??Spring Data可以通過Example物件來構造JPQL查詢,具體用法見以下代碼:

??

User user = new User();
user.setName("test");
ExampleMatcher matcher = ExampleMatcher.matching()
        .withIgnorePaths("name")
        .withIncludeNullValues()
        .withStringMatcher(ExampleMatcher.StringMatcher.ENDING);
Example<User> example = Example.of(user,matcher);
List<User> list = userRepository.findAll(example);

??3.6 用謂語QueryDSL進行查詢

??QueryDSL也是基于各種ORM之上的一個通用查詢框架,它與Spring Data JPA是同級別的, 使用QueryDSL的API可以寫岀SQL陳述句(Java代碼,非真正標準SQL),不需要懂SQL陳述句, 它能夠構建型別安全的查詢,這與JPA使用原生查詢時有很大的不同,可以不必再對“Object[]' 進行操作,它還可以和JPA聯合使用,

4.用JPA開發文章管理模塊

??4.1實作文章物體

@Entity
@Data
public class Article extends BaseEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column(nullable = false,unique = true)
    @NotEmpty(message = "標題不能為空")
    private String title;
    @Column(nullable = false)
    private String body;
}

代碼解釋如下:

  • @Entity:宣告它是個物體,然后加入了注解@Data, @Data是Lombok插件提供的注解, 以簡化代碼,自動生成Getter、Setter方法,文章的屬性欄位一般包含id、title、keyword、body,以及發布時間、更新時間、處理人,這里只簡化設定文章id、關鍵詞、標題和內容,
  • @GeneratedValue:將 id 作為主鍵,GenerationType 為“identity”,代表由資料庫統 一控制id的自增,如果屬性為“auto",則是Spring Boot控制id的自增,使用identity 的好處是,通過資料庫來管理表的主鍵的自增,不會影響到其他表
  • nullable = false, unique = true:建立唯一索引,避免重復,
  • @NotEmpty(message ="標題不能為空”):作為提示和驗證訊息,

??4.2 實作資料持久層

@Service
public interface ArticleRepository extends JpaRepository<Article,Long>,
        JpaSpecificationExecutor<Article>{
    Article findById(long id);
}

??4.3 通過創建服務介面和服務介面的實作類來完成業務邏輯功能

??(1)創建服務介面,見以下代碼

public interface ArticleService {
    public List<Article> getArticleList();
    public Article findArticleById(long id);
}

??(2)撰寫服務介面的實作

??在impl包下,新建article的impl實作service,并標注這個類為service服務類,

??通過implements宣告使用ArticleService介面,并重寫其方法,見以下代碼:

@Service
public class ArticleServiceImpl implements ArticleService{
    @Autowired
    private ArticleRepository articleRepository;
    @Override
    public List<Article> getArticleList() {
        return articleRepository.findAll();
    }
    @Override
    public Article findArticleById(long id) {
        return articleRepository.findById(id);
    }
}

??(3)實作增加、洗掉、修改和查詢的控制層API功能

package com.itheima.controller;

import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("article")
public class ArticleController {
    @Autowired
    private ArticleRepository articleRepository;
    @RequestMapping("")
    public ModelAndView articlelist(@RequestParam(value = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/start",defaultValue = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/0")Integer start,
                                    @RequestParam(value = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/limit",defaultValue = "https://www.cnblogs.com/liwenruo/archive/2022/07/20/5")Integer limit) {
        start = start < 0 ? 0 : start;
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        Pageable pageable = PageRequest.of(start, limit, sort);
        Page<Article> page = articleRepository.findAll(pageable);
        ModelAndView mav = new ModelAndView("article/list");
        mav.addObject("page", page);
        return mav;
    }
    @GetMapping("/{id}")
    public ModelAndView getArticle(@PathVariable("id") long id) {
        Article article = articleRepository.findById(id);
        ModelAndView mav = new ModelAndView("article/show");
        mav.addObject("article", article);
        return mav;
    }
    @GetMapping("/add")
    public String addArticle(){
        return "article/add";
    }
    @PostMapping("")
    public String saveArticle(Article model){
        articleRepository.save(model);
        return "redirect:/article/";
    }
    @DeleteMapping("/{id}")
    public String deleteArticle(@PathVariable("id") long id){
        articleRepository.deleteById(id);
        return "redirect:";
    }
    @GetMapping("/edit/{id}")
    public ModelAndView editArticle(@PathVariable("id") long id) {
        Article model = articleRepository.findById(id);
        ModelAndView mav = new ModelAndView("article/edit");
        mav.addObject("article", model);
        return mav;
    }
    @PutMapping("/{id}")
    public String editArticleSave(Article model,long id){
        model.setId(id);
        articleRepository.save(model);
        return "redirect:";
    }
}

5.實作自動填充欄位

??在操作物體類時,通常需要記錄創建時間和更新時間,如果每個物件的新增或修改都用手工來操作,則會顯得比較煩瑣,這時可以使用Spring Data JPA的注解@EnableJpaAuditing來實作自動填充欄位功能,具體步驟如下,

??(1)開啟JPA的審計功能

??通過在入口類中加上注解@EnableJpaAuditing,來開啟JPA的Auditing功能

??(2)創建基類

@Data
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
    @CreatedDate
    private Long createTime;     //createTime
    @LastModifiedDate
    private Long updateTime;     //updateTime
    @Column(name = "create_by")
    @CreatedBy
    private Long createBy; //createBy
    @Column(name = "lastmodified_by")
    @LastModifiedBy
    private Long lastModifiedBy; //lastModifiedBy
}

??(3)賦值給 CreatedBy 和 LastModifiedBy

??上述代碼已經自動實作了創建和更新時間賦值,但是創建人和最后修改人并沒有賦值,所以需要實作"AuditorAware"介面來回傳需要插入的值

public class InjectAuditor implements AuditorAware<String> {
    //給 Bean 中的 @CreatedBy @LastModifiedBy 注入操作人
    @Override
    public Optional<String> getCurrentAuditor() {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        if (securityContext==null) {
            return null;
        }
        if (securityContext.getAuthentication()==null) {
            return null;
        }else {
            String loginUserName = securityContext.getAuthentication().getName();
            Optional<String> name = Optional.ofNullable(loginUserName);
            return name;
        }
    }
}

??代碼解釋如下,

??@Configuration:表示此類是配置類,讓Spring來加我該類配置,

 ??SecurityContextHolder:用于獲取 SecurityContext,其存放了 Authentication 和特定于請求的安全資訊,這里是判斷用戶是否登錄,如果用戶登錄成功,則荻取用戶名,然后把用戶名回傳給操作人,

??(4)使用基類

??要在其他類中使用基類,通過在其他類中繼承即可

6.關系映射開發

??6.1認識物體間關系映射

????物件關系映射(object relational mapping )是指通過將物件狀態映射到資料庫列'來開發和 維護物件和關系資料庫之間的關系,它能夠輕松處理(執行)各種資料庫操作,如插入、更新、 洗掉等

??(1)映射方向

???ORM的映射方向是表與表的關聯(join ),可分為兩種,

  • 單向關系:代表一個物體可以將屬性參考到另一個物體,即只能從A表向B表進行聯表查詢,
  • 雙向關系:代表每個物體都有一個關系欄位(屬性)參考了其他物體,

??(2)ORM映射型別

  • 一對一 (@OneToOne):物體的每個實體與另一個物體的單個實體相關聯,
  • 一對多(@OneToMany): 一個物體的實體可以與另一個物體的多個實體相關聯,
  • 多對一(@ManyToOne): 一個物體的多個實體可以與另一個物體的單個實體相關聯,
  • 多對多(@ManyToMany):—個物體的多個實體可能與另一個物體的多個實體有關,在 這個映射中,任何一方都可以成為所有者方,

??

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/499851.html

標籤:其他

上一篇:泛型通配符?(問號)簡介說明

下一篇:golang拾遺:自定義型別和方法集

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more