百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

SpringBoot专栏:整合JPA并开启声明式事务(第10讲)

liebian365 2024-10-23 13:51 20 浏览 0 评论

前言

今天给大家介绍的是操作数据库的另一个模块 JPA,即 Java 持久层的 API,极大的简化了我们操作数据库的步骤,使我们的代码具有很强的可维护性。

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

JPA 的目标之一是制定一个可以由很多供应商实现的API,并且开发人员可以编码来实现该API,而不是使用私有供应商特有的API。

JPA是需要Provider来实现其功能的,Hibernate就是JPA Provider中很强的一个,应该说无人能出其右。从功能上来说,JPA就是Hibernate功能的一个子集。

快速构建步骤

添加相关依赖

添加spring-boot-starter-jdbc依赖:

 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jpa</artifactId>
 </dependency>

添加mysql连接类和连接池类:

 <dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <scope>runtime</scope>
 </dependency> 

配置数据源,在application.properties文件配置:

spring:
 datasource:
 driver-class-name: com.mysql.jdbc.Driver
 url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
 username: root
 password: 123456
 jpa:
 hibernate:
 ddl-auto: update # 第一次简表create 后面用update
 show-sql: true

特别注意,如果通过jpa在数据库中建表,将jpa.hibernate,ddl-auto改为create,建完表之后,要改为update,要不然每次重启工程会删除表并新建。

创建实体类

通过@Entity 表明是一个映射的实体类, @Id表明id, @GeneratedValue 字段自动生成

@Entity//告诉JPA这是一个实体类(和数据表映射的类)
@Table(name = "lp_users") //@Table来指定和哪个数据表对应;如果省略默认表名就是user;
public class UserInfo {
 @Id// @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
 @Column(name = "ID")
 private String id;
 @Column(name = "ACCOUNT",length = 60) //这是和数据表对应的一个列
 private String account;
 @Column(name = "NAME")//省略默认列名就是属性名
 private String name;
 @Column(name = "REMARKS")
 private String remarks;
 @Column(name = "PASSWORD")
 private String password;
 @Column(name = "IP")
 private String ip;
 @Column(name = "MAC")
 private String mac;
 private Short isautoexpire;
 @Column(name = "ISBINDIP")
 private Short isbindip;
 @Column(name = "ISBINDMAC")
 private Short isbindmac;
*****
}

Dao层

数据访问层,通过编写一个继承自 JpaRepository 的接口就能完成数据访问,其中包含了几本的单表查询的方法,非常的方便。值得注意的是,这个Account 对象名,而不是具体的表名,另外Interger是主键的类型,一般为Integer或者Long

@Transactional//执行修改方法时一定要添加这个注解和@Modifying注解
public interface UserInfoRepository extends JpaRepository<UserInfo,String> {
 @Modifying
 @Query(value = "update lp_users set password = :password where id = :id",nativeQuery = true)
 void resetPasswordById(@Param("id") String id, @Param("password") String password);
 /**报错:
 * java.sql.SQLException: Can not issue data manipulation statements with executeQuery().
 * 解决方式:
 * 在修改方法上面添加@Modifying 注解
 * 报错:
 * javax.persistence.TransactionRequiredException: Executing an update/delete query
 * 解决方式:
 * 在UserRepository.java类上添加@Transactional注解
 */
}

Web层(包含增删改查以及自定义sql等基础方法)

controller层,为了简化测试流程,暂时定义为get方法请求,实际开发中,一定严格规范请求类型已经restful风格

@RestController
@Transactional
public class UserController {
 @Autowired
 UserInfoRepository userInfoRepository;
 /**
 * 新增用户信息
 * IP:端口/user?id=201&account=201&isbindip=1&isbindmac=1
 * @param user
 * @return
 * 注:线上环境应该为post提交
 */
 @GetMapping("/user")
 public UserInfo insertUser(UserInfo user){
 UserInfo save = userInfoRepository.save(user);
 Integer.parseInt("error");
 return save;
 }
 /**
 * 删除用户
 * @param id
 * @return
 */
 @GetMapping("/userdel/{id}")
 public String delUser(@PathVariable("id") String id){
 userInfoRepository.deleteById(id);
 return "success";
 }
 /**
 * 修改密码
 * @param id
 * @return
 */
 @GetMapping("/userupdate/{id}")
 public String updateUser(@PathVariable("id") String id){
 userInfoRepository.resetPasswordById(id,"123456");
 //saveAndFlush
 return "success";
 }
 @GetMapping("/user/{id}")
 public UserInfo getUser(@PathVariable("id") String id){
 //在测试方法上加入@Transactional注解可以解决报错的问题
// UserInfo userList1 = userInfoRepository.getOne(id); //使用getOne()返回的是代理对象,无法直接操作,会出现hibernate lazyxxx no session 的错误
 Optional<UserInfo> userList = userInfoRepository.findById(id);
 //需要结果过做判断,查询结果为null时会报NoSuchElementException
 if(userList.isPresent()){
 return userList.get();
 }
 return null;
 }
 /**
 * 多条件查询用户
 * http://localhost:8080/users?password=fcfc92fc7492b5fc7b74cf92b8b537fc
 * @param userInfo
 * @return
 */
 @GetMapping("/users")
 public List<UserInfo> getUsers(UserInfo userInfo){
 Example<UserInfo> example=Example.of(userInfo);
 List<UserInfo> exampleResult = userInfoRepository.findAll(example);
 return exampleResult;
 }
}

测试添加方法:

IP:端口/user?id=201&account=201&isbindip=1&isbindmac=1

?数据库存在

?其他测试结果..

可以直接下载源码参考:

https://github.com/shinians/springboot-demos

End:

本章内容主要了解基本的增删改查,至于复杂的更加深入的技能点,用户可根据公司需求进行更深层探索,如果本项目对您有帮助也希望您有好的文章、好的心得也及时@我 ,谢谢。

更多问题可以关注@架构师速成记

JPA 概述

1. Java Persistence API(Java 持久层 API):用于对象持久化的 API

2. 作用:使得应用程序以统一的方式访问持久层

3. 前言中提到了 Hibernate,那么JPA 与 Hibernate究竟是什么关系呢:

1)JPA 是 Hibernate 的一个抽象,就像 JDBC 和 JDBC 驱动的关系

2)JPA 是一种 ORM 规范,是 Hibernate 功能的一个子集 (既然 JPA 是规范,Hibernate 对 JPA 进行了扩展,那么说 JPA 是 Hibernate 的一个子集不为过)

3)Hibernate 是 JPA 的一个实现

4. JPA 包括三个方面的技术:

1)ORM 映射元数据,支持 XML 和 JDK 注解两种元数据的形式

2)JPA 的 API

3)查询语言:JPQL

JPA 的基本注解

1. @Entity :修饰实体类,指明该类将映射到指定的数据表

2. @Table :当实体类与映射的数据库表名不同名时需要使用 @Table 注解,该注解与 @Entity 注解并列使用,使用其 name 属性指明数据库的表名

3. @Id :标识该属性为主键一般标注在该属性的 getter 方法上

4. @GeneratedValue :标注主键的生成策略,通过其 strategy 属性。通常与 @Id 注解一起使用。默认情况下 JPA 会自动选择一个最适合底层数据库的主键生成策略,MySQL 默认为 AUTO,常用策略有:

–IDENTITY:采用数据库 ID自增长的方式来自增主键字段,Oracle 不支持这种方式;

AUTOJPA自动选择合适的策略,是默认选项;

–SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式

–TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植

5. @Basic :用于没有任何标注的 getXxx() 方法,默认即为 @Basic,所以若一个 getter 方法无任何注解,可以使用 @Basic 注解,也可以不使用

6. @Column :当实体的属性与其映射的数据表的列不同名时使用,一般用于 getter 方法上。其 name 属性用来指明此属性在数据表中对应的列名unique 属性指明是否为唯一约束nullable 属性用来指明是否可以为空,false 为不能为空length 属性指明此列的长度

7. @Transient标注此注解后在创建数据表的时候将会忽略该属性 Customer 类并没有 info 这个属性,所以数据库中也不应该有 info 这个字段

8. @Temporal :向数据库映射日期(Date)属性时用来调整映射的精度。Date 类型的数据有 DATE, TIME, 和 TIMESTAMP 三种精度(即单纯的日期,时间,或者两者兼备).Birth 属性应该使用 DATE 类型(生日只具体到日即可,如:2015-10-22),而 CreateTime 应该使用 TIMESTAMP 类型(创建时间应该具体到秒,如:2017-10-11 22:39:13)

 问题探索:

1.什么是 JPQL?

2.如何开启JPA的二级缓存?

3.如何配置多对一、多对多的关系?

相关推荐

go语言也可以做gui,go-fltk让你做出c++级别的桌面应用

大家都知道go语言生态并没有什么好的gui开发框架,“能用”的一个手就能数的清,好用的就更是少之又少。今天为大家推荐一个go的gui库go-fltk。它是通过cgo调用了c++的fltk库,性能非常高...

旧电脑的首选系统:TinyCore!体积小+精简+速度极快,你敢安装吗

这几天老毛桃整理了几个微型Linux发行版,准备分享给大家。要知道可供我们日常使用的Linux发行版有很多,但其中的一些发行版经常会被大家忽视。其实这些微型Linux发行版是一种非常强大的创新:在一台...

codeblocks和VS2019下的fltk使用中文

在fltk中用中文有点问题。英文是这样。中文就成这个样子了。我查了查资料,说用UTF-8编码就行了。edit->Fileencoding->UTF-8然后保存文件。看下下边的编码指示确...

FLTK(Fast Light Toolkit)一个轻量级的跨平台Python GUI库

FLTK(FastLightToolkit)是一个轻量级的跨平台GUI库,特别适用于开发需要快速、高效且简单界面的应用程序。本文将介绍Python中的FLTK库,包括其特性、应用场景以及如何通过代...

中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux

IT之家1月29日消息,去年6月份,中科院大学教授、中科院计算所研究员包云岗,发布了开源高性能RISC-V处理器核心——香山。近日,包云岗在社交平台晒出图片,香山芯片已流片,回片后...

Linux 5.13内核有望合并对苹果M1处理器支持的初步代码

预计Linux5.13将初步支持苹果SiliconM1处理器,不过完整的支持工作可能还需要几年时间才能完全完成。虽然Linux已经可以在苹果SiliconM1上运行,但这需要通过一系列的补丁才能...

Ubuntu系统下COM口测试教程(ubuntu port)

1、在待测试的板上下载minicom,下载minicom有两种方法:方法一:在Ubuntu软件中心里面搜索下载方法二:按“Ctrl+Alt+T”打开终端,打开终端后输入“sudosu”回车;在下...

湖北嵌入式软件工程师培训怎么选,让自己脱颖而出

很多年轻人毕业即失业、面试总是不如意、薪酬不满意、在家躺平。“就业难”该如何应对,参加培训是否能改变自己的职业走向,在湖北,有哪些嵌入式软件工程师培训怎么选值得推荐?粤嵌科技在嵌入式培训领域有十几年经...

新阁上位机开发---10年工程师的Modbus总结

前言我算了一下,今年是我跟Modbus相识的第10年,从最开始的简单应用到协议了解,从协议开发到协议讲解,这个陪伴了10年的协议,它一直没变,变的只是我对它的理解和认识。我一直认为Modbus协议的存...

创建你的第一个可运行的嵌入式Linux系统-5

@ZHangZMo在MicrochipBuildroot中配置QT5选择Graphic配置文件增加QT5的配置修改根文件系统支持QT5修改output/target/etc/profile配置文件...

如何在Linux下给zigbee CC2530实现上位机

0、前言网友提问如下:粉丝提问项目框架汇总下这个网友的问题,其实就是实现一个网关程序,内容分为几块:下位机,通过串口与上位机相连;下位机要能够接收上位机下发的命令,并解析这些命令;下位机能够根据这些命...

Python实现串口助手 - 03串口功能实现

 串口调试助手是最核心的当然是串口数据收发与显示的功能,pzh-py-com借助的是pySerial库实现串口收发功能,今天痞子衡为大家介绍pySerial是如何在pzh-py-com发挥功能的。一、...

为什么选择UART(串口)作为调试接口,而不是I2C、SPI等其他接口

UART(通用异步收发传输器)通常被选作调试接口有以下几个原因:简单性:协议简单:UART的协议非常简单,只需设置波特率、数据位、停止位和校验位就可以进行通信。相比之下,I2C和SPI需要处理更多的通...

同一个类,不同代码,Qt 串口类QSerialPort 与各种外设通讯处理

串口通讯在各种外设通讯中是常见接口,因为各种嵌入式CPU中串口标配,工业控制中如果不够还通过各种串口芯片进行扩展。比如spi接口的W25Q128FV.对于软件而言,因为驱动接口固定,软件也相对好写,因...

嵌入式linux为什么可以通过PC上的串口去执行命令?

1、uboot(负责初始化基本硬bai件,如串口,网卡,usb口等,然du后引导系统zhi运行)2、linux系统(真正的操作系统)3、你的应用程序(基于操作系统的软件应用)当你开发板上电时,u...

取消回复欢迎 发表评论: