javascript
SpringBoot24 SpringDataJPA环境搭建、实体类注解、关联查询
?
1 版本說明
JDK:1.8
MAVEN:3.5
SpringBoot:2.0.4
IDEA:旗艦版207.2
MySQL:5.5
?
2?SpringDataJPA環境搭建(SpringBoot版本)
2.1 創建一個SrpingBoot項目
需要引入的依賴如下圖所示
2.2 配置數據庫相關
》創建一個mysql數據庫testdemo
》在testdemo中創建一個student表
/* Navicat MySQL Data TransferSource Server : mysql5.4 Source Server Version : 50540 Source Host : localhost:3306 Source Database : testdemoTarget Server Type : MYSQL Target Server Version : 50540 File Encoding : 65001Date: 2018-08-13 21:13:51 */SET FOREIGN_KEY_CHECKS=0;-- ---------------------------- -- Table structure for `student` -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` (`id` int(50) NOT NULL AUTO_INCREMENT,`name` varchar(20) NOT NULL,`age` int(10) NOT NULL,`address` varchar(50) DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4; student.sql》在springboot項目中配置數據庫信息
spring:datasource:url: jdbc:mysql://127.0.0.1/testdemo?characterEncoding=utf-8&useSSL=falseusername: rootpassword: 182838jpa:properties:hibernate:format_sql: trueshow_sql: true application.yml2.2.1 利用IDEA連接數據
參考博文
2.2.2 利用IDEA自動生成實體類
package cn.xiangxu.jpa_demo03.domain.domain_do;import javax.persistence.*;/*** @author 王楊帥* @create 2018-08-13 21:36* @desc**/ @Entity @Table(name = "student", schema = "testdemo", catalog = "") public class StudentDO {private int id;private String name;private int age;private String address;@Id@Column(name = "id")public int getId() {return id;}public void setId(int id) {this.id = id;}@Basic@Column(name = "name")public String getName() {return name;}public void setName(String name) {this.name = name;}@Basic@Column(name = "age")public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Basic@Column(name = "address")public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic boolean equals(Object object) {if (this == object) return true;if (object == null || getClass() != object.getClass()) return false;StudentDO studentDO = (StudentDO) object;if (id != studentDO.id) return false;if (age != studentDO.age) return false;if (name != null ? !name.equals(studentDO.name) : studentDO.name != null) return false;if (address != null ? !address.equals(studentDO.address) : studentDO.address != null) return false;return true;}@Overridepublic int hashCode() {int result = id;result = 31 * result + (name != null ? name.hashCode() : 0);result = 31 * result + age;result = 31 * result + (address != null ? address.hashCode() : 0);return result;} } StudentDO.java參考博文
2.3 創建持久層
技巧01:持久層接口只需要繼承?JpaRepository 接口即可
package cn.xiangxu.jpa_demo03.domain.repository;import cn.xiangxu.jpa_demo03.domain.domain_do.StudentDO; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository;/*** @author 王楊帥* @create 2018-08-13 21:53* @desc 學生持久層接口**/ public interface StudentRepository extends JpaRepository<StudentDO, Integer> {} StudentRepository.java技巧02:需要使用持久層實例時,只需要進行依賴注入即可
技巧03:持久層接口上不用寫? ?@Repository? ,因為繼承了?JpaRepository 接口后就已經是一個被Spring容器管理的持久層Bean啦
技巧04:Repository相關接口
?? ? ?
2.4 測試持久層
技巧01:繼承?JpaRepository 接口后就可以有很過方法可以使用
技巧02:可以直接使用的原因是:攔截 + JDK動態代理
package cn.xiangxu.jpa_demo03.domain.repository;import cn.xiangxu.jpa_demo03.domain.domain_do.StudentDO; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;import java.util.List;import static org.junit.Assert.*;@RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class StudentRepositoryTest {@Autowiredprivate StudentRepository studentRepository;@Testpublic void findall() {List<StudentDO> all = studentRepository.findAll();System.out.println(all);}} View Code技巧03:jpa支持自定義SQL【借助@Query注解實現】
?
?3 Projections 對查詢結果的擴展
3.1 返回類型建模
Spring JPA 對 Projections 的擴展的支持,個人覺得這是個非常好的東西,從字面意思上理解就是映射,指的是和 DB 的查詢結果的字段映射關系。一般情況下,我們是返回的字段和 DB 的查詢結果的字段是一一對應的,但有的時候,需要返回一些指定的字段,不需要全部返回,或者返回一些復合型的字段,還得自己寫邏輯。Spring Data 正是考慮到了這一點,允許對專用返回類型進行建模,以便更有選擇地將部分視圖對象。(聲明:來自gitChat)
3.1.1 需求
只需要查詢學生的姓名和年齡信息,其余信息不進行查詢
3.1.2 思路
聲明一個接口,包含我們要返回的屬性的方法即可
3.1.3 編程實現
》根據實體類中屬性的get方法創建接口
技巧01:接口中的方法就是需要獲取的字段在實體類中對應的get方法
package cn.xiangxu.jpa_demo03.domain.domain_do;/*** @author 王楊帥* @create 2018-08-13 22:16* @desc**/ public interface StudentBaseInfo {String getName();Integer getAge();} StudentBaseInfo.java》修改持久層接口中的方法
技巧01:返回值用StudentBaseInfo類型
package cn.xiangxu.jpa_demo02.repository;import cn.xiangxu.jpa_demo02.domain.domain_do.StudentBaseInfo; import cn.xiangxu.jpa_demo02.domain.domain_do.StudentDO; import org.springframework.data.jpa.repository.JpaRepository;import java.util.List;/*** @author 王楊帥* @create 2018-08-13 10:00* @desc**/ public interface StudentRepository extends JpaRepository<StudentDO, Integer> {/*** 根據姓名和年齡* @param name 姓名* @param age 年齡* @return*/List<StudentDO> findByNameAndAge(String name, Integer age);/*** 根據年齡段查詢【PS: 開區間】* @param start 最小值* @param end 最大值* @return*/List<StudentDO> findByAgeBetween(Integer start, Integer end);/*** 小于給定年齡【PS: 開區間】* @param age 年齡* @return*/List<StudentDO> findByAgeLessThan(Integer age);/*** 小于給定年齡【PS: 閉區間】* @param age 年齡* @return*/List<StudentDO> findByAgeLessThanEqual(Integer age);List<StudentDO> findByAgeGreaterThan(Integer age);List<StudentDO> findByAgeGreaterThanEqual(Integer age);List<StudentDO> findByName(String name);List<StudentDO> findByNameEquals(String name);List<StudentDO> findByNameIs(String name);List<StudentDO> findByAgeAfter(Integer age);List<StudentDO> findByAgeBefore(Integer age);List<StudentDO> findByAgeAfterOrAgeEquals(Integer age, Integer age2);// List<StudentDO> findByAddress(String address); List<StudentBaseInfo> findByAddress(String address);} StudentRepository.java》測試類
package cn.xiangxu.jpa_demo03.domain.repository;import cn.xiangxu.jpa_demo03.domain.domain_do.StudentBaseInfo; import cn.xiangxu.jpa_demo03.domain.domain_do.StudentDO; import cn.xiangxu.jpa_demo03.repository.StudentRepository; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class StudentRepositoryTest {@Autowiredprivate StudentRepository studentRepository;@Testpublic void findall() {List<StudentDO> all = studentRepository.findAll();System.out.println(all);}@Testpublic void findByName() {List<StudentBaseInfo> byNameIs = studentRepository.findByNameIs("楊玉林");System.out.println(byNameIs);}} View Code》跳坑01:通過這種方式獲取到的數據是一個Map對象,如何轉化成一個實體類列表呢
》填坑01:創建一個實體類,這個實體類的字段要和創建的接口中方法對應實體類類的字段名保持一致【PS:本博文就繼續使用之前的實體類】,將查詢到的數據轉化成流,然后利用peek這個中間操作進行轉化
package cn.xiangxu.jpa_demo03.domain.repository;import cn.xiangxu.jpa_demo03.domain.domain_do.StudentBaseInfo; import cn.xiangxu.jpa_demo03.domain.domain_do.StudentDO; import cn.xiangxu.jpa_demo03.repository.StudentRepository; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;import java.util.ArrayList; import java.util.List;@RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class StudentRepositoryTest {@Autowiredprivate StudentRepository studentRepository;@Testpublic void findall() {List<StudentDO> all = studentRepository.findAll();System.out.println(all);}@Testpublic void findByName() {List<StudentBaseInfo> byNameIs = studentRepository.findByNameIs("楊玉林");System.out.println(byNameIs);}@Testpublic void findBYName02() {List<StudentBaseInfo> byNameIs = studentRepository.findByNameIs("王楊帥");List<StudentDO> studentDOList = new ArrayList<>();byNameIs.stream().peek(i -> {StudentDO studentDO = new StudentDO();BeanUtils.copyProperties(i, studentDO);studentDOList.add(studentDO);}).forEach(System.out::println);System.out.println(studentDOList);}} View Code》轉化后的結果為
?
4 實體類注解
待更新...... 2018年8月14日20:21:24
?
5 關聯查詢
說明:本博是利用原生的SQL進行關聯查詢
5.1 需求
現有兩張數據庫表:
product -> 存放產品信息
provider -> 存放供應商信息
product 和 provider 的關系時多對一的關系,即:一個供應商可能和多個產品對應
5.2 思路
知己利用SQL的關聯查詢實現
5.3 編程實現
5.3.1 數據表
技巧01:product中的provider_id字段和provider的id字段作為關聯查詢的橋梁
技巧02:理論上說,product中的provider_id字段應該設置成外鍵,但是為了開發方便,此處不進行設置【PS: 開發人員知道這是外鍵即可】
/* Navicat MySQL Data TransferSource Server : mysql5.4 Source Server Version : 50540 Source Host : localhost:3306 Source Database : testdemoTarget Server Type : MYSQL Target Server Version : 50540 File Encoding : 65001Date: 2018-08-14 20:25:59 */SET FOREIGN_KEY_CHECKS=0;-- ---------------------------- -- Table structure for `product` -- ---------------------------- DROP TABLE IF EXISTS `product`; CREATE TABLE `product` (`id` int(11) NOT NULL AUTO_INCREMENT,`product_name` varchar(255) NOT NULL,`product_price` double NOT NULL,`provider_id` int(11) NOT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;-- ---------------------------- -- Records of product -- ---------------------------- INSERT INTO `product` VALUES ('1', '天友純牛奶', '3', '1'); INSERT INTO `product` VALUES ('2', '天友核桃花生奶', '2', '1'); INSERT INTO `product` VALUES ('3', '福特福克斯', '13', '2'); INSERT INTO `product` VALUES ('4', '福特嘉年華', '9', '2');-- ---------------------------- -- Table structure for `provider` -- ---------------------------- DROP TABLE IF EXISTS `provider`; CREATE TABLE `provider` (`id` int(11) NOT NULL AUTO_INCREMENT,`provider_name` varchar(255) NOT NULL,`provider_phone` varchar(255) NOT NULL,`provider_address` varchar(255) NOT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;-- ---------------------------- -- Records of provider -- ---------------------------- INSERT INTO `provider` VALUES ('1', '天友乳業', '13282882818', '重慶市大足區'); INSERT INTO `provider` VALUES ('2', '長安制造', '13212112121', '重慶市渝北區'); View Code5.3.2 創建實體類
技巧01:利用IDEA自動生成
技巧02:ProductInfoDTO這個實體類是用來封裝產品信息和供應商信息的
package cn.xiangxu.jpa_demo04.domain.domain_do;import lombok.ToString;import javax.persistence.*;/*** @author 王楊帥* @create 2018-08-14 19:54* @desc**/ @Entity @ToString @Table(name = "product", schema = "testdemo", catalog = "") public class ProductDO {private int id;private String productName;private double productPrice;private int providerId;@Id@Column(name = "id")public int getId() {return id;}public void setId(int id) {this.id = id;}@Basic@Column(name = "product_name")public String getProductName() {return productName;}public void setProductName(String productName) {this.productName = productName;}@Basic@Column(name = "product_price")public double getProductPrice() {return productPrice;}public void setProductPrice(double productPrice) {this.productPrice = productPrice;}@Basic@Column(name = "provider_id")public int getProviderId() {return providerId;}public void setProviderId(int providerId) {this.providerId = providerId;}@Overridepublic boolean equals(Object object) {if (this == object) return true;if (object == null || getClass() != object.getClass()) return false;ProductDO productDO = (ProductDO) object;if (id != productDO.id) return false;if (Double.compare(productDO.productPrice, productPrice) != 0) return false;if (providerId != productDO.providerId) return false;if (productName != null ? !productName.equals(productDO.productName) : productDO.productName != null)return false;return true;}@Overridepublic int hashCode() {int result;long temp;result = id;result = 31 * result + (productName != null ? productName.hashCode() : 0);temp = Double.doubleToLongBits(productPrice);result = 31 * result + (int) (temp ^ (temp >>> 32));result = 31 * result + providerId;return result;} } ProductDO.java package cn.xiangxu.jpa_demo04.domain.domain_do;import lombok.ToString;import javax.persistence.*;/*** @author 王楊帥* @create 2018-08-14 19:54* @desc**/ @Entity @ToString @Table(name = "provider", schema = "testdemo", catalog = "") public class ProviderDO {private int id;private String providerName;private String providerPhone;private String providerAddress;@Id@Column(name = "id")public int getId() {return id;}public void setId(int id) {this.id = id;}@Basic@Column(name = "provider_name")public String getProviderName() {return providerName;}public void setProviderName(String providerName) {this.providerName = providerName;}@Basic@Column(name = "provider_phone")public String getProviderPhone() {return providerPhone;}public void setProviderPhone(String providerPhone) {this.providerPhone = providerPhone;}@Basic@Column(name = "provider_address")public String getProviderAddress() {return providerAddress;}public void setProviderAddress(String providerAddress) {this.providerAddress = providerAddress;}@Overridepublic boolean equals(Object object) {if (this == object) return true;if (object == null || getClass() != object.getClass()) return false;ProviderDO that = (ProviderDO) object;if (id != that.id) return false;if (providerName != null ? !providerName.equals(that.providerName) : that.providerName != null) return false;if (providerPhone != null ? !providerPhone.equals(that.providerPhone) : that.providerPhone != null)return false;if (providerAddress != null ? !providerAddress.equals(that.providerAddress) : that.providerAddress != null)return false;return true;}@Overridepublic int hashCode() {int result = id;result = 31 * result + (providerName != null ? providerName.hashCode() : 0);result = 31 * result + (providerPhone != null ? providerPhone.hashCode() : 0);result = 31 * result + (providerAddress != null ? providerAddress.hashCode() : 0);return result;} } ProviderDO.java package cn.xiangxu.jpa_demo04.domain.domain_do;import lombok.Builder; import lombok.Data;/*** @author 王楊帥* @create 2018-08-14 20:03* @desc**/ @Data @Builderpublic class ProductInfoDTO {private int id;private String productName;private double productPrice;private int providerId;private String providerName;private String providerPhone;private String providerAddress;} ProductInfoDTO.java5.3.3 創建持久層接口
技巧01:這里使用@Query進行原生的SQL查詢,所以直接在ProductDAO中就可以查詢出產品和供應商的信息
package cn.xiangxu.jpa_demo04.repository;import cn.xiangxu.jpa_demo04.domain.domain_do.ProductDO; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query;import java.util.List; import java.util.Map;/*** @author 王楊帥* @create 2018-08-14 19:55* @desc**/ public interface ProductDAO extends JpaRepository<ProductDO, Integer> {@Query(nativeQuery = true,value = "SELECT product_name, product_price, provider_name, provider_phone, provider_address\n" +"FROM product\n" +"JOIN provider \n" +"ON product.provider_id = provider.id\n" +"WHERE product.provider_id = ?1")List<Map<String, Object>> findTest(Integer providerId);} ProductDAO.java5.3.4 測試
技巧01:多表關聯查詢時獲取到數據是Map類型的,需要進行一層轉化;本博文用的是阿里巴巴的 fastjson 進行轉化
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.1.46</version></dependency> View Code坑01:fastjson 轉化時 map 的 key 要和 實體類的屬性 保持一致,不一致時只有通過本辦法實現了
package cn.xiangxu.jpa_demo04.repository;import cn.xiangxu.jpa_demo04.JpaDemo04ApplicationTests; import cn.xiangxu.jpa_demo04.domain.domain_do.DoctorInfoDetail; import cn.xiangxu.jpa_demo04.domain.domain_do.ProductDO; import cn.xiangxu.jpa_demo04.domain.domain_do.ProductInfoDTO; import com.alibaba.fastjson.JSONObject; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import java.util.ArrayList; import java.util.List; import java.util.Map;@Component public class ProductDaoTest extends JpaDemo04ApplicationTests {@Autowiredprivate ProductDAO productDAO;@Testpublic void test01() {List<ProductDO> all = productDAO.findAll();System.out.println(all);}@Testpublic void test02() {List<Map<String, Object>> test = productDAO.findTest(2);System.out.println(test);List<ProductInfoDTO> productInfoDTOS = new ArrayList<>();for (Integer i = 0; i < test.size(); i++) {Map<String, Object> info = test.get(i); // ProductInfoDTO productInfoDTO = JSONObject.parseObject(JSONObject.toJSONString(test.get(i)), ProductInfoDTO.class);ProductInfoDTO productInfoDTO = ProductInfoDTO.builder().productName((String)info.get("product_name")).productPrice((Double)info.get("product_price")).providerName((String)info.get("provider_name")).providerPhone((String)info.get("provider_phone")).providerAddress((String)info.get("provider_address")).build();System.out.println(productInfoDTO);productInfoDTOS.add(productInfoDTO);}System.out.println(productInfoDTOS);}} View Code?
?
轉載于:https://www.cnblogs.com/NeverCtrl-C/p/9471496.html
總結
以上是生活随笔為你收集整理的SpringBoot24 SpringDataJPA环境搭建、实体类注解、关联查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入理解MyBatis的原理(三):配置
- 下一篇: day1-Python擅长的领域+学习内