问题描述

数据导入,因为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;
}

不小心中奖了,codekeyvalue这三个都是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

学生有三个属性,idnamecode

@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存储失败,未反映到数据表。

总结

  1. 可以通过监听器在实体的各个状态执行相关回调方法。
  2. @PostPersist的回调方法中如果修改了实体属性,如果主键有值生成策略,会自动调用一次update方法,将数据反映到数据表。
  3. 如果主键不添加策略,不会反映到数据表。
  4. @PostUpdate的回调方法中如果修改了实体属性,不会反映到数据表。

Entity 监听器相关推荐

  1. Android 百度鹰眼轨迹SDK(v2.1.6)

    闲聊 看过<鹰眼追击>这部电影的读者一定对"鹰眼"这台巨无霸计算机印象深刻,如今我们能够实现自己的鹰眼. 效果图 本篇为百度地图SDK第三篇博文 第一篇实现:Andro ...

  2. java基础--名词解释汇总

    "专业术语",程序员在对JVM 做任何的性能和垃圾回收调整之前理解和记住这些"专业术语"是非常重要的.那么学习java有哪些专业名词是程序员必须记的呢?下面为大 ...

  3. 基于android端计步器软件的尝试

    这学期选了一门java课,然而课已经上完了还是对java一知半解,只能通过大作业来实践一下了.这次要做的是一个计步器软件,最初的目标是想实现记录步数并且显示走过路程,并能与朋友圈好友比较走过步数的功能 ...

  4. Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰眼

    上一篇文章介绍了地图画轨迹的基本原理和实现.不难发现,当位置处于建筑物密集区.桥梁.高架桥下,gps信号较差时,画出来的轨迹效果会比较差.即使是在空旷地带,也难免会出现gps漂移的情况而造成轨迹的偏差 ...

  5. Android 百度鹰眼 SDK

    1.创建鹰眼服务 进入鹰眼轨迹管理台 http://lbsyun.baidu.com/trace/admin/service 创建服务 获取到服务ID158542 2.下载demo http://lb ...

  6. Android百度鹰眼轨迹

    作者:短工邦技术部 - 陈文超 百度地图之百度鹰眼轨迹使用 拿外卖配送为例,配送员从接单开始上传行驶轨迹,用户端可以实时查看配送员的行驶轨迹,对于点外卖的用户来说可以更直接地观察到自己的订单是否在配送 ...

  7. 地图轨迹跟踪系统设计与实现(Android+Eclipse+APP)

    目 录 1 在线地图轨迹APP概述 1 1.1 本论文的背景及意义 1 1.2 本论文的主要方法和研究进展 1 1.3 本论文的主要内容 1 1.4 本论文的结构安排 1 2 系统分析 3 2.1 研 ...

  8. 百度地图轨迹(Andriod SDK)

    项目结构 BaseActivity.java package siso.track.activity;import android.app.Activity; import android.os.Bu ...

  9. Hibernate的拦截器和监听器 .

    http://blog.csdn.net/shizhan1881/article/details/8478923 最近项目需要,用到了Hibernate的拦截器和监听器,有些小小心得,和大家分享下. ...

最新文章

  1. biztalk中的发送端口产生异常及处理(下)
  2. poj 3680 Intervals(离散化+费用流)
  3. 组合模式(Composition)
  4. 写linux程序测试吞吐量,Linux下测试磁盘性能(IO、吞吐量)
  5. 立足共赢 | 开宸引领绿色会展经济新形式
  6. 如何在没有导入excel的情况下获取excel中的测试数据
  7. 有关Kill Session问题的讨论(旧文初发)
  8. Excel函数实战技巧精粹(二)常用函数之VLOOKUP全解
  9. FireMonkey 界面的玩法
  10. 如何解决网站可能存在webshell网页木马,阿里云网站木马后门文件提醒
  11. 阿里云商标智能注册申请图文教程(亲踩坑)
  12. linux如何将百分比转换为数字,Linux_sql 自定义百分比转换小数函数代码,复制代码 代码如下: --CAST 和 CO - phpStudy...
  13. 神秘电报密码——哈夫曼编码
  14. 【依葫芦画瓢】SSM-CRUD --- 2
  15. 机器学习(周志华)学习笔记(一)
  16. 【转载】音频基础知识
  17. 学生成绩等级用c语言,C语言实现学生成绩等级划分的方法实例
  18. CEC循环生态社区周而复始生生不息推进XAG令牌市场
  19. git如何删除github上的文件,亲测有效
  20. Python遍历多个列表:ValueError: too many values to unpack (expected 2)

热门文章

  1. [导入]解决“Internet Explorer 无法打开 Internet站点已终止操作”问题
  2. ubuntu vscode_如何在Ubuntu-18.04下用VSCode编译LibTorch
  3. 计算机网络原理 大型实验,计算机网络原理实验 实验一
  4. gtk linux 升级_需要在Ubuntu上更新GTK(10.04)
  5. 双目标帕累托优化_结构力学中的优化分析(3) —— 结构优化分析
  6. wordpress 内网安装插件_Wordpress安装后必做的优化操作
  7. android通知栏打开actvity,Android实现点击通知栏后,先启动应用再打开目标Activity...
  8. linux意外重启分析,Linux关机重启流程分析
  9. php ecos,php
  10. oracle的shell命令,Shell实现的Oracle启动脚本分享