第一步首先創建一個maven工程,導入對於的pom依賴
<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>com.cib.com</groupId> <artifactId>heimaspringdatajpa</artifactId> <version>0.0.1-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-c3p0</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 --> <!-- 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>
1、接下來創建jpa的核心配置文件
jpa的核心配置文件必須放在類路徑的meta-info文件夾下面,命名也必須滿足對於的規則
PA規范要求在類路徑的META-INF目錄下放置persistence.xml, 文件的名稱是固定的,配置模板如下:
<!--必須要有name屬性,不能為空 -->
<persistence-unit name="myJap" transaction-type="RESOURCE_LOCAL">
這里
如果是分布式事務管理,這里就要配置為JTA,這里只操作一個數據庫,這里不存在分布式事務,這里設置為RESOURCE_LOCAl
persistence.xml的內容如下所示
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <!--必須要有name屬性,不能為空 --> <persistence-unit name="myJap" transaction-type="RESOURCE_LOCAL"> <!--可選 --> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <!--廠商的特定屬性 --> <properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=UTF-8" /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="123456" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.hbm2ddl.auto" value="update" /> </properties> </persistence-unit> </persistence>
接下來,我們要編寫實體類,創建對於的數據庫表
創建客戶的數據庫表
drop table if exists cst_customer; /*創建客戶表*/ CREATE TABLE cst_customer ( cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)', cust_name varchar(32) NOT NULL COMMENT '客戶名稱(公司名稱)', cust_source varchar(32) DEFAULT NULL COMMENT '客戶信息來源', cust_industry varchar(32) DEFAULT NULL COMMENT '客戶所屬行業', cust_level varchar(32) DEFAULT NULL COMMENT '客戶級別', cust_address varchar(128) DEFAULT NULL COMMENT '客戶聯系地址', cust_phone varchar(64) DEFAULT NULL COMMENT '客戶聯系電話', PRIMARY KEY (`cust_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=UTF8MB4; ———————————————— 版權聲明:本文為CSDN博主「底層_碼農」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/qq_40794973/article/details/98895832
注:表可以不用創建
3)創建、編寫實體類和數據庫表的映射配置[重點]
注解描述
@Entity:聲明實體類】
@Table : 配置實體類和表的映射關系 , name : 配置數據庫表的名稱
/**
* @Id:聲明主鍵的配置
* @GeneratedValue:配置主鍵的生成策略
* strategy
* GenerationType.IDENTITY :自增,mysql
* * 底層數據庫必須支持自動增長(底層數據庫支持的自動增長方式,對id自增)
* GenerationType.SEQUENCE : 序列,oracle
* * 底層數據庫必須支持序列
* GenerationType.TABLE : jpa提供的一種機制,通過一張數據庫表的形式幫助我們完成主鍵自增
* GenerationType.AUTO : 由程序自動的幫助我們選擇主鍵生成策略
* @Column:配置屬性和字段的映射關系
* name:數據庫表中字段的名稱
*/
/**
* 客戶編號(主鍵)
*/
GenerationType.IDENTITY :自增,mysql
* * 底層數據庫必須支持自動增長(底層數據庫支持的自動增長方式,對id自增) 必須和mysql中的 AUTO_INCREMENT一一對象,cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)',
@Column:配置屬性和字段的映射關系
* name:數據庫表中字段的名稱
package com.itcast.domain; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; /** * 客戶的實體類 * 配置映射關系 * * 1.實體類和表的映射關系 * @Entity:聲明實體類 * @Table : 配置實體類和表的映射關系 * name : 配置數據庫表的名稱 * 2.實體類中屬性和表中字段的映射關系 */ @Entity @Table(name = "cst_customer") public class Customer implements Serializable { /** * @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_industry") private String custIndustry; /** * 客戶級別 */ @Column(name="cust_level") private String custLevel; /** * 客戶聯系地址 */ @Column(name="cust_address") private String custAddress; /** * 客戶聯系電話 */ @Column(name="cust_phone") private String custPhone; 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 getCustIndustry() { return custIndustry; } public void setCustIndustry(String custIndustry) { this.custIndustry = custIndustry; } public String getCustLevel() { return custLevel; } public void setCustLevel(String custLevel) { this.custLevel = custLevel; } public String getCustAddress() { return custAddress; } public void setCustAddress(String custAddress) { this.custAddress = custAddress; } public String getCustPhone() { return custPhone; } public void setCustPhone(String custPhone) { this.custPhone = custPhone; } }
接下來我們就可以編寫一個測試類,測試對於的jpa的操作
/**
* 測試jpa的保存
* 案例:保存一個客戶到數據庫中
* Jpa的操作步驟
* 1.加載配置文件創建工廠(實體管理器工廠)對象
* 2.通過實體管理器工廠獲取實體管理器
* 3.獲取事務對象,開啟事務
* 4.完成增刪改查操作
* 5.提交事務(回滾事務)
* 6.釋放資源
*/
package com.itcast.cn; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import org.junit.Test; import com.itcast.domain.Customer; public class TestJpa { /** * 測試jpa的保存 * 案例:保存一個客戶到數據庫中 * Jpa的操作步驟 * 1.加載配置文件創建工廠(實體管理器工廠)對象 * 2.通過實體管理器工廠獲取實體管理器 * 3.獲取事務對象,開啟事務 * 4.完成增刪改查操作 * 5.提交事務(回滾事務) * 6.釋放資源 */ @Test public void testSave() { //1.加載配置文件創建工廠(實體管理器工廠)對象 EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJap"); //2.通過實體管理器工廠獲取實體管理器 EntityManager em = factory.createEntityManager(); //3.獲取事務對象,開啟事務 EntityTransaction tx = em.getTransaction(); //獲取事務對象 tx.begin();//開啟事務 try{ //4.完成增刪改查操作:保存一個客戶到數據庫中 Customer customer = new Customer(); customer.setCustName("蔡徐坤"); customer.setCustIndustry("明星"); customer.setCustSource("bibi"); //保存 em.persist(customer); //保存操作 //5.提交事務 tx.commit(); }catch (Exception e){ tx.rollback();//回滾事務 e.printStackTrace(); }finally { //6.釋放資源 em.close(); //關閉工廠 factory.close(); } } }
運行的sql語句如下所示
log4j:WARN No appenders could be found for logger (org.jboss.logging).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into cst_customer (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source) values (?, ?, ?, ?, ?, ?)
GenerationType.TABLE : jpa提供的一種機制,通過一張數據庫表的形式幫助我們完成主鍵自增,jpa會另外生成一張表幫助我們進行主鍵的管理
GenerationType.AUTO : 由程序自動的幫助我們選擇主鍵生成策略
多個線程在內存中共享一份Factory對象,減少Factory對象創建消耗資源
采用靜態代碼塊的方法,減少Factory資源創建消耗性能的問題
1. 抽取JPAUtil工具類
package com.itcast.utils; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; /** * 解決實體管理器工廠的浪費資源和耗時問題 * 通過靜態代碼塊的形式,當程序第一次訪問此工具類時,創建一個公共的實體管理器工廠對象 * * 第一次訪問getEntityManager方法:經過靜態代碼塊創建一個factory對象,再調用方法創建一個EntityManager對象 * 第二次方法getEntityManager方法:直接通過一個已經創建好的factory對象,創建EntityManager對象 */ public class JpaUtils { private static EntityManagerFactory factory; static { //1.加載配置文件,創建entityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa"); } /** * 獲取EntityManager對象 */ public static EntityManager getEntityManager() { return factory.createEntityManager(); } }
我們在編寫一個測試類進行測試
解決創建 EntityManagerFactory 浪費資源問題
3. 測試查詢
查詢有兩個方法,注意區別
package com.itcast.cn; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import org.junit.Test; import com.itcast.domain.Customer; import com.itcast.utils.JpaUtils; public class TestJpa { /** * 測試jpa的保存 * 案例:保存一個客戶到數據庫中 * Jpa的操作步驟 * 1.加載配置文件創建工廠(實體管理器工廠)對象 * 2.通過實體管理器工廠獲取實體管理器 * 3.獲取事務對象,開啟事務 * 4.完成增刪改查操作 * 5.提交事務(回滾事務) * 6.釋放資源 */ @Test public void testSave() { //1.加載配置文件創建工廠(實體管理器工廠)對象 EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJap"); //2.通過實體管理器工廠獲取實體管理器 EntityManager em = factory.createEntityManager(); //3.獲取事務對象,開啟事務 EntityTransaction tx = em.getTransaction(); //獲取事務對象 tx.begin();//開啟事務 try{ //4.完成增刪改查操作:保存一個客戶到數據庫中 Customer customer = new Customer(); customer.setCustName("蔡徐坤"); customer.setCustIndustry("明星"); customer.setCustSource("bibi"); //保存 em.persist(customer); //保存操作 //5.提交事務 tx.commit(); }catch (Exception e){ tx.rollback();//回滾事務 e.printStackTrace(); }finally { //6.釋放資源 em.close(); //關閉工廠 factory.close(); } } @Test public void testtestSave02(){ //1.獲取工廠(實體管理器工廠)對象 EntityManager em = JpaUtils.getEntityManager(); //3.獲取事務對象,開啟事務 EntityTransaction tx = em.getTransaction(); //獲取事務對象 tx.begin();//開啟事務 //4.完成增刪改查操作:保存一個客戶到數據庫中 Customer customer = new Customer(); customer.setCustName("蔡徐坤"); customer.setCustIndustry("明星"); customer.setCustSource("bibi"); //保存 em.persist(customer); //保存操作 //5.提交事務 tx.commit(); //6.釋放資源 em.close(); } /** * 根據id查詢客戶 * 使用find方法查詢: * 1.查詢的對象就是當前客戶對象本身 * 2.在調用find方法的時候,就會發送sql語句查詢數據庫 * * 立即加載 */ @Test public void testFind() { //1.通過工具類獲取entityManager EntityManager entityManager = JpaUtils.getEntityManager(); //3.增刪改查 -- 根據id查詢客戶 /** * find : 根據id查詢數據 * class:查詢數據的結果需要包裝的實體類類型的字節碼 * id:查詢的主鍵的取值 * 沒有返回 null */ Customer customer = entityManager.find(Customer.class, 1L);//打斷點 //不管打不打印(使用),執行到上一條語句時,都會發送SQL語句 //System.out.print(customer); //class com.bug.domain.Customer System.out.println(customer.toString()); //5.釋放資源 entityManager.close(); } /** * 根據id查詢客戶 * getReference方法 * 1.獲取的對象是一個動態代理對象 * 2.調用getReference方法不會立即發送sql語句查詢數據庫 * * 當調用查詢結果對象的時候,才會發送查詢的sql語句:什么時候用,什么時候發送sql語句查詢數據庫 * * 延遲加載(懶加載) * * 得到的是一個動態代理對象 * * 什么時候用,什么使用才會查詢 */ @Test public void testReference() { //1.通過工具類獲取entityManager EntityManager entityManager = JpaUtils.getEntityManager(); //3.增刪改查 -- 根據id查詢客戶 /** * getReference : 根據id查詢數據 * class:查詢數據的結果需要包裝的實體類類型的字節碼 * id:查詢的主鍵的取值 */ Customer customer = entityManager.getReference(Customer.class, 1L);//打斷點 //這里不打印(不使用)就不會發送SQL語句 //System.out.print(customer); //class com.bug.domain.Customer_$$_jvst88e_0 代理對象 System.out.println("\n\n"); System.out.println(customer.toString()); //5.釋放資源 entityManager.close(); } }
//3.增刪改查 -- 根據id查詢客戶
/**
* getReference : 根據id查詢數據
* class:查詢數據的結果需要包裝的實體類類型的字節碼
* id:查詢的主鍵的取值
*/
getReference 是懶加載,在find查詢語句的時候不會發起sql語句查詢,在實際使用使用System.out.print(customer)的時候才發起sql語句進行查詢,返回的查詢結果是一個代理對象
4. 測試刪除
@Test public void testRemove() { //1.通過工具類獲取entityManager EntityManager entityManager = JpaUtils.getEntityManager(); //3.增刪改查 -- 刪除客戶 //3.獲取事務對象,開啟事務 EntityTransaction tx = entityManager.getTransaction(); //獲取事務對象 tx.begin();//開啟事務 //i 根據id查詢客戶 Customer customer = entityManager.find(Customer.class, 1L); System.out.println(customer); if(customer != null){ //ii 調用remove方法完成刪除操作 entityManager.remove(customer); } //5.提交事務 tx.commit(); //5.釋放資源 entityManager.close(); }
7.JPA中的復雜查詢
JPQL全稱Java Persistence Query Language,Java持久化查詢語言(JPQL),它是一種可移植的查詢語言,旨在以面向對象表達式語言的表達式,將SQL語法和簡單查詢語義綁定在一起·使用這種語言編寫的查詢是可移植的,可以被編譯成所有主流數據庫服務器上的SQL。
其特征與原生SQL語句類似,並且完全面向對象,通過類名和屬性訪問,而不是表名和表的屬性。
jpql語句不能寫select *,但是能夠寫select 加上對象的屬性值
查詢數據庫 表中存在多少條記錄
//統計查詢 @Test public void findCount() { EntityManager em = null; EntityTransaction tx = null; try { //獲取實體管理對象 em = JPAUtil.getEntityManager(); //獲取事務對象 tx = em.getTransaction(); tx.begin(); // 查詢全部客戶 // 1.創建query對象 String jpql = "select count(custId) from Customer"; Query query = em.createQuery(jpql); // 2.查詢並得到返回結果 Object count = query.getSingleResult(); // 得到集合返回類型 System.out.println(count); tx.commit(); } catch (Exception e) { // 回滾事務 tx.rollback(); e.printStackTrace(); } finally { // 釋放資源 em.close(); } } ———————————————— 版權聲明:本文為CSDN博主「I Java」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/zlx_508/article/details/97005499
記錄總數只有一條記錄,使用getSingleResult,返回一條記錄
分頁查詢
0表示查詢第一頁,2表示第一頁顯示2條記錄
//分頁查詢客戶 @Test public void findPaged () { EntityManager em = null; EntityTransaction tx = null; try { //獲取實體管理對象 em = JPAUtil.getEntityManager(); //獲取事務對象 tx = em.getTransaction(); tx.begin(); //創建query對象 String jpql = "from Customer"; Query query = em.createQuery(jpql); //起始索引 query.setFirstResult(0); //每頁顯示條數 query.setMaxResults(2); //查詢並得到返回結果 List list = query.getResultList(); //得到集合返回類型 for (Object object : list) { System.out.println(object); } tx.commit(); } catch (Exception e) { // 回滾事務 tx.rollback(); e.printStackTrace(); } finally { // 釋放資源 em.close(); } } ———————————————— 版權聲明:本文為CSDN博主「I Java」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/zlx_508/article/details/97005499
接下來我們講解條件查詢
//條件查詢 @Test public void findCondition () { EntityManager em = null; EntityTransaction tx = null; try { //獲取實體管理對象 em = JPAUtil.getEntityManager(); //獲取事務對象 tx = em.getTransaction(); tx.begin(); //創建query對象 String jpql = "from Customer where custName like ? "; Query query = em.createQuery(jpql); //對占位符賦值,從1開始 query.setParameter(1, "傳智播客%"); //查詢並得到返回結果 Object object = query.getSingleResult(); //得到唯一的結果集對象 System.out.println(object); tx.commit(); } catch (Exception e) { // 回滾事務 tx.rollback(); e.printStackTrace(); } finally { // 釋放資源 em.close(); } } ———————————————— 版權聲明:本文為CSDN博主「I Java」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/zlx_508/article/details/97005499
接下來重點講解spring -data-jpa
這里配置文件有點問題,不清楚的看佟剛spring data的視頻教程
pom.xml的依賴如下
<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>com.cib.com</groupId> <artifactId>heimaspringdatajpa</artifactId> <version>0.0.1-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-c3p0</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 --> <!-- 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>
db.properties的配置如下
jdbc.user=root jdbc.password=123456 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql:///jpa
<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置自動掃描的包 --> <context:component-scan base-package="com.atguigu.springdata"></context:component-scan> <!-- 1. 配置數據源 --> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <!-- 配置其他屬性 --> </bean> <!-- 2. 配置 JPA 的 EntityManagerFactory --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean> </property> <property name="packagesToScan" value="com.atguigu.springdata"></property> <property name="jpaProperties"> <props> <!-- 二級緩存相關 --> <!-- <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> <prop key="net.sf.ehcache.configurationResourceName">ehcache-hibernate.xml</prop> --> <!-- 生成的數據表的列的映射策略 --> <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> <!-- hibernate 基本屬性 --> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 3. 配置事務管理器 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean> <!-- 4. 配置支持注解的事務 --> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 5. 配置 SpringData --> <!-- 加入 jpa 的命名空間 --> <!-- base-package: 掃描 Repository Bean 所在的 package --> <jpa:repositories base-package="com.atguigu.springdata" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories> </beans>
這里有幾個配置很關鍵
<jpa:repositories base-package="com.atguigu.springdata" 指定掃描@Reporisty注解的包
<property name="packagesToScan" value="com.atguigu.springdata"></property>指定@Entiry注解的包
<context:component-scan base-package="com.atguigu.springdata"></context:component-scan>指定spring @service @compent所在的包路徑
接下來我們創建包com.atguigu.springdata,所有在的操作都在這個包下面
接下來我們創建實體類
package com.atguigu.springdata; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity // 聲明此類是個實體類 需要導入javax.persistence.Entity; @Table(name = "cst_customer") //需要將該類對應到數據庫中的哪一個表中,name中填表的名稱 public class Customer { @Id //聲明主鍵 @GeneratedValue(strategy = GenerationType.IDENTITY) //聲明主鍵的生成策略為自動遞增 //mysql使用自增模式,orcle 使用序列模式 @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 cusIndustry; @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 getCusIndustry() { return cusIndustry; } public void setCusIndustry(String cusIndustry) { this.cusIndustry = cusIndustry; } 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 + ", cusIndustry=" + cusIndustry + ", custPhone=" + custPhone + ", custAddress=" + custAddress + "]"; } }
實體類創建成功之后,接下來我們就可以編寫jpa的接口進行增刪改查的操作了,只需要編寫jpa接口,不需要編寫jpa的實現類
關鍵點:
1.編寫dao層的接口就可以了,不需要dao接口的實現類
2、編寫的dao接口的規范如下
SpringDataJPA通過實現接口(代理的形式)進行簡單的CRUD
https://blog.csdn.net/qq_42041712/article/details/94451572
JpaRepository<Customer,Long> 第一個參數是我們要操作的實體類類型,第二個參數是實體類的主鍵
JpaSpecificationExecutor<Customer> 參數是我們要操作的實體類的類型
package com.atguigu.springdata; 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> { }
接下來編寫好接口之后,就可以進行增加刪除操作數據庫了,注意CustomerDao沒有使用注解,只要放在<jpa:repositories base-package="com.atguigu.springdata"對於的包下面就可以了
我們可以編寫一個測試類進行操作,首先保證數據庫中存在數據
import java.io.FileNotFoundException; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.stream.Collector; import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.sql.DataSource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.jpa.domain.Specification; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.atguigu.springdata.CustomerDao; import com.itcast.domain.Customer; import com.itcast.utils.JpaUtils; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class SpringDataTest { @Autowired private CustomerDao dao; @Test public void testFind() { com.atguigu.springdata.Customer customer = dao.findOne((long) 2); System.out.println(customer.toString()); } }
測試的結果如下
在eclipse中查看一個類及其父類中的所有方法和屬性
只需要連續按兩次Ctrl+O
JpaRepository默認實現了下面的方法
在eclipse中查看一個類的集成關系
只需要連續按兩次Ctrl+T
JpaRepository繼承自PagingAndSortingRepository,PagingAndSortingRepository繼承自CrudRepository,CrudRepository集成自Repository
import java.io.FileNotFoundException; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.stream.Collector; import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.sql.DataSource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.jpa.domain.Specification; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.atguigu.springdata.Customer; import com.atguigu.springdata.CustomerDao; import com.itcast.utils.JpaUtils; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class SpringDataTest { @Autowired private CustomerDao customerDao; @Test public void testFind() { com.atguigu.springdata.Customer customer = customerDao.findOne((long) 2); System.out.println(customer.toString()); } /** * 保存客戶:調用save(obj)方法 */ @Test public void testSave() { Customer c = new Customer(); c.setCustName("傳智播客"); customerDao.save(c); } /** * 修改客戶:調用save(obj)方法 * 對於save方法的解釋:如果執行此方法是對象中存在id屬性,即為更新操作會先根據id查詢,再更新 * 如果執行此方法中對象中不存在id屬性,即為保存操作 * */ @Test public void testUpdate() { //根據id查詢id為1的客戶 Customer customer = customerDao.findOne(1l); //修改客戶名稱 customer.setCustName("傳智播客順義校區"); //更新 customerDao.save(customer); } }
/**
* 根據id刪除:調用delete(id)方法
*/
@Test
public void testDelete() {
customerDao.delete(1l);
}
import java.io.FileNotFoundException; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.stream.Collector; import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.sql.DataSource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.jpa.domain.Specification; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.atguigu.springdata.Customer; import com.atguigu.springdata.CustomerDao; import com.itcast.utils.JpaUtils; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class SpringDataTest { @Autowired private CustomerDao customerDao; @Test public void testFind() { com.atguigu.springdata.Customer customer = customerDao.findOne((long) 2); System.out.println(customer.toString()); } /** * 保存客戶:調用save(obj)方法 */ @Test public void testSave() { Customer c = new Customer(); c.setCustName("傳智播客"); customerDao.save(c); } /** * 修改客戶:調用save(obj)方法 * 對於save方法的解釋:如果執行此方法是對象中存在id屬性,即為更新操作會先根據id查詢,再更新 * 如果執行此方法中對象中不存在id屬性,即為保存操作 * */ @Test public void testUpdate() { //根據id查詢id為1的客戶 Customer customer = customerDao.findOne(1l); //修改客戶名稱 customer.setCustName("傳智播客順義校區"); //更新 customerDao.save(customer); } @Test public void testCount() { long count = customerDao.count(); System.out.println(count); } @Test public void testExits() { boolean exists = customerDao.exists((long) 2); System.out.println(exists); } }
@Test @Transactional public void testGetOne() { Customer one = customerDao.getOne((long) 2); System.out.println(one); }
getOne是懶加載,findOne是直接加載,懶加載的實現需要依賴事務,所有使用getOne方法的時候,一定要引入事務管理的依賴,這里使用 @Transactiona,否則代碼會報錯
3.2 使用JPQL的方式查詢
使用Spring Data JPA提供的查詢方法已經可以解決大部分的應用場景,但是對於某些業務來說,我們還需要靈活的構造查詢條件,這時就可以使用@Query注解,結合JPQL的語句方式完成查詢
package com.atguigu.springdata; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import antlr.collections.List; /* * 符合SpringDatajpa的dao層接口規范 *JpaRepository<操作的實體類類型,實體類中主鍵屬性的類型> *封裝了基本的CRUD操作 JpaSpecificationExecutor<操作的實體類類型> *封裝了復雜查詢操作(分頁) * */ public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> { //@Query 使用jpql的方式查詢。?1代表參數的占位符,其中1對應方法中的參數索引 @Query(value="from Customer where custName = ?1") public Customer findCustomer(String custName); }
//@Query 使用jpql的方式查詢。?1代表參數的占位符,其中1對應方法中的參數索引
2表示的是輸入參數為name,1表示輸入的參數是id
此外,也可以通過使用 @Query 來執行一個更新操作,為此,我們需要在使用 @Query 的同時,用 @Modifying 來將該操作標識為修改查詢,這樣框架最終會生成一個更新的操作,而非查詢
package com.atguigu.springdata; 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 org.springframework.stereotype.Repository; import antlr.collections.List; /* * 符合SpringDatajpa的dao層接口規范 *JpaRepository<操作的實體類類型,實體類中主鍵屬性的類型> *封裝了基本的CRUD操作 JpaSpecificationExecutor<操作的實體類類型> *封裝了復雜查詢操作(分頁) * */ public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> { //@Query 使用jpql的方式查詢。?1代表參數的占位符,其中1對應方法中的參數索引 @Query(value="from Customer where custName = ?1") public Customer findCustomer(String custName); @Query(value="update Customer set custName = ?1 where custId = ?2") @Modifying public void updateCustomer(String custName,Long custId); }
執行更新或者刪除操作,必須需要添加 @Modifying,此外必須要具有事務操作
@Test @Transactional @Rollback(value=false) public void testupdateCustomer() { customerDao.updateCustomer("我是可不2222", (long) 2); }
執行更新刪除操作需要有事務所有上面有@Transactional,此外jpa執行事務操作完成之后默認會回滾,當數據更新操作成功之后,因為jpa默認要回滾,會把更新的數據還原回去,我們要在數據庫中看到更新的
數據,我們要禁止jpa的回滾@Rollback(value=false)
3.3 使用SQL語句查詢
Spring Data JPA同樣也支持sql語句的查詢,如下:
package com.atguigu.springdata; import java.util.List; 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 org.springframework.stereotype.Repository; /* * 符合SpringDatajpa的dao層接口規范 *JpaRepository<操作的實體類類型,實體類中主鍵屬性的類型> *封裝了基本的CRUD操作 JpaSpecificationExecutor<操作的實體類類型> *封裝了復雜查詢操作(分頁) * */ public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> { //@Query 使用jpql的方式查詢。?1代表參數的占位符,其中1對應方法中的參數索引 @Query(value="from Customer where custName = ?1") public Customer findCustomer(String custName); @Query(value="update Customer set custName = ?1 where custId = ?2") @Modifying public void updateCustomer(String custName,Long custId); /** * nativeQuery : 使用本地sql的方式查詢 */ @Query(value="select * from cst_customer",nativeQuery=true) public List<Object[]> findSql(); }
這里千萬要注意返回的是一個List<Object[]>,每一個元素是一個Object類型的數組,不能寫成List<Customer[]>
@Test public void testfindSql() { List<Object[]> datas = customerDao.findSql(); for(Object[] data:datas){ System.out.println(Arrays.toString(data)); } }
package com.atguigu.springdata; import java.util.List; 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 org.springframework.stereotype.Repository; /* * 符合SpringDatajpa的dao層接口規范 *JpaRepository<操作的實體類類型,實體類中主鍵屬性的類型> *封裝了基本的CRUD操作 JpaSpecificationExecutor<操作的實體類類型> *封裝了復雜查詢操作(分頁) * */ public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> { //@Query 使用jpql的方式查詢。?1代表參數的占位符,其中1對應方法中的參數索引 @Query(value="from Customer where custName = ?1") public Customer findCustomer(String custName); @Query(value="update Customer set custName = ?1 where custId = ?2") @Modifying public void updateCustomer(String custName,Long custId); /** * nativeQuery : 使用本地sql的方式查詢 */ @Query(value="select * from cst_customer",nativeQuery=true) public List<Object[]> findSql(); @Query(value = "select * from cst_customer where cust_name like ?1",nativeQuery = true) public List<Object []> findSql2(String name);
}
測試代碼
import java.io.FileNotFoundException; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.stream.Collector; import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.sql.DataSource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Query; 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 com.atguigu.springdata.Customer; import com.atguigu.springdata.CustomerDao; import com.itcast.utils.JpaUtils; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class SpringDataTest { @Autowired private CustomerDao customerDao; @Test public void testFind() { com.atguigu.springdata.Customer customer = customerDao.findOne((long) 2); System.out.println(customer.toString()); } /** * 保存客戶:調用save(obj)方法 */ @Test public void testSave() { Customer c = new Customer(); c.setCustName("傳智播客"); customerDao.save(c); } /** * 修改客戶:調用save(obj)方法 * 對於save方法的解釋:如果執行此方法是對象中存在id屬性,即為更新操作會先根據id查詢,再更新 * 如果執行此方法中對象中不存在id屬性,即為保存操作 * */ @Test public void testUpdate() { //根據id查詢id為1的客戶 Customer customer = customerDao.findOne(1l); //修改客戶名稱 customer.setCustName("傳智播客順義校區"); //更新 customerDao.save(customer); } @Test public void testCount() { long count = customerDao.count(); System.out.println(count); } @Test public void testExits() { boolean exists = customerDao.exists((long) 2); System.out.println(exists); } @Test @Transactional public void testGetOne() { Customer one = customerDao.getOne((long) 2); System.out.println(one); } @Test @Transactional @Rollback(value=false) public void testupdateCustomer() { customerDao.updateCustomer("我是可不2222", (long) 2); } @Test public void testfindSql() { List<Object[]> datas = customerDao.findSql(); for(Object[] data:datas){ System.out.println(Arrays.toString(data)); } } //測試sql查詢 @Test public void testFindSql() { List<Object[]> list = customerDao.findSql2("迅騰軟件%");//模糊查詢 for(Object[] obj: list){ System.out.println(Arrays.toString(obj)); } } }
3.4 方法命名規則查詢
顧名思義,方法命名規則查詢就是根據方法的名字,就能創建查詢。只需要按照Spring Data JPA提供的方法命名規則定義方法的名稱,就可以完成查詢工作。Spring Data JPA在程序執行的時候會根據方法名稱進行解析,並自動生成查詢語句進行查詢
按照Spring Data JPA 定義的規則,查詢方法以findBy開頭,涉及條件查詢時,條件的屬性用條件關鍵字連接,要注意的是:條件屬性首字母需大寫。框架在進行方法名解析時,會先把方法名多余的前綴截取掉,然后對剩下部分進行解析。
package com.atguigu.springdata; import java.util.List; 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 org.springframework.stereotype.Repository; /* * 符合SpringDatajpa的dao層接口規范 *JpaRepository<操作的實體類類型,實體類中主鍵屬性的類型> *封裝了基本的CRUD操作 JpaSpecificationExecutor<操作的實體類類型> *封裝了復雜查詢操作(分頁) * */ public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> { //@Query 使用jpql的方式查詢。?1代表參數的占位符,其中1對應方法中的參數索引 @Query(value="from Customer where custName = ?1") public Customer findCustomer(String custName); @Query(value="update Customer set custName = ?1 where custId = ?2") @Modifying public void updateCustomer(String custName,Long custId); /** * nativeQuery : 使用本地sql的方式查詢 */ @Query(value="select * from cst_customer",nativeQuery=true) public List<Object[]> findSql(); @Query(value = "select * from cst_customer where cust_name like ?1",nativeQuery = true) public List<Object []> findSql2(String name); //方法命名方式查詢(根據客戶名稱查詢客戶) public Customer findByCustName(String custName); }
測試代碼如下
@Test public void testFindSql22() { Customer customer = customerDao.findByCustName("3333"); System.out.println(customer.toString()); }
我們使用下Like查看下模糊查詢
package com.atguigu.springdata; import java.util.List; 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 org.springframework.stereotype.Repository; /* * 符合SpringDatajpa的dao層接口規范 *JpaRepository<操作的實體類類型,實體類中主鍵屬性的類型> *封裝了基本的CRUD操作 JpaSpecificationExecutor<操作的實體類類型> *封裝了復雜查詢操作(分頁) * */ public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> { //@Query 使用jpql的方式查詢。?1代表參數的占位符,其中1對應方法中的參數索引 @Query(value="from Customer where custName = ?1") public Customer findCustomer(String custName); @Query(value="update Customer set custName = ?1 where custId = ?2") @Modifying public void updateCustomer(String custName,Long custId); /** * nativeQuery : 使用本地sql的方式查詢 */ @Query(value="select * from cst_customer",nativeQuery=true) public List<Object[]> findSql(); @Query(value = "select * from cst_customer where cust_name like ?1",nativeQuery = true) public List<Object []> findSql2(String name); //方法命名方式查詢(根據客戶名稱查詢客戶) public Customer findByCustName(String custName); public List<Customer> findByCustNameLike(String custName); }
測試代碼如下
@Test public void testFindSql22() { List<Customer> customers = customerDao.findByCustNameLike("3333%"); for(Customer customer:customers){ System.out.println(customer.toString()); } }
這里沒有占位符,兩個參數順利不能弄錯了
package com.atguigu.springdata; import java.util.List; 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 org.springframework.stereotype.Repository; /* * 符合SpringDatajpa的dao層接口規范 *JpaRepository<操作的實體類類型,實體類中主鍵屬性的類型> *封裝了基本的CRUD操作 JpaSpecificationExecutor<操作的實體類類型> *封裝了復雜查詢操作(分頁) * */ public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> { //@Query 使用jpql的方式查詢。?1代表參數的占位符,其中1對應方法中的參數索引 @Query(value="from Customer where custName = ?1") public Customer findCustomer(String custName); @Query(value="update Customer set custName = ?1 where custId = ?2") @Modifying public void updateCustomer(String custName,Long custId); /** * nativeQuery : 使用本地sql的方式查詢 */ @Query(value="select * from cst_customer",nativeQuery=true) public List<Object[]> findSql(); @Query(value = "select * from cst_customer where cust_name like ?1",nativeQuery = true) public List<Object []> findSql2(String name); //方法命名方式查詢(根據客戶名稱查詢客戶) public Customer findByCustName(String custName); public List<Customer> findByCustNameLike(String custName); public List<Customer> findByCustNameLikeAndCusIndustry(String custName,String cusIndustry); }
測試代碼如下
@Test public void testFindSql22() { List<Customer> customers = customerDao.findByCustNameLikeAndCusIndustry("3333%","明星"); for(Customer customer:customers){ System.out.println(customer.toString()); } } Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_industry as cust_ind2_0_, customer0_.cust_address as cust_add3_0_, customer0_.cust_level as cust_lev4_0_, customer0_.cust_name as cust_nam5_0_, customer0_.cust_phone as cust_pho6_0_, customer0_.cust_source as cust_sou7_0_ from cst_customer customer0_ where ( customer0_.cust_name like ? ) and customer0_.cust_industry=?
我們重點來看下JpaSpecificationExecutor方法
這個接口有上面的幾個方法,T findOne(Specification<T> spec);之前的JpaRepository接口也有findOne方法只能依據主鍵查詢,但是沒有攜帶Specification參數,這里攜帶了Specification參數
我們可以按照主鍵查詢,也可以安裝名稱查詢,我們可以自定義查詢條件
/** * Specification in the sense of Domain Driven Design. * * @author Oliver Gierke * @author Thomas Darimont */ public interface Specification<T> { /** * Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given * {@link Root} and {@link CriteriaQuery}. * * @param root * @param query * @return a {@link Predicate}, must not be {@literal null}. */ Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); }
我們來測試下上面的幾個接口
對象CriteriaBuilder有下面這樣多的比較的方式
@Test public void testFindSql223333() { Specification<Customer> spec = new Specification<Customer>() { public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) { // TODO Auto-generated method stub Path<Object> custName = root.get("custName"); Predicate predicate = cb.equal(custName, "3333"); return predicate; } }; Customer customer = customerDao.findOne(spec); System.out.println(customer.toString()); }
多個查詢條件的拼接
@Test public void testFindSql223333222() { Specification<Customer> spec = new Specification<Customer>() { public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) { // TODO Auto-generated method stub Path<Object> custName = root.get("custName"); Path<Object> cusIndustry = root.get("cusIndustry"); Predicate predicate1 = cb.equal(custName, "3333"); Predicate predicate2 = cb.equal(cusIndustry, "2222"); Predicate predicate3 = cb.and(predicate1,predicate2); return predicate3; } }; Customer customer = customerDao.findOne(spec); System.out.println(customer.toString()); }
@Test public void testFindSql223333222wwww() { Specification<Customer> spec = new Specification<Customer>() { public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) { // TODO Auto-generated method stub Path<Object> custName = root.get("custName"); Predicate predicate = cb.like(custName.as(String.class), "33%"); return predicate; } }; List<Customer> customer = customerDao.findAll(spec); System.out.println(customer.toString()); }
對於 List<Customer> customer = customerDao.findAll(spec)返回的數據是一個集合,我們可以指定返回的集合中的數據按照某種方式進行排序
@Test public void testFindSql223333222wwwwww() { Specification<Customer> spec = new Specification<Customer>() { public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) { // TODO Auto-generated method stub Path<Object> custName = root.get("custName"); Predicate predicate = cb.like(custName.as(String.class), "33%"); return predicate; } }; Sort sort = new Sort(Sort.Direction.ASC,"custId"); List<Customer> customer = customerDao.findAll(spec,sort); System.out.println(customer.toString()); }
按照"custId"的Sort.Direction.ASC進行排序
/** * 目標: 實現帶查詢條件的分頁. id > 5 的條件 * * 調用 JpaSpecificationExecutor 的 Page<T> findAll(Specification<T> spec, Pageable pageable); * Specification: 封裝了 JPA Criteria 查詢的查詢條件 * Pageable: 封裝了請求分頁的信息: 例如 pageNo, pageSize, Sort */ @Test public void testJpaSpecificationExecutorss(){ int pageNo = 3 - 1; int pageSize = 5; Sort sort = new Sort(Sort.Direction.ASC,"custId"); //封裝分頁的信息 PageRequest pageable = new PageRequest(pageNo, pageSize,sort); Specification<Customer> spec = new Specification<Customer>() { public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) { // TODO Auto-generated method stub Path<Object> custName = root.get("custName"); Predicate predicate = cb.like(custName.as(String.class), "33%"); return predicate; } }; Page<Customer> page = customerDao.findAll(spec, pageable); System.out.println("總記錄數: " + page.getTotalElements()); System.out.println("當前第幾頁: " + (page.getNumber() + 1)); System.out.println("總頁數: " + page.getTotalPages()); System.out.println("當前頁面的 List: " + page.getContent()); List<Customer> content = page.getContent(); System.out.println("當前頁面的記錄數: " + page.getNumberOfElements()); /*List<Person> collect = page.getContent().stream().map(stat->(Person)stat).collect(Collectors.toList()); System.out.println("當前頁面的 List1: " + collect);*/ }
打印結果如下
Hibernate: select count(customer0_.cust_id) as col_0_0_ from cst_customer customer0_ where customer0_.cust_name like ? 總記錄數: 1 當前第幾頁: 3 總頁數: 1 當前頁面的 List: [] 當前頁面的記錄數: 0
客戶個聯系人是一對多的關系
3.2 實戰Hibernate一對多關聯映射 3.2.1 創建數據表(客戶----聯系人) 客戶表: CREATE TABLE `cst_customer` ( `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)', `cust_name` varchar(32) NOT NULL COMMENT '客戶名稱(公司名稱)', `cust_source` varchar(32) DEFAULT NULL COMMENT '客戶信息來源', `cust_industry` varchar(32) DEFAULT NULL COMMENT '客戶所屬行業', `cust_level` varchar(32) DEFAULT NULL COMMENT '客戶級別', `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定電話', `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移動電話', PRIMARY KEY (`cust_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; 聯系人表: CREATE TABLE `cst_linkman` ( `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '聯系人編號(主鍵)', `lkm_name` varchar(16) DEFAULT NULL COMMENT '聯系人姓名', `lkm_cust_id` bigint(32) DEFAULT NULL COMMENT '客戶id', `lkm_gender` char(1) DEFAULT NULL COMMENT '聯系人性別', `lkm_phone` varchar(16) DEFAULT NULL COMMENT '聯系人辦公電話', `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '聯系人手機', `lkm_email` varchar(64) DEFAULT NULL COMMENT '聯系人郵箱', `lkm_qq` varchar(16) DEFAULT NULL COMMENT '聯系人qq', `lkm_position` varchar(16) DEFAULT NULL COMMENT '聯系人職位', `lkm_memo` varchar(512) DEFAULT NULL COMMENT '聯系人備注', PRIMARY KEY (`lkm_id`), KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`), CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
接下來我們要新增一個聯系人的實體類對象
在customer客戶端實體類中,需要配置下面的信息
package com.atguigu.springdata; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity // 聲明此類是個實體類 需要導入javax.persistence.Entity; @Table(name = "cst_customer") //需要將該類對應到數據庫中的哪一個表中,name中填表的名稱 public class Customer { @Id //聲明主鍵 @GeneratedValue(strategy = GenerationType.IDENTITY) //聲明主鍵的生成策略為自動遞增 //mysql使用自增模式,orcle 使用序列模式 @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 cusIndustry; @Column(name = "cust_phone") private String custPhone; @Column(name = "cust_address") private String custAddress; @OneToMany(targetEntity=LinkMan.class) @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id") private Set<LinkMan> linkMans = new HashSet<LinkMan>(); 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 getCusIndustry() { return cusIndustry; } public void setCusIndustry(String cusIndustry) { this.cusIndustry = cusIndustry; } 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 + ", cusIndustry=" + cusIndustry + ", custPhone=" + custPhone + ", custAddress=" + custAddress + "]"; } public Set<LinkMan> getLinkMans() { return linkMans; } public void setLinkMans(Set<LinkMan> linkMans) { this.linkMans = linkMans; } }
在聯系人方需要配置如下
package com.atguigu.springdata; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity // 聲明此類是個實體類 需要導入javax.persistence.Entity; @Table(name = "cst_linkman") //需要將該類對應到數據庫中的哪一個表中,name中填表的名稱 public class LinkMan {
@Id //聲明主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY) //聲明主鍵的生成策略為自動遞增
@Column(name = "lkm_id") //設置該屬性和數據庫中的哪一個字段對應
private Long lkmId; @Column(name = "lkm_gender") //設置該屬性和數據庫中的哪一個字段對應 private Character lkmGender; @Column(name = "lkm_name") //設置該屬性和數據庫中的哪一個字段對應 private String lkmName; @Column(name = "lkm_phone") //設置該屬性和數據庫中的哪一個字段對應 private String lkmPhone; @Column(name = "lkm_email") //設置該屬性和數據庫中的哪一個字段對應 private String lkmEmail; @Column(name = "lkm_qq") //設置該屬性和數據庫中的哪一個字段對應 private String lkmQq; @Column(name = "lkm_mobile") //設置該屬性和數據庫中的哪一個字段對應 private String lkmMobile; @Column(name = "lkm_memo") //設置該屬性和數據庫中的哪一個字段對應 private String lkmMemo; @Column(name = "lkm_position") //設置該屬性和數據庫中的哪一個字段對應 private String lkmPosition; @ManyToOne(targetEntity=Customer.class) @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id") private Customer customer; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } public Long getLkmId() { return lkmId; } public void setLkmId(Long lkmId) { this.lkmId = lkmId; } public Character getLkmGender() { return lkmGender; } public void setLkmGender(Character lkmGender) { this.lkmGender = lkmGender; } public String getLkmName() { return lkmName; } public void setLkmName(String lkmName) { this.lkmName = lkmName; } public String getLkmPhone() { return lkmPhone; } public void setLkmPhone(String lkmPhone) { this.lkmPhone = lkmPhone; } public String getLkmEmail() { return lkmEmail; } public void setLkmEmail(String lkmEmail) { this.lkmEmail = lkmEmail; } public String getLkmQq() { return lkmQq; } public void setLkmQq(String lkmQq) { this.lkmQq = lkmQq; } public String getLkmMobile() { return lkmMobile; } public void setLkmMobile(String lkmMobile) { this.lkmMobile = lkmMobile; } public String getLkmMemo() { return lkmMemo; } public void setLkmMemo(String lkmMemo) { this.lkmMemo = lkmMemo; } public String getLkmPosition() { return lkmPosition; } public void setLkmPosition(String lkmPosition) { this.lkmPosition = lkmPosition; } }
@JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")中表示的是表聯系人中的lkm_cust_id字段的值,來自於表客戶的cust_id
接下來,我們要編寫一個操作聯系人的接口類
package com.atguigu.springdata; import java.util.List; 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 org.springframework.stereotype.Repository; /* * 符合SpringDatajpa的dao層接口規范 *JpaRepository<操作的實體類類型,實體類中主鍵屬性的類型> *封裝了基本的CRUD操作 JpaSpecificationExecutor<操作的實體類類型> *封裝了復雜查詢操作(分頁) * */ public interface LinnkManDao extends JpaRepository<LinkMan,Long>, JpaSpecificationExecutor<LinkMan> { }
整個工程的結構如下所示
接下來我們來就可以進行測試了
我們來看下程序的代碼
import java.io.FileNotFoundException; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.stream.Collector; import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.sql.DataSource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Query; 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 com.atguigu.springdata.Customer; import com.atguigu.springdata.CustomerDao; import com.atguigu.springdata.LinkMan; import com.atguigu.springdata.LinnkManDao; import com.itcast.utils.JpaUtils; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class oneToManyTest { @Autowired private CustomerDao customerDao; @Autowired private LinnkManDao linnkManDao; @Test @Transactional @Rollback(value=false) public void save(){ Customer customer = new Customer(); customer.setCustName("百度"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("小明"); linkMan.setCustomer(customer); customerDao.save(customer); linnkManDao.save(linkMan); } }
這里操作了兩張表要保證事務的一致性 @Transactional,其次事務操作成功之后要讓更新的記錄保存到數據庫,不進行回滾 @Rollback(value=false)