Entity 监听器
问题描述
数据导入,因为ID
业务无关性,在多系统中,需要添加code
进行对象唯一性标识。
某些实体,其code
为国家规定,需要用户输入,某些国家未规定代码的实体,我们需要为其设置一个不重复的代码作为标识。
最初
为了保证每次运行系统,该代码不重复,所以新建一张code
表用于存储不同的实体的code
编号到多少了,以保证不重复。
为了让每个人都能看懂,用了Code
作为实体名,key
作为相应的实体名(建了一个枚举,防止打错),value
作为已经编码到的号码。
实体省略getter、setter方法。
@ApiModel("代码实体")
@Entity
@Table(name = "resource_code")
public class Code {@Id@GeneratedValueprivate Long id;@ApiModelProperty("键")@Column(name = "code_key", unique = true)private String key;@ApiModelProperty("值")@Column(name = "code_value")private Integer value = 0;
}
不小心中奖了,code
、key
、value
这三个都是mysql
里的关键字或保留字。
解决过程中也算总结出了一点经验。机器人会报如下的错:
Unsuccessful: create table resource_code
You have an error in your SQL syntax;
建表失败,你的SQL
有语法错误,因为ORM
映射是Hibernate
为我们实现的,经过了全世界开发者的测试,肯定不会错,那为什么语法错误呢?极有可能使用了数据库中的关键字或保留字。
更好的方案
潘老师又提出了更好的方案:
id
由数据库唯一分配,可以在当前实体有id
之后,将id
再存储一份给code
。
@PostPersist // 实体新建以后执行
public void postPersist() {if (this.code == null || this.code.equals("")) {this.code = this.id.toString();}
}
需要在持久化之后执行,我们就需要学习一下Entity
监听器。
监听器
实体监听器不需要实现任何特定的接口。可以将回调注解应用到特定事件中需要被通知的任何方法。
可以在单个方法中合并几个回调,但不允许在几个方法中重复相同的回调。——《
Hibernate
实战 第12章 12.3.4 实体监听器与回调》
回调
可以在单个方法中合并几个回调
@PrePersist
@PostPersist
public void callback() {System.out.println("running ...");
}
但不允许在几个方法中重复相同的回调
@PrePersist
public void callback() {System.out.println("running ...");
}@PrePersist
public void callback2() {System.out.println("running ...");
}
You can only annotate one callback method with javax.persistence.PrePersist in bean class
控制台会报错:在bean
里,你只能使用PrePersist
注解一个回调方法。
回调注解
回调注解 | 描述 |
---|---|
@PostLoad | Executed after an entity has been loaded into the current persistence context or an entity has been refreshed. |
@PrePersist | Executed before the entity manager persist operation is actually executed or cascaded. This call is synchronous with the persist operation. |
@PostPersist | Executed after the entity manager persist operation is actually executed or cascaded. This call is invoked after the database INSERT is executed. |
@PreUpdate | Executed before the database UPDATE operation. |
@PostUpdate | Executed after the database UPDATE operation. |
@PreRemove | Executed before the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation. |
@PostRemove | Executed after the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation. |
测试
@Test
public void saveTest() {Student student = new Student();student.setName("zhangsan");studentRepository.save(student);Student newStudent = studentRepository.findOne(student.getId());newStudent.setName("newZhangsan");studentRepository.save(newStudent);studentRepository.delete(student.getId());
}
this is prePersist
this is postPersist
this is postLoad
this is postLoad
this is preUpdate
this is postUpdate
this is postLoad
this is preRemove
this is postRemove
执行过程应该与各位预期一致。
@PostPersist
学生有三个属性,id
、name
、code
。
@Test
public void saveTest() {Student student = new Student();student.setName("zhangsan");studentRepository.save(student);
}
直接运行。
this is prePersist
this is postPersist
PostPersist回调业务逻辑
@PostPersist
public void postPersist() {System.out.println("this is postPersist");this.code = String.valueOf(this.id);
}
再运行:
this is prePersist
this is postPersist
this is preUpdate
this is postUpdate
与上次相比,多了两次update
的执行。
所以,我们总结出,@PostPersist
在数据库语句插入之后执行,如果我们在@PostPersist
的回调方法中修改了对象的状态,自动地调用一次更新方法,将修改后的状态持久化。
@PostUpdate
既然@PostPersist
都能自动将数据持久化,我们再来试试@PostUpdate
。
@PostPersist
public void postPersist() {System.out.println("this is postPersist");
}
@PostUpdate
public void postUpdate() {System.out.println("this is postUpdate");this.code = String.valueOf(this.id + 1);
}
@Test
public void saveTest() {Student student = new Student();student.setName("zhangsan");studentRepository.save(student);Student newStudent = studentRepository.findOne(student.getId());newStudent.setName("newZhangsan");studentRepository.save(newStudent);
}
- 如果
code
的值为id + 1
的话,说明自动将@PostUpdate
的数据改动也持久化。 - 如果为
null
,说明没有自动持久化,@PostUpdate
中修改的实体属性不会反映到数据表。
this is prePersist
this is postPersist
this is postLoad
this is postLoad
this is preUpdate
this is postUpdate
结果为null
。很遗憾,@PostUpdate
中修改的实体属性不会反映到数据表。
新发现的问题
最开始以为都好使,然后在项目中应用,但遇到了问题。
初始化时,精确度类别的code
存上了,但是用途的code
没存上。
后来发现用途实体主键不是自增的。
@Entity
public class Student {@Idprivate Long id;@PostPersistpublic void postPersist() {System.out.println("this is postPersist");this.code = "123";}
}
去掉主键值生成策略,进行测试。
@Test
public void saveTest() {Student student = new Student();student.setId(1L);student.setName("zhangsan");studentRepository.save(student);
}
code
存储失败,未反映到数据表。
总结
- 可以通过监听器在实体的各个状态执行相关回调方法。
@PostPersist
的回调方法中如果修改了实体属性,如果主键有值生成策略,会自动调用一次update
方法,将数据反映到数据表。- 如果主键不添加策略,不会反映到数据表。
@PostUpdate
的回调方法中如果修改了实体属性,不会反映到数据表。
Entity 监听器相关推荐
- Android 百度鹰眼轨迹SDK(v2.1.6)
闲聊 看过<鹰眼追击>这部电影的读者一定对"鹰眼"这台巨无霸计算机印象深刻,如今我们能够实现自己的鹰眼. 效果图 本篇为百度地图SDK第三篇博文 第一篇实现:Andro ...
- java基础--名词解释汇总
"专业术语",程序员在对JVM 做任何的性能和垃圾回收调整之前理解和记住这些"专业术语"是非常重要的.那么学习java有哪些专业名词是程序员必须记的呢?下面为大 ...
- 基于android端计步器软件的尝试
这学期选了一门java课,然而课已经上完了还是对java一知半解,只能通过大作业来实践一下了.这次要做的是一个计步器软件,最初的目标是想实现记录步数并且显示走过路程,并能与朋友圈好友比较走过步数的功能 ...
- Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰眼
上一篇文章介绍了地图画轨迹的基本原理和实现.不难发现,当位置处于建筑物密集区.桥梁.高架桥下,gps信号较差时,画出来的轨迹效果会比较差.即使是在空旷地带,也难免会出现gps漂移的情况而造成轨迹的偏差 ...
- Android 百度鹰眼 SDK
1.创建鹰眼服务 进入鹰眼轨迹管理台 http://lbsyun.baidu.com/trace/admin/service 创建服务 获取到服务ID158542 2.下载demo http://lb ...
- Android百度鹰眼轨迹
作者:短工邦技术部 - 陈文超 百度地图之百度鹰眼轨迹使用 拿外卖配送为例,配送员从接单开始上传行驶轨迹,用户端可以实时查看配送员的行驶轨迹,对于点外卖的用户来说可以更直接地观察到自己的订单是否在配送 ...
- 地图轨迹跟踪系统设计与实现(Android+Eclipse+APP)
目 录 1 在线地图轨迹APP概述 1 1.1 本论文的背景及意义 1 1.2 本论文的主要方法和研究进展 1 1.3 本论文的主要内容 1 1.4 本论文的结构安排 1 2 系统分析 3 2.1 研 ...
- 百度地图轨迹(Andriod SDK)
项目结构 BaseActivity.java package siso.track.activity;import android.app.Activity; import android.os.Bu ...
- Hibernate的拦截器和监听器 .
http://blog.csdn.net/shizhan1881/article/details/8478923 最近项目需要,用到了Hibernate的拦截器和监听器,有些小小心得,和大家分享下. ...
最新文章
- biztalk中的发送端口产生异常及处理(下)
- poj 3680 Intervals(离散化+费用流)
- 组合模式(Composition)
- 写linux程序测试吞吐量,Linux下测试磁盘性能(IO、吞吐量)
- 立足共赢 | 开宸引领绿色会展经济新形式
- 如何在没有导入excel的情况下获取excel中的测试数据
- 有关Kill Session问题的讨论(旧文初发)
- Excel函数实战技巧精粹(二)常用函数之VLOOKUP全解
- FireMonkey 界面的玩法
- 如何解决网站可能存在webshell网页木马,阿里云网站木马后门文件提醒
- 阿里云商标智能注册申请图文教程(亲踩坑)
- linux如何将百分比转换为数字,Linux_sql 自定义百分比转换小数函数代码,复制代码 代码如下: --CAST 和 CO - phpStudy...
- 神秘电报密码——哈夫曼编码
- 【依葫芦画瓢】SSM-CRUD --- 2
- 机器学习(周志华)学习笔记(一)
- 【转载】音频基础知识
- 学生成绩等级用c语言,C语言实现学生成绩等级划分的方法实例
- CEC循环生态社区周而复始生生不息推进XAG令牌市场
- git如何删除github上的文件,亲测有效
- Python遍历多个列表:ValueError: too many values to unpack (expected 2)
热门文章
- [导入]解决“Internet Explorer 无法打开 Internet站点已终止操作”问题
- ubuntu vscode_如何在Ubuntu-18.04下用VSCode编译LibTorch
- 计算机网络原理 大型实验,计算机网络原理实验 实验一
- gtk linux 升级_需要在Ubuntu上更新GTK(10.04)
- 双目标帕累托优化_结构力学中的优化分析(3) —— 结构优化分析
- wordpress 内网安装插件_Wordpress安装后必做的优化操作
- android通知栏打开actvity,Android实现点击通知栏后,先启动应用再打开目标Activity...
- linux意外重启分析,Linux关机重启流程分析
- php ecos,php
- oracle的shell命令,Shell实现的Oracle启动脚本分享