目录
三、对象关系映射 --- 如何让 dept 和 emp 表产生关系
Spring Data 与 JPA
JPA 是 Java Persistence API 的简称,中文名 Java 持久层 API, 是 JDK5.0 注解 或 XML 描述对象- 关系表的映射关系,并将运行期的实体对象持久化到数据库中,JPA 是 ORM 映射框架。(51CTO老齐学编程)
ORM思想
- 对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。 本质上就是将数据从一种形式转换到另外一种形式。
- 主要目的:操作实体类就相当于操作数据库中的表。
- 建立两个映射关系:
实体类和表的映射关系
实体类中的属性和表中字段的映射关系
不再重点关注:sql语句
- 实现ORM思想的框架:mybatis、hibernate。
JPA规范
当ORM思想刚出现的时候,许多厂家推出一大堆框架采用ORM思想,所以sun公司最后为了统一标准,指定了jpa规范,实现了这个规范的有:hibernate、toplink等,真正工作的不是jpa,而是hibernate或者toplink等框架。
一、基本的CRUD
创建数据库文件
执行 SQL 脚本
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50718
Source Host : localhost:3306
Source Schema : scott
Target Server Type : MySQL
Target Server Version : 50718
File Encoding : 65001
Date: 20/04/2018 16:57:32
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for bonus
-- ----------------------------
DROP TABLE IF EXISTS `bonus`;
CREATE TABLE `bonus` (
`ename` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`job` varchar(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`sal` decimal(7, 2) NULL DEFAULT NULL,
`comm` decimal(7, 2) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for dept
-- ----------------------------
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
`deptno` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`dname` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`loc` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`deptno`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 54 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO `dept` VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO `dept` VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO `dept` VALUES (40, 'OPERATIONS', 'BOSTON');
-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`empno` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`ename` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`job` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`mgr` int(10) UNSIGNED NULL DEFAULT NULL,
`hiredate` date NULL DEFAULT NULL,
`sal` decimal(7, 2) NULL DEFAULT NULL,
`comm` decimal(7, 2) NULL DEFAULT NULL,
`deptno` int(10) UNSIGNED NULL DEFAULT NULL,
PRIMARY KEY (`empno`) USING BTREE,
INDEX `deptno`(`deptno`) USING BTREE,
CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptno`) REFERENCES `dept` (`deptno`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 7935 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800.00, NULL, 20);
INSERT INTO `emp` VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600.00, 300.00, 30);
INSERT INTO `emp` VALUES (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250.00, 500.00, 30);
INSERT INTO `emp` VALUES (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975.00, NULL, 20);
INSERT INTO `emp` VALUES (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250.00, 1400.00, 30);
INSERT INTO `emp` VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850.00, NULL, 30);
INSERT INTO `emp` VALUES (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450.00, NULL, 10);
INSERT INTO `emp` VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1987-07-13', 3000.00, NULL, 20);
INSERT INTO `emp` VALUES (7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5000.00, NULL, 10);
INSERT INTO `emp` VALUES (7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500.00, 0.00, 30);
INSERT INTO `emp` VALUES (7876, 'ADAMS', 'CLERK', 7788, '1987-07-13', 1100.00, NULL, 20);
INSERT INTO `emp` VALUES (7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950.00, NULL, 30);
INSERT INTO `emp` VALUES (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000.00, NULL, 20);
INSERT INTO `emp` VALUES (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300.00, NULL, 10);
-- ----------------------------
-- Table structure for salgrade
-- ----------------------------
DROP TABLE IF EXISTS `salgrade`;
CREATE TABLE `salgrade` (
`grade` int(10) UNSIGNED NULL DEFAULT NULL,
`losal` int(10) UNSIGNED NULL DEFAULT NULL,
`hisal` int(10) UNSIGNED NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of salgrade
-- ----------------------------
INSERT INTO `salgrade` VALUES (1, 700, 1200);
INSERT INTO `salgrade` VALUES (2, 1201, 1400);
INSERT INTO `salgrade` VALUES (3, 1401, 2000);
INSERT INTO `salgrade` VALUES (4, 2001, 3000);
INSERT INTO `salgrade` VALUES (5, 3001, 9999);
SET FOREIGN_KEY_CHECKS = 1;
创建项目
下一步
next:
pom.xml 文件介绍
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kangna</groupId>
<artifactId>springdatajpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springdatajpa</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 加载 hibernate 核心包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 加载 web项目所需要的包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 加载 MySQL的驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 用于测试的包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
maven 镜像 要配置好,我第一次 竟然 下载不到springWeb 依赖包 ,重新创建了一个新的工程。
resource 下 application.properties 配置 数据源的基本信息
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/scott?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
# display sql in console
spring.jpa.show-sql=true
创建实体类
package com.kangna.springdatajpa.entity;
import javax.persistence.*;
/********************************
* @Author: kangna
* @Date: 2020/1/9 16:59
* @Version: 1.0
* @Desc:
********************************/
@Entity // 告诉Spring Boot 这个一个实体类,在 SB 启动的时候加载这个类
@Table(name = "dept")
public class Dept {
@Id // 指定主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增长 相当于 MySQL中的 auto_increment
@Column(name = "deptno") // deptno 属性 对用deptno 字段
private Integer deptno;
@Column(name = "dname")
private String dname;
@Column(name = "loc")
private String location;
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
创建接口 DeptRepository
package com.kangna.springdatajpa.repository;
import com.kangna.springdatajpa.entity.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
/** JpaRepository 是Spring Boot 为我们提供的简化类,默认提供了增删改查方法
* 我们需要 定义 Repository 接口就可以了,在 Spring Boot 启动的时候会自动帮我们生成具体的实现类,来实现具体的CRUD方法
*/
public interface DeptRepository extends JpaRepository<Dept, Integer>{
}
创建DeptController
package com.kangna.springdatajpa.controller;
import com.kangna.springdatajpa.entity.Dept;
import com.kangna.springdatajpa.repository.DeptRepository;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import java.util.Optional;
/********************************
* @Author: kangna
* @Date: 2020/1/9 17:30
* @Version: 1.0
* @Desc:
********************************/
@Controller
@RequestMapping("/dept")
public class DeptController {
@Resource
private DeptRepository deptRepository = null;
@GetMapping("/{id}")
@ResponseBody
public Dept findById(@PathVariable("id") Integer id) {
// Optional 是实体类的包装类, 用于判断对象是否存在
Optional<Dept> optional = deptRepository.findById(id);
Dept dept = null;
if (optional.isPresent() == true) {
// 获取到对应的实体类
dept = optional.get();
}
return dept;
}
}
启动 Web应用
到 指定的 路径查看查询结果
添加 ,修改 ,删除
控制台打印:
定义 好映射关系 ,hibernate 帮我们自动生成 SQL 语句
二、 JPA数据查询
需求:按照 部门名称 查找部门信息
接口中 方法的定义
package com.kangna.springdatajpa.repository;
import com.kangna.springdatajpa.entity.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/** JpaRepository 是Spring Boot 为我们提供的简化类,默认提供了增删改查方法
* 我们需要 定义 Repository 接口就可以了,在 Spring Boot 启动的时候会自动帮我们生成具体的实现类,来实现具体的CRUD方法
*/
public interface DeptRepository extends JpaRepository<Dept, Integer>{
// select * from dept where dname ....
//List<Dept> findByDName(String dname);
/**
* JPQL java persistence query language 持久化查询语言
* 类SQL语法,使用时注意以下几点
* (1) 大多数情况下,将 * 替换为别名
* (2) 表名改为类名
* (3) 字段名改为 属性名
*/
@Query("select d from Dept d where d.dname = 'Tranning'")
List<Dept> findDepts();
}
findDepts 方法 在 DeptController 类中的实现
@GetMapping("/find")
@ResponseBody
public List<Dept> findDepts(String dname) {
List<Dept> list = deptRepository.findDepts();
return list;
}
查询结果
需求:按照部门编号升序 查询所有部门
JPQL实现
public interface DeptRepository extends JpaRepository<Dept, Integer>{
// select * from dept where dname ....
//List<Dept> findByDName(String dname);
/**
* JPQL java persistence query language 持久化查询语言
* 类SQL语法,使用时注意以下几点
* (1) 大多数情况下,将 * 替换为别名
* (2) 表名改为类名
* (3) 字段名改为 属性名
*/
//@Query("select d from Dept d where d.dname = 'Tranning'")
//List<Dept> findDepts();
@Query("select d from Dept d where d.dname = :dn order by deptno asc")
// 将 dname 参数的值 带入到 :dn 中
List<Dept> findDepts(@Param("dn") String dname);
}
Controller 完善
@GetMapping("/find")
@ResponseBody
public List<Dept> findDepts(String dname) {
List<Dept> list = deptRepository.findDepts(dname);
return list;
}
结果显示
补充:看看 JpaRepository
package org.springframework.data.jpa.repository;
import java.util.List;
import javax.persistence.EntityManager;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
@Override
List<T> findAll();
@Override
List<T> findAll(Sort sort);
@Override
List<T> findAllById(Iterable<ID> ids);
@Override
<S extends T> List<S> saveAll(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
JpaRepository接口 定义我们 常用 的 CRUD方法
三、对象关系映射 --- 如何让 dept 和 emp 表产生关系
添加 emp 实体类
package com.kangna.springdatajpa.entity;
import javax.persistence.*;
import java.util.Date;
/********************************
* @Author: kangna
* @Date: 2020/1/9 21:42
* @Version: 1.0
* @Desc:
********************************/
@Entity
@Table
public class Emp {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Float sal;
private Float comm;
// 多的一方 使用 ManyToOne 一个部门多个员工
@ManyToOne
@JoinColumn(name = "deptno") // 指定关联的 字段,一般为主键
private Dept dept;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Float getSal() {
return sal;
}
public void setSal(Float sal) {
this.sal = sal;
}
public Float getComm() {
return comm;
}
public void setComm(Float comm) {
this.comm = comm;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
EmpController
package com.kangna.springdatajpa.controller;
import com.kangna.springdatajpa.entity.Dept;
import com.kangna.springdatajpa.entity.Emp;
import com.kangna.springdatajpa.repository.DeptRepository;
import com.kangna.springdatajpa.repository.EmpRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
/********************************
* @Author: kangna
* @Date: 2020/1/9 21:57
* @Version: 1.0
* @Desc:
********************************/
@RestController // 默认所有的方法返回的是 JSON 字符串
@RequestMapping("/emp")
public class EmpController {
@Autowired
private EmpRepository empRepository;
@Autowired
private DeptRepository deptRepository;
@GetMapping("/{id}")
public Emp findById(@PathVariable("id") Integer id) {
return empRepository.findById(id).get();
}
@GetMapping("/create")
public Emp create() {
Emp emp = new Emp();
emp.setComm(0f);
emp.setEname("kangna");
emp.setHiredate(new Date());
emp.setJob("deve");
emp.setMgr(null);
emp.setSal(25000f);
Dept dept = deptRepository.findById(20).get();
emp.setDept(dept);
empRepository.save(emp);
return emp;
}
}
新增
控制台打印出的SQL
insert into emp (comm, deptno, ename, hiredate, job, mgr, sal) values (?, ?, ?, ?, ?, ?, ?)
再去数据库看看数据是否插入