1. 程式人生 > 實用技巧 >SpringBoot入門(三)——SpringData JPA

SpringBoot入門(三)——SpringData JPA

iwehdio的部落格園:https://www.cnblogs.com/iwehdio/

1、JPA

  • ORM:物件關係對映。

    • 主要目的:操作實體類就相當於操作資料庫表。
    • 需要對映關係:
      • 建立實體類和表的關係。
      • 建立實體類中屬性和表中欄位的關係。
    • 不需要再重點關注sql語句。
  • JPA規範:

    • ORM框架的規範,內部由介面和抽象類組成。
    • 使用一些註解表示對映方式
    • 類比JDBC:
      • MySQL驅動和Oracle驅動都實現了JDBC規範。
      • 實現了JDBC的介面,更換資料庫Java程式碼不需要改變。
    • 優勢:標準化、容器級特性的支援、簡單方便、查詢能力、高階特性。
  • 搭建環境的過程:

    • 匯入maven座標。

    • 配置JPA核心配置檔案:

      • 需要配置到類路徑下的 META-INF 資料夾下。
      • 命名為 persistence.xml。
      <?xml version="1.0" encoding="UTF-8"?>
      <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
          <!--持久化單元:
          name持久化單元名稱;
          transaction-type:事務管理的方式。RESOURCE_LOCAL本地事務管理;JTA:分散式事務管理-->
          <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
      
              <!--  jpa的實現方式  -->
              <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
              <properties>
                  <!-- 資料庫資訊-->
                  <property name="javax.persistence.jdbc.user" value="root"/>
                  <property name="javax.persistence.jdbc.password" value="root"/>
                  <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
                  <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
                  <!-- 可選配置:配置JPA實現方式(Hibernate)的配置 -->
                  <!-- 顯示sql(true,flase);自動建立資料庫表(create,update,none) -->
                  <property name="hibernate.show_sql" value="true"/>
                  <property name="hibernate.hbm2ddl.auto" value="update"/>
              </properties>
          </persistence-unit>
      
      </persistence>
      
    • 編寫客戶的實體類。

    • 用JPA註解配置實體類和表、類中屬性和表中欄位的對映。

      • 實體類和表的對映:
        • 實體類上宣告@Entity該類是一個實體類。
        • 對映關係@Table(name="資料庫表名")
      • 類中屬性和表中欄位的對映:
        • 主鍵對應的屬性上加@Id
        • 主鍵如果是自增的,還需要加@GeneratedValue(strategy = GenerationType.IDENTITY)
        • 指定資料庫表中的欄位@Column(name = "表中欄位")
        • 普通屬性只需要加@Column
      @Entity
      @Table(name = "cst_customer")
      public class Customer {
          @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;
      }
      
    • JPA的操作步驟(儲存一個客戶到資料庫):

      • 載入配置檔案,建立實體管理器工廠物件。
      • 通過工廠獲取實體管理器。
      • 獲取事務物件,開啟事務。
      • 完成增刪改查操作。
      • 提交/回滾事務。釋放資源。
      @Test
      public void testSave() {
      	EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
          EntityManager entityManager = factory.createEntityManager();
          EntityTransaction transaction = entityManager.getTransaction();
          transaction.begin();
          Customer customer = new Customer();
          customer.setCustName("iwehdio");
          customer.setCustIndustry("java");
          entityManager.persist(customer);
          transaction.commit();
          entityManager.close();
          factory.close();
      }
      
    • entityManager.persist()方法:儲存物件,傳入一個實體類物件。

  • API物件:

    • Persistence的靜態方法createEntityManagerFactory:根據持久化單元名稱建立實體管理器工廠EntityManagerFactory。
    • 實體管理器工廠EntityManagerFactory:建立實體管理器EntityManager。
      • EntityManagerFactory內部維護了資料庫資訊、快取資訊、實體管理器物件等。
      • 建立過程比較浪費資源。
      • 是執行緒安全的訪問物件。
      • 可以建立一個公共的實體管理器工程,藉助靜態程式碼塊的形式。
    • EntityManager實體類管理器物件:getTransaction建立事務物件EntityTransaction。
      • EntityManager實體類管理器物件是真正與資料庫進行操作的物件。
      • presist儲存、merge更新、remove刪除、find/getReference根據id查詢。
    • EntityTransaction事務物件:開啟、提交、回滾。
  • 主鍵生成策略:

    • 使用註解@GenratedValue
    • 自增:GenerationType.INDENTITY,前提是底層資料庫支援自動增長方式,對id自增(MySQL)。
    • 序列:GenerationType.SEQUENCE,前提是底層資料庫支援序列(Oracle)。
    • JPA提供的機制,通過一張資料庫表的形式完成主鍵自增:GenerationType.TABLE
    • 程式自動選擇主鍵生成測量:GenerationType.AUTO
  • 抽取JpaUtils:

    public class JapUtils {
        private static EntityManagerFactory factory;
        static {
            //載入配置檔案,建立實體管理器工廠
            factory = Persistence.createEntityManagerFactory("myJpa");
        }
        //獲取實體管理器工廠的方法
        public static EntityManager getEntityManager() {
            return factory.createEntityManager();
        }
    }
    
    • 第一次訪問,靜態程式碼塊建立工廠物件,在呼叫方法建立管理器物件。
  • 根據id查詢客戶:

    • entityManager.find()方法:第一個引數是查詢資料的結果需要封裝的實體類物件的位元組碼,第二個的主鍵的取值。

      @Test
      public void testfind() {
          EntityManager entityManager = JpaUtils.getEntityManager();
          EntityTransaction transaction = entityManager.getTransaction();
          transaction.begin();
          Customer customer = entityManager.find(Customer.class, 1L);
          System.out.println(customer);
          transaction.commit();
          entityManager.close();
      }
      
    • entityManager.getReference():與find類似,也是查詢方法,引數相同。

    • find方法查詢的物件就是當前客戶物件本身,在呼叫find方法時就傳送SQL語句查詢,也就是立即載入。

    • 而getReference方法查詢的物件是客戶物件的動態代理物件,呼叫getReference方法不會立即傳送SQL語句查詢。在呼叫查詢物件時,才傳送SQL語句,也就是延遲載入。

  • 刪除客戶:

    • entityManager.remove()方法:傳入的引數是一個物件。
    • 需要先根據id查詢,再將查到的物件傳入remove方法。
  • 更新客戶:

    • entityManager.merge()方法:傳入的引數是一個物件。
    • 需要先根據id查詢,再將查到的物件更新資料後傳入merge方法。
  • jpql查詢:

    • JPA查詢語句,查詢的是實體類和類中的屬性,與SQL語句語法相似。

    • 查詢步驟:

      • 根據jpql語句建立Query物件。
      • 對引數賦值。
      • 傳送查詢,封裝結果。
    • 查詢全部:

      • jpql="from Customer"語句:查詢所有。支援簡寫也支援全類名。
      • entityManager.createQuery(jpql)方法:建立Query查詢物件,是執行jpql的物件。
      • query.getResultList()方法:傳送查詢,並封裝結果集為List。
      String jpql = "from Customer";
      Query query = entityManager.createQuery(jpql);
      List resultList = query.getResultList();
      for(Object object :resultList) {
          System.out.println(object);
      }
      
    • 根據id倒序查詢:

      • jpql = "from Customer order by custId desc "語句:倒序查詢所有。
    • 統計查詢:

      • jpql = "select count(custId) from Customer"語句:統計客戶總數。
      • query.getSingleResult()方法:傳送查詢,獲取單個結果。
    • 分頁查詢:

      • jpql語句還是查詢所有。
      • query.setFirstResult()方法:分頁查詢的起始頁碼。
      • query.setMaxResults()方法:分頁查詢的每頁條數。
    • 條件查詢:

      • jpql = "from Customer where custName like ?"語句:對名字進行模糊查詢。
      • query.setParameter()方法:設定佔位符,第一個是佔位符索引從1開始,第二個是佔位符的值。

2、SpringData JPA

  • Spring基於ORM框架、JPA規範基礎上封裝的JPA應用框架,擺脫了DAO層的操作。

  • 環境搭建:

    • 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>
      
    • 配置Spring配置檔案:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans> 
          <!-- 1.dataSource 配置資料庫連線池-->
          <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
              <property name="driverClass" value="com.mysql.jdbc.Driver" />
              <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/jpa" />
              <property name="user" value="root" />
              <property name="password" value="root" />
          </bean>
      
          <!-- 2.配置entityManagerFactory -->
          <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
              <property name="dataSource" ref="dataSource" />
              <!-- 配置掃描的實體類所在的包-->
              <property name="packagesToScan" value="cn.iwehdio.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>
      
      
          <!-- 3.事務管理器-->
          <!-- JPA事務管理器,配置實體管理器工廠  -->
          <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
              <property name="entityManagerFactory" ref="entityManagerFactory" />
          </bean>
      
          <!-- 整合spring data jpa,配置dao介面包、事務和實體管理器工廠-->
          <jpa:repositories base-package="cn.iwehdio.dao"
                            transaction-manager-ref="transactionManager"
                            entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
      
          <!-- 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.iwehdio.service.*.*(..))" />
              <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
          </aop:config>
          <!-- 配置包掃描註解   -->
          <context:component-scan base-package="cn.iwehdio"></context:component-scan>
      
      </beans>
      
    • 編寫實體類,使用jpa註解配置對映關係。

  • 編寫dao介面:

    • 符合SpringData JPA的介面規範:

      • 繼承介面JpaRepositoryJpaSpecificationExecutor
      • 需要提供相應的泛型。
        • 介面JpaRepository
          • 第一個泛型:操作的實體類型別。
          • 第二個泛型:實體類中主鍵屬性的型別。
          • 封裝了基本CRUD操作。
        • 介面JpaSpecificationExecutor
          • 泛型:操作的實體類型別。
          • 封裝了複雜查詢。
      public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {
      }
      
    • 測試:

      • 測試環境:根據主鍵查詢一個。

        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations = "classpath:applicationContext.xml")
        public class DaoTest {
        
            @Autowired
            private CustomerDao customerDao;
        
            @Test
            public void test1() {
                Customer one = customerDao.findOne(2L);
                System.out.println(one);
            }
        }
        
      • findOne()方法:根據主鍵查詢一個。

      • save()方法:儲存或更新。如果傳入的物件存在主鍵,則為更新;沒有主鍵,則為儲存。

      • delete()方法:根據主鍵刪除。

      • findAll()方法:查詢所有。

  • SpringData JPA執行過程:

    • 真正發揮作用的介面的實現類,在程式執行過程中,自動幫助我們動態生成了介面的實現類物件。
    • 通過動態代理,可以生成基於介面的實現類物件。
    • 最終是呼叫JPA的實體管理器進行操作。
    • 執行流程:
      • 通過JDKDynamicAopProxy的invoke方法建立動態代理物件SimpleJpaRepository。
      • SimpleJpaRepository實現了之前dao中繼承的兩個介面JpaRepository和JpaSpecificationExecutor。
      • 通過entityManager完成操作。
      • JPA規範呼叫hibernate封裝的jdbc操作資料庫。
    • 配置檔案中<jpa:repositories base-package=“”> 指定對此包下的dao介面進行動態代理增強。
  • 查詢操作:

    • 藉助介面中定義好的方法:

      • count()方法:查詢總數量。
      • exists()方法:傳入主鍵,判斷是否存在此條記錄。是通過查詢count實現的。
      • getOne()方法:根據主鍵從資料庫查詢。
        • 單元測試需要加上事務支援@Transactional
        • 是延遲載入。
    • 支援jpql的查詢方式:

      • 需要將jpql語句使用註解@Query的形式,配置到介面方法上。

      • 按名稱查詢:

        @Query(value = "from Customer where custName = ?")
        public Customer findByName(String custName);
        
      • 按名稱的主鍵id查詢:

        @Query(value = "from Customer where custName=? and custId=?")
        public Customer findByNameAndId(String name, Long id);
        
      • 多個引數傳入,預設情況下jpql語句中的佔位符賦值順序與方法的引數列表一致。

      • 也可以指定順序,在jpql語句中使用?索引。索引就是方法引數列表中的順序,從1開始。

    • 支援jpql的更新方式:

      • 使用註解@Modifying表示當前是一個更新方法。

      • 進行更新或刪除操作,需要事務支援。但是預設會回滾事務,需要加上@Rollback(value=false)

      • 按主鍵id更新名稱:

        @Query(value = "update Customer set custName=?2 where custId=?1")
        @Modifying
        public void updateName(Long id, String name);
        
    • 支援sql的查詢方式:

      • 使用註解@Query,使用屬性nativeQuery指定哪種語句。true為本地查詢表示使用sql,false(預設)表示使用jpql。

      • 查詢所有:

        @Query(value = "select * from cst_customer", nativeQuery = true)
        public List<Customer> findAllAsSQL();
        
      • 多個引數的賦值方式與jpql相同。

    • 方法名稱規則查詢:

      • 是對jpql更加深入的一層封裝,只需要按照SpringData JPA提供的方法名稱規則定義方法,不需要配置查詢語句即可完成查詢。

      • 方法命名規則:

        • findBy開頭的表示查詢:

          • 之後為物件中的屬性名(首字母大寫),表示查詢的條件。

          • findByCustName表示根據客戶名稱查詢。

            public Customer findByCustName(String name);
            
          • 在之後可再加查詢方式,比如Like。

            public List<Customer> findByCustNameLike(String name);
            
          • 多條件查詢findBy+屬性名+查詢方式+條件連線符(Or或者And)+其他屬性查詢。

3、複雜操作

  • specificaions 動態查詢:

    • 通過JpaSpecificationExcutor介面中的方法進行查詢。

    • 所有方法都需要傳入引數Specification<T> spec作為查詢條件。

      • 是一個用於描述條件的介面。提供泛型,就是查詢的物件型別。
      • 在查詢時需要自定義實現類,實現toPredicate()方法封裝查詢條件。包括三個引數:
        • root:查詢的根物件,查詢的任何屬性都可以從根物件中獲取。
        • CriteriaQuery:頂層查詢物件,一般不用。
        • CriteriaBuilder:查詢的構造器,內部封裝了許多查詢條件。
    • 查詢條件:

      • 查詢方式:在CriteriaBuilder中。
      • 比較的屬性名稱:在root中。
      • root.get("屬性名")獲取比較的屬性。
    • 動態查詢:

      • 根據客戶名稱查詢:

        • criteriaBuilder.equal()方法:第一個引數需要比較的屬性,第二個引數屬性的取值。

          @Test
          public void testfindOne() {
              //匿名內部類
              Specification<Customer> spec = new Specification<Customer>() {
                  @Override
                  public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                      //1、獲取比較的屬性(使用實體類中的屬性名)
                      Path<Object> custName = root.get("custName");
                      //2、構造查詢條件
                      Predicate predicate = criteriaBuilder.equal(custName, "iwehdio");
                      return predicate;
                  }
              };
              Customer customer = customerDao.findOne(spec);
              System.out.println(customer);
          }
          
      • 多條件拼接:根據名稱和行業查詢。

        • 分別構造名稱和行業的查詢,然後將兩個查詢聯絡起來。

        • 將多個查詢條件進行組合:criteriaBuilder.and()方法或criteriaBuilder.or()方法,傳入多個查詢條件。

          @Test
          public void testmulti() {
              Specification<Customer> spec = new Specification<Customer>() {
                  @Override
                  public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                      Path<Object> custName = root.get("custName");
                      Path<Object> custIndustry = root.get("custIndustry");
                      Predicate predicate1 = criteriaBuilder.equal(custName, "iwehdio");
                      Predicate predicate2 = criteriaBuilder.equal(custIndustry, "a");
                      Predicate and = criteriaBuilder.and(predicate1, predicate2);
                      return and;
                  }
              };
              Customer customer = customerDao.findOne(spec);
              System.out.println(customer);
          }
          
      • 模糊查詢:

        • criteriaBuilder.like()方法:模糊查詢。除了equal方法以外,都還需要使用path.as(.class)傳入比較的引數型別。

          @Test
          public void testlike() {
              Specification<Customer> spec = new Specification<Customer>() {
                  @Override
                  public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                      Path<Object> custName = root.get("custName");
                      Predicate predicate = criteriaBuilder.like(custName.as(String.class), "iwe%");
                      return predicate;
                  }
              };
              List<Customer> all = customerDao.findAll(spec);
              System.out.println(all);
          }
          
      • 指定資料順序:

        • 新增排序Sort物件。

        • 建立排序物件Sort,構造方法傳入引數。第一個引數傳入升序還是降序,第二個引數是排序的屬性名稱。

          Sort sort = new Sort(Sort.Direction.DESC, "custId");
          List<Customer> all = customerDao.findAll(spec, sort);
          
      • 分頁查詢:

        • 新增分頁引數Pageable物件,返回Page分頁物件。

        • 建立分頁引數物件PageRequest,構造方法傳入引數。第一個引數當前查詢的頁數(從0開始),第二個引數每頁查詢的數量。

          @Test
          public void testpage() {
              Specification<Customer> spec = null;
              Pageable pageable = new PageRequest(0, 2);
              Page<Customer> all = customerDao.findAll(spec, pageable);
              System.out.println(all.getContent());
          
          }
          
        • .getContent()方法:得到資料列表。

  • 多表關係:

    • 可以通過實體類中的包含關係,描述表關係。

    • 步驟:

      • 通過外來鍵和中間表確定表關係,
      • 編寫實體類,在實體類中用包含關係描述表關係。
      • 配置對映關係。
    • 一對多操作:

      • 客戶到聯絡人的一對多關係:

        • 宣告關係:@OneToMany註解,targetEntity 指定對方物件的位元組碼。

        • 配置外來鍵:@JoinColumn註解,name指定外來鍵欄位名稱,referencedColumnName指定參照的主表的主鍵欄位名稱。

          @OneToMany(targetEntity = LinkMan.class)
          @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
          private Set<LinkMan> linkMans = new HashSet<>();
          
      • 聯絡人到客戶的多對一關係:

        @ManyToOne(targetEntity = Customer.class)
        @JoinColumn(name = "lkm_cust_id", referencedColumnName = "cust_id")
        private Customer customer;
        
        • 配置聯絡人的實體類和Dao介面。
      • 在一的一方放棄外來鍵維護:

        @OneToMany(mappedBy = "customer")
        private Set<LinkMan> linkMans = new HashSet<>();
        
        • 指定外來鍵中,對方配置關係的屬性名稱。
      • 刪除操作:

        • 刪除從表資料,可以隨時任意刪除。
        • 刪除主表資料:
          • 有從表資料的話:
            • 預設情況下,將外來鍵置為null,刪除主表資料。
            • 如果一的一方放棄了外來鍵維護,則不能刪除。
            • 如果還要刪除,需要使用級聯刪除引用。
          • 沒有從表資料引用,隨便刪除。
        • 級聯操作:
          • 需要區分操作主體。
          • 需要在操作主體的實體類上,新增級聯屬性,使用@OneToMany(cascade=)配置級聯。
          • 可選值包括:ALL所有,MERGE更新,PERSIST儲存,REMOVE刪除。
    • 多對多操作:

      • 使用者與角色之間的多對多關係:

        • 宣告關係:使用@ManyToMany註解,targetEntity 指定對方物件的位元組碼。

        • 配置中間表:使用@JoinTable註解,name指定中間表名稱,joinColumns指定當前物件在中間表中的外來鍵,inverseJoinColumns指定對方物件在中間表的外來鍵。

          @ManyToMany(targetEntity = Role.class)
          @JoinTable(name = "sys_user_role",
                     joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
                     inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")})
          private Set<Role> role = new HashSet<>();
          
      • 多對多放棄維護權:被動的一方放棄維護權。設定同一對多。

      • 多對多級聯操作:設定同一對多。

  • 物件導航查詢:

    • 通過查詢一個物件,查詢其所有的關聯物件。
    • 通過的方法是呼叫這個物件的get()方法來查詢。
    • 從一方查詢多方預設使用延遲載入。呼叫get()方法並不會立即進行查詢。
    • 關閉延遲載入:修改配置為立即載入,配置到多表對映的註解中,即@OneToMany等註解中的fetch屬性。EAGER表示立即載入,LAZY表示延遲載入。
    • 從多方查詢一方預設使用立即載入。

iwehdio的部落格園:https://www.cnblogs.com/iwehdio/