一个迟来的赞,送给JPA。AbstractEntity需要准备些什么?
关系型数据库其实很讨人厌,尤其是在你使用数据库驱动的开发模式时。需要首先把表给创建好了,然后再使用代码生成器反向生成一堆几乎无法可读的代码。当字段有变更的时候,又是一番折腾。
- 作者:小姐姐养的狗02号来源:小姐姐味道|2021-02-22 21:20
本文转载自微信公众号「小姐姐味道」,作者小姐姐养的狗02号。转载本文请联系小姐姐味道公众号。
本篇属于代码解析系列文章之一,主要内容是JPA的基础父类设计。参考代码:https://github.com/xjjdog/bcMall/blob/master/bc-utils/src/main/java/cn/xjjdog/bcmall/utils/db/AbstractEntity.java
关系型数据库其实很讨人厌,尤其是在你使用数据库驱动的开发模式时。需要首先把表给创建好了,然后再使用代码生成器反向生成一堆几乎无法可读的代码。当字段有变更的时候,又是一番折腾。
这其中的典型,就是MyBatis,所以催生了更加简洁的MyBatis Plus。
了解到一些大厂(阿里、腾讯、抖音等),JPA的使用也越来越广泛了,包括我们公司,这是把合适的工具放到了合适的地方。如果想要快速开发,JPA无疑是一个比较好的选择。你无需关注数据库表的结构,使用代码驱动即可完成工作,管它后面是MySQL还是Oracle。JPA把数据库相关的知识给弱化了,让你专注于业务开发。
我个人曾是非常排斥JPA这种弱化SQL的工具的,这源于对早起Hibernate版本的错误认识。但尝试过mybatis、spring-data-jdbc、jooq后,发现这个东西是真的香!一个迟到的赞,送给JPA。
这对一些管理系统来说,非常合适。因为性能并不是这些系统主要的痛点,业务复杂性才是。
本文将介绍一个简单的实体类,需要准备哪些基本字段。这些字段,又是如何在代码中被使用的。
1. 基本字段介绍
首先看一下我们的基础定义类。
代码不多,信息却不少。
下面来一行行解析。
- @Data
Data注解是属于lombok类的,lombok是地球人都知道的代码简化工具,提供了非常多的注解。如果你不想记忆太多的注解,直接加上一个Data,是最偷懒的选择。
- @MappedSuperclass
这个注解是JPA的,用来标识父类。标注为@MappedSuperclass的类将不是一个完整的实体类,不会映射到数据库表,但是它的属性都将映射到子类的数据库字段中。放在这里再合适不过了。
- @EntityListeners(AuditingEntityListener.class)
开启自动审计功能,这个和下面的两个日期字段是相互配合的,我们稍后介绍。
- @JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler"}) //直接使用bean时,避免json序列号失败
有时候,我们想要再controller层直接使用JPA的实体。但JPA内部其实是有很多附加变量的,比如hibernateLazyInitializer。
为了让实体在json序列化的时候能够正常进行,需要忽略这两个字段。所以这个注解,是属于jackson json的。
2. 自定义ID生成器
JPA其实提供了非常多的ID生成策略。不过,在互联网应用下,应用较多的还是雪花算法,因为它有着良好的扩展性,在数据迁移的时候也不会有很多冲突。
为了指定雪花算法,我们需要下面几行代码。
- static final String ID_GEN = "cn.xjjdog.bcmall.utils.db.DistributedId";
- @Id
- @GenericGenerator(name = "IdGen", strategy = ID_GEN)
- @GeneratedValue(generator = "IdGen")
其中的一个关键,就是使用我们名称叫做IdGen的ID生成器。这里的代码,是有一点小遗憾的。由于JVM类加载的缘故,我们无法在注解中直接使用类的名称(*.class.getName()) 来获取它的包路径,只能作为字符串写死在这里。
下面我们就来看一下这个ID生成器的处理。
- public class DistributedId implements IdentifierGenerator {
- @Override
- public Serializable generate(SharedSessionContractImplementor sharedSessionContractImplementor, Object obj) throws HibernateException {
- if (obj == null) throw new HibernateException(new NullPointerException()) ;
- if ((((AbstractEntity) obj).getId()) == null) {
- return String.valueOf(Snowflake.createId());
- } else {
- return ((AbstractEntity) obj).getId();
- }
- }
- }
代码如上。在直接使用之前,我们还做了一点小处理。当我们判断实体的ID为空的时候,才使用雪花算法构造一个新的ID;否则使用实体原来设置好的ID,保持不变。
为什么这样做?因为这是有需求的。像订单这种业务,你需要先生成一个订单号,然后再更新一些数据库信息,发布一些消息等;而不是在保存动作出发的时候才生成一个。
如果你不做上面代码的处理。JPA将每次保存的时候都自动生成一个,覆盖了你原有的。我就在这里吃过亏,通过debug代码才进行的修复。
3. 自动填充字段
上面说到createdDate和lastModifiedDate两个字段,其实在使用的时候,是不需要手动去设值的。这两个值,将通过审计功能自动完成。
- @EntityListeners(AuditingEntityListener.class)
当然,我们还要用特有的注解,来标识这两个字段。
- /**
- * 创建时间
- */
- @CreatedDate
- private Date createdDate;
- /**
- * 更新时间
- */
- @LastModifiedDate
- private Date lastModifiedDate;
最后,不要忘了在全局配置中通过Config开启这个功能。
- @Configuration
- @EnableJpaAuditing
- public class JpaConfig {
- }
当然,审计是不能没有用户的。所以这个系列还有@CreatedBy注解,用来标注是谁创建的。你需要在代码中组装它们,比如下面的代码,就是从Spring Sercurity中获取用户信息。
- @Configuration
- @Slf4j
- public class UserAuditor implements AuditorAware<String> {
- @Override
- public Optional<String> getCurrentAuditor() {
- UserDetails user;
- try {
- user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
- return Optional.ofNullable(user.getUsername());
- }catch (Exception e){
- return Optional.empty();
- }
- }
- }
4. End
JPA写管理系统,真的是神器。当你不需要考虑极限的代码效率时,是一个非常好的选择。再看看最近的MyBatis版本,包括MyBatis Plus设计,很多东西已经和JPA越来越像了。因为在设计上来说,JPA是最接近面向对象编程的思想的。
B端复杂业务的技术栈,并不需要和C端的技术栈相雷同。JPA显然通过极少的代码和约定,就能把事情搞定,让开发者真正的把重点关注到业务开发上来。后面的文章,我们还会用到MyBatis和MyBatis Plus,到时候,我们再详细分析它们使用的场景。
作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。
【编辑推荐】
点赞 0
- 大家都在看
- 猜你喜欢
编辑推荐
- 24H热文
- 一周话题
- 本月获赞
- 使用MySQL命令行修改密码MySQL时间格式化四种优秀的数据库设计工具14个必须掌握的数据库面试题(附答案)MySQL update 语句的正确用法记录一次MySQL两千万数据的大表优化解决过程,提供三种解决方案Java连接MYSQL 数据库的连接步骤DB-Engines 3 月数据库流行度排行:SQL Server 分数暴跌
- 使用MySQL命令行修改密码MySQL时间格式化四种优秀的数据库设计工具MySQL update 语句的正确用法记录一次MySQL两千万数据的大表优化解决过程,提供三种解决方案不会MySQL索引,面试官让回家等通知!14个必须掌握的数据库面试题(附答案)MySQL分库分表,写得太好了!
- 使用MySQL命令行修改密码四种优秀的数据库设计工具MySQL时间格式化记录一次MySQL两千万数据的大表优化解决过程,提供三种解决方案MySQL update 语句的正确用法MySQL分库分表,写得太好了!不会MySQL索引,面试官让回家等通知!MySQL 8.0不讲武德,给我挖坑!
订阅专栏+更多
-
数据湖与数据仓库的分析实践攻略
助力现代化数据管理:数据湖与数据仓库的分析实践攻略共3章 | 创世达人6人订阅学习
-
云原生架构实践
新技术引领移动互联网进入急速赛道共3章 | KaliArch35人订阅学习
-
数据中心和VPDN网络建设案例
漫画+案例共20章 | 捷哥CCIE221人订阅学习
视频课程+更多
-
ClickHouse数据库培训实战 (PB级大数据分析
讲师:风哥3210人学习过
-
VMware vSphere VCP 6.5 | 6.7 |7.0 (附Hori
讲师:郝旺291302人学习过
-
高性能高扩展的千亿级实时数据仓库全实现(通
讲师:友凡2721人学习过
专题推荐+更多
- 精选博文
- 论坛热帖
-
订阅51CTO邮刊
点击这里查看样刊

51CTO服务号

51CTO官微