Springboot使用Spring Data JPA实现数据库操作


Posted in Java/Android onJune 30, 2021

SpringBoot整合JPA

使用数据库是开发基本应用的基础,借助于开发框架,我们已经不用编写原始的访问数据库的代码,也不用调用JDBC(Java Data Base Connectivity)或者连接池等诸如此类的被称作底层的代码,我们将从更高的层次上访问数据库,这在Springboot中更是如此,本章我们将详细介绍在Springboot中使用 Spring Data JPA 来实现对数据库的操作。

JPA & Spring Data JPA

JPA是Java Persistence API的简称,中文名Java持久层API,是Sun官方提出的Java持久化规范.

其设计目标主要是为了简化现有的持久化开发工作和整合ORM技术

JPA使用XML文件或注解(JDK 5.0或更高版本)来描述对象-关联表的映射关系,能够将运行期的实体对象持久化到数据库,它为Java开发人员提供了一种ORM工具来管理Java应用中的关系数据。

简单地说,JPA就是为POJO(Plain Ordinary Java Object)提供持久化的标准规范,即将Java的普通对象通过对象关系映射(Object-Relational Mapping,ORM)持久化到数据库中。

由于JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,因而具有易于使用、伸缩性强等优点。

Spring Data JPA 是 Spring 基于 Spring Data 框架、在JPA 规范的基础上开发的一个框架,使用 Spring Data JPA 可以极大地简化JPA 的写法,可以在几乎不用写实现的情况下实现对数据库的访问和操作,除了CRUD外,还包括分页和排序等一些常用的功能。

Spring Data JPA 还提供了对分页查询、自定义SQL、查询指定N条记录、联表查询等功能的支持

JPA不是一种新的ORM框架,它的出现只是用于规范现有的ORM技术,它不能取代现有的Hibernate、TopLink等框架。相反,在采用JPA开发时,我们将仍将使用到这些ORM框架,只是此时开发出来的应用不再依赖于某个持久化提供商。应用可以在不修改代码的情况下在任何JPA环境下运行,真正做到低耦合,可扩展的程序设计。

Hibernate & JPA

1、JPA

全称Java Persistence API,通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

JPA的出现有两个原因:

其一,简化现有Java EE和Java SE应用的对象持久化的开发工作;

其二,Sun希望整合对ORM技术,实现持久化领域的统一。

JPA提供的技术:

1)ORM映射元数据:JPA支持XML和JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;

2)JPA 的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。

3)查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

2、JPA & Hibernate 关系

JPA是规范,Hibernate是框架,JPA是持久化规范,而Hibernate实现了JPA。

Hibernate VS Mybatis

Mybatis:小巧、方便、高效、简单、直接、半自动

Hibernate:强大、方便、高效、复杂、绕弯子、全自动

一、导入依赖

<dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <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>
        </dependency>
    </dependencies>

二、简单的CRUD

1、配置文件

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/shy
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  jpa:
    hibernate:
      #定义数据库表的生成策略 create 创建一个表 update 更新或者创建数据表
      ddl-auto: update
      #控制台显示sql语句
    show-sql: true
server:
  port: 80

其中,spring.jpa.hibernate.ddl-auto 参数用来配置是否开启自动更新数据库表结构,可取create、create-drop、update、validate、none五个值。

  • create 每次加载hibernate时,先删除已存在的数据库表结构再重新生成;
  • create-drop 每次加载hibernate时,先删除已存在的数据库表结构再重新生成,并且当 sessionFactory关闭时自动删除生成的数据库表结构;
  • update 只在第一次加载hibernate时自动生成数据库表结构,以后再次加载hibernate时根据model类自动更新表结构;
  • validate 每次加载hibernate时,验证数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
  • none 关闭自动更新

2、实体类

Shop:

package com.shy.entity;
import lombok.Data;
import javax.persistence.*;
@Data
//使用jpa注解 配置映射关系
@Entity//告诉jpa这是一个实体类 和数据表映射的类
public class Shop{
    @Id//表明这是以一个主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增
    private Integer shopId;

    @Column(length = 20)
    private String shopName;

    private double price;

    private Integer shopClassId;

    private Integer num;
}

ShopClass,商品类别

package com.shy.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Data
@Entity
public class ShopClass {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer shopClassId;

    private String shopClassName;
}

3、Dao层

编写dao继承JpaRepository类,泛型传入 要操作的实体类,和主键类型

package com.example.dao;
import com.shy.entity.Shop;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/* 参数一 T :当前需要映射的实体
 * 参数二 ID :当前映射的实体中的OID(映射对象标识符,数据库主键)的类型*/

@Repository
public interface ShopRepository extends JpaRepository<Shop,Integer> {
    /*
     * 我们在这里直接继承 JpaRepository
     * 这里面已经有很多现成的方法了
     * 这也是JPA的一大优点
     * 我们可以直接使用这些方法,包括其父类的好多方法。
     * */
}

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);// 根据ID集合查询实体

	@Override
	<S extends T> List<S> saveAll(Iterable<S> entities);// 保存并返回(修改后的)实体集合

	void flush();// 提交事务

	<S extends T> S saveAndFlush(S entity); // 保存实体并立即提交事务

	<S extends T> List<S> saveAllAndFlush(Iterable<S> entities);

	@Deprecated
	default void deleteInBatch(Iterable<T> entities){deleteAllInBatch(entities);}

	void deleteAllInBatch(Iterable<T> entities); // 批量删除实体集合

	void deleteAllByIdInBatch(Iterable<ID> ids);

	void deleteAllInBatch();// 批量删除所有实体

	@Deprecated
	T getOne(ID id);// 根据ID查询实体

	T getById(ID id);

	@Override
	<S extends T> List<S> findAll(Example<S> example);// 查询与指定Example匹配的所有实体

	@Override
	<S extends T> List<S> findAll(Example<S> example, Sort sort);// 查询与指定Example匹配的所有实体并排序
}

4、service层

service:

package com.shy.service;

import com.shy.entity.Shop;
import com.shy.vo.ShopAndShopClassVo;

import java.util.List;

public interface ShopService {
    //查询所有商品
    List<Shop> findAll();

    //增加商品
    Shop addShop(Shop shop);

    //通过商品id修改商品名
    Shop updateShop();

    //通过商品id删除商品
    void delShop(Integer id);
}

Impl:

package com.shy.service;

import com.shy.dao.ShopRepository;
import com.shy.entity.Shop;
import com.shy.vo.ShopAndShopClassVo;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ShopServiceImpl implements ShopService{
    @Autowired
    private ShopRepository shopRepository;

    @Override
    public List<Shop> findAll() {
        return shopRepository.findAll();
    }

    @Override
    public Shop addShop(Shop shop) {
        shop.setPrice(333);
        shop.setShopClassId(3);
        shop.setNum(30);
        shop.setShopName("耳机");
        return shopRepository.save(shop);
    }

    @Override
    public Shop updateShop() {
        Shop shop = new Shop();
        shop.setShopId(11);
        shop.setShopName("平板");
        shop.setShopClassId(3);
        shop.setNum(40);
        return shopRepository.save(shop);
    }

    @Override
    public void delShop(Integer id) {
        shopRepository.deleteById(id);
        System.out.println("删除成功");
    }
}

5、controller

package com.shy.controller;

import com.alibaba.fastjson.JSON;
import com.shy.entity.Shop;
import com.shy.service.ShopService;
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.RestController;
@RestController
public class ShopController {
    @Autowired
    private ShopService shopService;

    @GetMapping("/list")
    public String findAll(){
        return JSON.toJSONString(shopService.findAll());
    }

    @GetMapping("/save")
    public String save(Shop shop){
        return JSON.toJSONString(shopService.addShop(shop));
    }

    @GetMapping("/saveAndFlush")
    public String saveAndFlush(){
        return JSON.toJSONString(shopService.updateShop());
    }

    @GetMapping("/delShop/{id}")
    public void delShop(@PathVariable Integer id){
        shopService.delShop(id);
    }

}

全程用postman测试

三、自定义SQL

在ShopRepository中添加

//使用原生sql需要加上,nativeQuery = true
 	//?1代表第一个参数
    @Query(value="select * from shop where shop.price = ?1",nativeQuery = true)
    Shop findByPrice(Double price);

    //修改商品,@Modifying+@Query执行更新操作,serviceImpl不要忘记加上,要使用hql的话,需要把entity别名删掉
    @Transactional//设计修改表的操作需要开启事务支持
    @Modifying//这个注解只支持返回值为int/Integer
    @Query("update Shop s set s.shopName = ?1 where s.shopId = ?2")
    int updateshop2(String name,Integer shopId);

service:

//通过价格查询商品
    Shop findByPrice(Double price);

	//修改商品名原生sql方法
    int updateshop2(String name,Integer shopId);

Impl:

@Override
    public Shop findByPrice(Double price) {
        return shopRepository.findByPrice(price);
    }

	@Override
    public int updateshop2(String name, Integer shopId) {
        return shopRepository.updateshop2(name, shopId);
    }

controller:

@GetMapping("/listPrice/{price}")
    public String findByPrice(@PathVariable Double price){
        return JSON.toJSONString(shopService.findByPrice(price));
    }

	@GetMapping("/saveAndFlush2/{id}/{name}")
    public String saveAndFlush2(@PathVariable(value = "id") Integer shopId,
                               @PathVariable String name){
        return shopService.updateshop2(name, shopId)>0?"修改成功":"修改失败";
    }

四、分页查询

Pageable 是 Spring 封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则。

Spring Data JPA 已经帮我们内置了分页功能,在查询的方法中,需要传入参数 Pageable,当查询中有多个参数的时候 Pageable 建议作为最后一个参数传入,

Pageable使用的时候需要传入页数、每页条数和排序规则,排序规则可省略

service:

/**
     * 分页查询
     * @param pageNo 第几页
     * @param pageSize 每页有多少条数据
     * @param pageable Spring 封装的分页实现类
     * @return 数据
     */
    Page<Shop> pageShop(Integer pageNo,Integer pageSize,Pageable pageable);

Impl:

@Override
    public Page<Shop> pageShop(Integer pageNo, Integer pageSize, Pageable pageable) {
        //注意排序这找的是实体类中的字段,不是数据库里的
        //分页页码从0开始
        pageable = PageRequest.of(pageNo,pageSize, Sort.Direction.DESC, "shopId");
        return shopRepository.findAll(pageable);
    }

controller:

@GetMapping("/pageShop/{pageNo}/{pageSize}")
    public String pageShop(@PathVariable Integer pageNo,
                           @PathVariable Integer pageSize,Pageable pageable){
        return JSON.toJSONString(shopService.pageShop(pageNo, pageSize, pageable));
    }

五、连表查询

VO(value object)值对象

  • 通常用于业务层之间的数据传递,仅仅包含数据而已
  • View object:视图对象

接受页面传递来的对象,封装对象

将业务处理完成的对象,封装成页面要用的数据

创建ShopAndShopClassVo用来接收连表查询后的结果

entity,这里的有参构造必须加,要往里赋值

package com.shy.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ShopAndShopClassVo {
    private String shopName;
    private double price;
    private String shopClassName;
}

ShopRepository:

//连表查询
    @Query("select new com.shy.vo.ShopAndShopClassVo(s.shopName,s.price,sc.shopClassName) from Shop 			s,ShopClass sc " +
            "where s.shopClassId=sc.shopClassId and sc.shopClassName=?1")
    List<ShopAndShopClassVo> findShopInfo(String shopClassName);

JPQL进行查询,它的特征就是与原生SQL语句类似,完全面向对象,通过类名和属性访问,而不是表名和表属性

service:

//连表查询
    List<ShopAndShopClassVo> findShopInfo(String shopClassName);

Impl:

@Override
    public List<ShopAndShopClassVo> findShopInfo(String shopClassName) {
        return shopRepository.findShopInfo(shopClassName);
    }

controller:

@GetMapping("/andFind/{name}")
    public String findShopInfo(@PathVariable("name") String shopClassName){
        return JSON.toJSONString(shopService.findShopInfo(shopClassName));
    }

六、分组查询

接收数据的另一种写法,创建一个结果集的接口来接收连表查询后的结果

定义一个结果集的接口类,接口类的内容来自于商品表和商品类别表。

entity:

package com.shy.entity;

public interface GroupShop {
    String getNum();
    String getShopClassName();
}

在运行中 Spring 会给接口(GroupShop)自动生产一个代理类来接收返回的结果,代码中使用 getXX 的形式来获取。

ShopRepository:

//分组查询
    @Query("select count(s.shopName) as 商品数量,sc.shopClassName as 类别名称 from Shop s,ShopClass sc where s.shopClassId=sc.shopClassId group by s.shopClassId")
    List<GroupShop> groupShop();

service:

//分组查询
    List<GroupShop> groupShop();

Impl:

@Override
    public List<GroupShop> groupShop() {
        return shopRepository.groupShop();
    }

controller:

@GetMapping("/groupShop")
    public String groupShop(){
        return JSON.toJSONString(shopService.groupShop());
    }

七、与mybatis对比

  • jpa是对象与对象之间的映射,而mybatis是对象和结果集的映射
  • jpa移植性比较好,不用关心用什么数据库,因为mybatis自由写sql语句,所以当项目移植的时候还需要改sql。
  • 修改字段时JPA更简单,mybatis需要修改一堆的xml,mapper等文件很麻烦。
  • mybatis自定义sql,比较灵活,也可以写复杂的sql,JPA只适合简单的单表sql
  • 总结:mybatis和JPA各有优势,如果sql简单,则jpa使用效率更高,如果sql较复杂,需要自定义,则使用mybatis更加顺手。

到此这篇关于SpringBoot整合JPA的全过程的文章就介绍到这了,更多相关SpringBoot整合JPA内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
手把手教你用SpringBoot将文件打包成zip存放或导出
Jun 11 Java/Android
详解JAVA中的OPTIONAL
Jun 14 Java/Android
Spring Boot 启动、停止、重启、状态脚本
Jun 26 Java/Android
分析Java中Map的遍历性能问题
Jun 26 Java/Android
JUnit5常用注解的使用
Jul 02 Java/Android
Java Socket实现多人聊天系统
Jul 15 Java/Android
SpringDataJPA实体类关系映射配置方式
Dec 06 Java/Android
java协程框架quasar和kotlin中的协程对比分析
Feb 24 Java/Android
Android在Sqlite3中的应用及多线程使用数据库的建议
Apr 24 Java/Android
Spring IOC容器Bean的作用域及生命周期实例
May 30 Java/Android
Java实现HTML转为Word的示例代码
Jun 28 Java/Android
Android移动应用开发指南之六种布局详解
Sep 23 Java/Android
如何给HttpServletRequest增加消息头
解决ObjectMapper.convertValue() 遇到的一些问题
Jun 30 #Java/Android
Java基础之详解HashSet的使用方法
Java实现多文件上传功能
Jun 30 #Java/Android
Java基础之线程锁相关知识总结
Jun 30 #Java/Android
详解Spring事件发布与监听机制
浅谈自定义校验注解ConstraintValidator
You might like
php 下载保存文件保存到本地的两种实现方法
2013/08/12 PHP
PHP实现的简单缓存类
2015/07/29 PHP
PHP通过CURL实现定时任务的图片抓取功能示例
2016/10/03 PHP
PHP通过引用传递参数用法分析
2016/12/01 PHP
PHP实现微信支付(jsapi支付)流程步骤详解
2018/03/15 PHP
ASP中用Join和Array,可以加快字符连接速度的代码
2007/08/22 Javascript
推荐一些非常不错的javascript学习资源站点
2007/08/29 Javascript
JQery jstree 大数据量问题解决方法
2010/03/09 Javascript
你必须知道的Javascript知识点之&quot;this指针&quot;的应用
2013/04/23 Javascript
javascript高级编程之函数表达式 递归和闭包函数
2015/11/29 Javascript
jQuery实现的左右移动焦点图效果
2016/01/14 Javascript
Base64(二进制)图片编码解析及在各种浏览器的兼容性处理
2017/02/09 Javascript
jquery.uploadifive插件怎么解决上传限制图片或文件大小问题
2017/05/08 jQuery
js canvas实现放大镜查看图片功能
2017/06/08 Javascript
JS实现弹出下载对话框及常见文件类型的下载
2017/07/13 Javascript
js+canvas实现纸牌游戏
2020/03/16 Javascript
js cavans实现静态滚动弹幕
2020/05/21 Javascript
python下MySQLdb用法实例分析
2015/06/08 Python
python daemon守护进程实现
2016/08/27 Python
Python实现多线程的两种方式分析
2018/08/29 Python
python 实现提取某个索引中某个时间段的数据方法
2019/02/01 Python
python抓取搜狗微信公众号文章
2019/04/01 Python
django基础学习之send_mail功能
2019/08/07 Python
np.newaxis 实现为 numpy.ndarray(多维数组)增加一个轴
2019/11/30 Python
pytorch Dataset,DataLoader产生自定义的训练数据案例
2021/03/03 Python
CSS3 函数技巧 用css 实现js实现的事情(clac Counters Tooltip)
2017/08/15 HTML / CSS
HTML5通过navigator.mediaDevices.getUserMedia调用手机摄像头问题
2020/04/27 HTML / CSS
捷克厨房用品购物网站:Tescoma
2018/07/13 全球购物
Allen Edmonds官方网站:一家美国优质男士鞋类及配饰制造商
2019/03/12 全球购物
小学教师评语大全
2014/04/23 职场文书
医疗器械售后服务承诺书
2014/05/21 职场文书
社区科普工作方案
2014/06/03 职场文书
2015年父亲节活动总结
2015/02/12 职场文书
公司人力资源管理制度
2015/08/05 职场文书
2019新员工试用期转正申请书3篇
2019/08/13 职场文书
Python实现聚类K-means算法详解
2022/07/15 Python