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的介面規範:
- 繼承介面
JpaRepository
和JpaSpecificationExecutor
。 - 需要提供相應的泛型。
- 介面
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表示延遲載入。 - 從多方查詢一方預設使用立即載入。