JDBC
最底层技术规范(相对于JPA而言)
定义:java语言连接关系数据库进行SQL操作的规范,各个数据库厂商实现了该规范(JDBC驱动程序)。
MyBatis
定义:基于java实现的SQL映射框架,
封装了JDBC操作。
完成的是SQL到方法,实现是半自动化的。
容易理解。
Hibernate(冬眠)
定义:基于java实现的ORM(对象关系映射)框架,
封装了JDBC操作。
类直接映射表,实现是自动化的,高度封装。Domain model persistence for relational databases
领域模型(业务对象)持久化到关系数据库
JPA
Java Persistence API (JPA) specification
hibernate是JPA的一种参考实现。
JPA的一个实现:Hibernate,TopLink,
JPA是技术规范,抽象的定义。如:碳酸饮料,啤酒。
Hibernate是一个实现 。如 可乐,雪碧。
三者的联系
JDBC是技术规范,实现:mysql,db2,oracle,postgreSQL,
只使用JDBC中的API,看不到厂商的影子,实际的工作都是厂商驱动完成的。MyBatis:SQL映射,介于两者之间。
Spring Data JDBC
JPA是技术规范,实现:hiberbnate,topLink
Spring Data JPA默认使用了hibernate,切换到toplink实现,编码时只是用JPA的API,
看不到hibernate的影子。
JDBC和JPA的区别
JDBC,JPA 都是 Java 语言中定义的技术规范,JDBC 连接关系数据库,执行 SQL 语言,
JPA 建立在 JDBC 之上,封装 JDBC ,JPA 的方法操作,底层是 JDBC。
MySQL默认连接是150个
代码演示
先创建一个工程目录,选择工程所需的依赖
工程目录如图:
City.java
package com.newer.jpa;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* POJO/Domain Object/使用JPA的注解进行ORM
*
* 实体类映射到表,类的属性映射到表的列,不写 SQL,自动化
* @author Admin
*
*/
@Entity
//对应表名
@Table(name = "city")
public class City {
//驼峰式命名法
//+-------------+----------+------+-----+---------+----------------+
//| Field | Type | Null | Key | Default | Extra |
//+-------------+----------+------+-----+---------+----------------+
//| ID | int | NO | PRI | NULL | auto_increment |
//| Name | char(35) | NO | | | |
//| CountryCode | char(3) | NO | MUL | | |
//| District | char(20) | NO | | | |
//| Population | int | NO | | 0 | |
// 主键
@Id
// 自增长
@GeneratedValue
Long id;
@Column(name = "name", nullable = true)
String name;
//
String countryCode;
// 类中属性名与表中列名一致时,可以不写注解
String district;
int population;
public City() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getDistrict() {
return district;
}
public void setDistrict(String district) {
this.district = district;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public String toString() {
return "City [id=" + id + ", name=" + name + ", countryCode=" + countryCode + ", district=" + district
+ ", population=" + population + "]";
}
}
CityRepository.java
package com.newer.jpa;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
/**
* 数据持久化 操作
* @author Admin
*
*/
@Repository
public interface CityRepository extends PagingAndSortingRepository<City, Long>{
// CRUD 基本操作 框架已经实现了,不需要你写了
// 排序,分页也实现了,不需要你写
// TODO 额外的一些操作,需要自己实现
}
CityController.java
package com.newer.jpa;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Restful API定义实现
* @author Admin
*
*/
@RestController
//请求映射
@RequestMapping("/api/city")
public class CityController {
// 依赖service
// 也可以直接注入repository
@Autowired
CityRepository cityRepository;
/**
* 分页获得数据:GET "/api/city ?p=0&s=20"
*
* @RequestParam:字符串查询参数
* @param page 页码数,
* @param size 一页的记录数
* @return 分页信息:数据,总页数,当前页,当前页是否第一页等
*/
@GetMapping
public Page<City> findAll(
@RequestParam(name = "p" ,defaultValue = "0") int page,
@RequestParam(name = "s",defaultValue = "300") int size
) {
// API是Spring Data设计
// 排序规则
// order by name,id,desc
Sort s1=Sort.by("name").ascending().and(Sort.by("id").descending());
// order by name,id
Sort s2=Sort.by("name","id");
// 分页信息
// 1.页码数,基于0开始的索引
// 2.记录数,20条记录
// 3.排序规则
// Pageable pageable=PageRequest.of(0, 20,Sort.by("id")) ;
Pageable pageable=PageRequest.of(page, size,Sort.by("id")) ;
return cityRepository.findAll(pageable);
}
}
HomeController.java
package com.newer.jpa;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String home() {
return "index.html";
}
}
index.html
<!doctype html>
<html lang="en">
<head>
<title>数据分页</title>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<!-- axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- vue -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-3">数据分页</h1>
<p class="lead">Vue & Spring Boot &MyBatis& MySQL</p>
</div>
</div>
<div id="app" class="container">
<h1>{{totalPages}}</h1>
<!-- 表格 -->
<table class="table">
<thead>
<tr>
<th>编号</th>
<th>城市</th>
<th>国家</th>
<th>所在地区</th>
<th>人口</th>
</tr>
</thead>
<tbody>
<tr v-for="(city, index) in cityList" :key="index">
<td>{{city.id}}</td>
<td>{{city.name}}</td>
<td>{{city.countryCode}}</td>
<td>{{city.district}}</td>
<td>{{city.population}}</td>
</tr>
</tbody>
</table>
<!-- 分页 -->
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
<li class="page-item ">
<a class="page-link" href="#" aria-label="Previous">
<span @click="page(index--)" aria-hidden="true" :class="{active: index===number}">上一页</span>
</a>
</li>
<!-- 默认的样式 -->
<!-- <li class="page-item active"><a class="page-link" href="#">当前</a></li> -->
<li v-for="(n, index) in totalPages" :key="index" class="page-item" :class="{active: n-1===number}">
<a @click="page(n-1)" class="page-link" href="#">
{{n}}
</a>
</li>
<li class="page-item">
<a class="page-link" href="#" aria-label="Next">
<span @click="page(index++)" aria-hidden="true" :class="{active: index===number}">下一页</span>
</a>
</li>
</ul>
</nav>
</div>
<script>
new Vue({
el: '#app',
data: {
cityList: [],
// 总页数
totalPages: '',
// 当前页
number: '',
index: 1
},
methods: {
page: function (num) {
axios.get('/api/city', {
params: {
p: num
}
})
.then(res => {
// console.log(res);
this.cityList = res.data.content;
this.totalPages = res.data.totalPages;
this.number = res.data.number;
})
},
next: function (i) {
axios.get('/api/city', {
params: {
p: i
}
})
.then(res => {
console.log(res);
})
}
},
created() {
// 本地URL
let url = '/api/city';
axios.get(url)
.then(res => {
console.log(res)
this.cityList = res.data.content;
this.totalPages = res.data.totalPages;
this.number = res.data.number;
})
.catch(err => {
console.error(err);
})
},
})
</script>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
</body>
</html>
application.properties
#数据源
spring.datasource.url=jdbc:mysql://阿里云数据库ip:3306/world
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#请求参数
spring.http.log-request-details=true
#Spring MVC
logging.level.web=debug
#数据源默认的数据库连接池信息
logging.level.com.zaxxer=debug
#hibernate(JPA)
logging.level.org.hibernate.sql=debug
#jpa/hibernate 驼峰命名规则的映射
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
现在可以来看看效果:
从数据库取得的数据
前端上渲染:(之前设置为一页有300条记录)