转载

数据持久化存储之JPA操作

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条记录)

 

正文到此结束
本文目录