常见db中的四个操作curd,前面的几篇博文分别介绍了insert,update,接下来我们看下delete的使用姿势,通过JPA可以怎样删除数据
一般来讲是不建议物理删除(直接从表中删除记录)数据的,在如今数据就是钱的时代,更常见的做法是在表中添加一个表示状态的字段,然后通过修改这个字段来表示记录是否有效,从而实现逻辑删除;这么做的原因如下
物理删除,如果出问题恢复比较麻烦
无法保证代码一定准确,在出问题的时候,删错了数据,那就gg了
删除数据,会导致重建索引
Innodb数据库对于已经删除的数据只是标记为删除,并不真正释放所占用的磁盘空间,这就导致InnoDB数据库文件不断增长,也会导致表碎片
逻辑删除,保留数据,方便后续针对数据的挖掘或者分析
在开始之前,当然得先准备好基础环境,如安装测试使用mysql,创建SpringBoot项目工程,设置好配置信息等,关于搭建项目的详情可以参考前一篇文章
190612-SpringBoot系列教程JPA之基础环境搭建
下面简单的看一下演示添加记录的过程中,需要的配置
沿用前一篇的表,结构如下
配置信息,与之前有一点点区别,我们新增了更详细的日志打印;本篇主要目标集中在添加记录的使用姿势,对于配置说明,后面单独进行说明
数据修改嘛,所以我们先向表里面插入两条数据,用于后面的操作
下面谈及到的删除,都是物理删除,可以理解为直接将某些记录从表中抹除掉(并不是说删了就完全没有办法恢复)针对CURD四种操作而言,除了read之外,另外三个insert,update,delete都会加写锁(一般来将会涉及到行锁和gap锁,从后面也会看到,这三个操作要求显示声明事物)
前面插入篇已经介绍了POJO的逐步创建过程,已经对应的注解含义,下面直接贴出成果
上面类中的几个注解,说明如下
@Data
属于lombok注解,与jpa无关,自动生成 getter/setter/equals/hashcode/tostring
等方法
@Entity
, @Table
jpa注解,表示这个类与db的表关联,具体匹配的是表 money
@Id
@GeneratedValue
作用与自增主键
@Column
表明这个属性与表中的某列对应
@CreateDate
根据当前时间来生成默认的时间戳
接下来我们新建一个api继承自 CurdRepository
,然后通过这个api来与数据库打交道
先写一个用于查询数据的方法,用于校验我们执行删除之后,是否确实被删除了
在执行下面操作之前,先调用上面的,输出结果如
这种应该属于最常见的删除方式了,为了避免误删,通过精确的主键id来删除记录,是一个非常好的使用姿势, CrudRepository
这个接口已经提供了对应的方法,所以我们可以直接使用
执行完毕之后,输出结果如下,对比前面的输出可以知道 id=21
的记录被删除了
把上面代码再执行一次,发现抛了异常
为什么会这样呢?我们debug进去,调用的实现是默认的 SimpleJpaRepository
,其源码如
从源码可以看出,这个是先通过id进行查询,如果对应的记录不存在时,直接抛异常;当存在时,走remove逻辑;
如果我们希望删除一个不存在的数据时,不要报错,可以怎么办?
自定义实现一个继承 SimpleJpaRepository
的类,覆盖删除方法
然后再调用上面的方法就可以了,不演示具体的测试case了,源码可以到项目工程中查看 :point_right: 源码(https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/102-jpa)
虽然根据id进行删除比较稳妥,但也无法避免某些情况下需要根据其他的字段来删除,比如我们希望删除名为 jpa一灰灰7
的数据,这时则需要我们在 MoneyDeleteRepository
新增一个方法
这里比较简单的提一下这个方法的命名规则,后面在查询这一篇会更加详细的说明;
delete
表示执行的是删除操作
By
表示根据某个字段来进行条件限定
Name
这个有POJO中的属性匹配
上面这个方法,如果翻译成sql,相当于 deletefrommoneywherename=xx
调用方式和前面一样,如下
然后我们执行上面的测试,发现并不能成功,报错了
通过前面update的学习,知道需要显示加一个事物的注解,我们这里直接加在 Repository
中
然后再次执行输出如下,这里我们把sql的日志也打印了
从最终剩余的记录来看,name为 jpa一灰灰7
的被删除了,再看一下前面删除的sql,会发现一个有意思的地方, deleteByName
这个方法,翻译成sql变成了两条
select*frommoneywherename=xxx
先根据name查询记录
deletefrommoneywhereid=xxx
根据前面查询记录的id,删除记录
接下来演示一个删除money在 [2000,3000]
区间的记录,这时我们新增的放入可以是
通过方法命名也可以简单知道上面这个等同于sql deletefrommoneywheremoney between xxxandxxx
测试代码为
输出日志
从拼接的sql可以看出,上面的逻辑等同于,先执行了查询,然后根据id一个一个进行删除....
我们通过声明方法的方式来实现条件删除;需要注意
删除需要显示声明事物 @Transactional
删除一个不存在的记录,会抛异常
声明删除方法时,实际等同于先查询记录,然后根据记录的id进行精准删除
工程:https://github.com/liuyueyi/spring-boot-demo
module: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/102-jpa
Mysql之锁与事务知识要点小结
Spring学习之事务的使用姿势
Spring学习之事务管理与传播属性
190612-SpringBoot系列教程JPA之基础环境搭建
190614-SpringBoot系列教程JPA之新增记录使用姿势
190623-SpringBoot系列教程JPA之update使用姿势
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
一灰灰Blog个人博客 https://blog.hhui.top
一灰灰Blog-Spring专题博客 http://spring.hhui.top