7

一个迟来的赞,送给JPA。AbstractEntity需要准备些什么?

 3 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzA4MTc4NTUxNQ%3D%3D&%3Bmid=2650523437&%3Bidx=1&%3Bsn=2290c4f5af8eb669b76e3b3bbe781fb4
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

e6JBVrU.gif!mobile

以免费实战教学为目的开源系统bcMall,欢迎star:https://github.com/xjjdog/bcMall

本篇属于代码解析系列文章之一,主要内容是JPA的基础父类设计。参考代码: https://github.com/xjjdog/bcMall/blob/master/bc-utils/src/main/java/cn/xjjdog/bcmall/utils/db/AbstractEntity.java

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

关系型数据库其实很讨人厌,尤其是在你使用数据库驱动的开发模式时。需要首先把表给创建好了,然后再使用代码生成器反向生成一堆几乎无法可读的代码。当字段有变更的时候,又是一番折腾。

这其中的典型,就是MyBatis,所以催生了更加简洁的MyBatis Plus。

了解到一些大厂(阿里、腾讯、抖音等),JPA的使用也越来越广泛了,包括我们公司,这是把合适的工具放到了合适的地方。如果想要快速开发,JPA无疑是一个比较好的选择。你无需关注数据库表的结构,使用代码驱动即可完成工作,管它后面是MySQL还是Oracle。JPA把数据库相关的知识给弱化了,让你专注于业务开发。

我个人曾是非常排斥JPA这种弱化SQL的工具的,这源于对早起Hibernate版本的错误认识。但尝试过mybatis、spring-data-jdbc、jooq后,发现这个东西是真的香!一个迟到的赞,送给JPA。

EZbQbai.png!mobile

这对一些管理系统来说,非常合适。因为性能并不是这些系统主要的痛点,业务复杂性才是。

本文将介绍一个简单的实体类,需要准备哪些基本字段。这些字段,又是如何在代码中被使用的。

1. 基本字段介绍

首先看一下我们的基础定义类。

代码不多,信息却不少。

NJ7FZzN.png!mobile

下面来一行行解析。

@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. 自动填充字段

上面说到 createdDatelastModifiedDate 两个字段,其实在使用的时候,是不需要手动去设值的。这两个值,将通过审计功能自动完成。

@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,欢迎添加好友,进一步交流。

推荐阅读:

一图解千愁,jvm内存从来没有这么简单过!

失联的架构师,只留下一段脚本

架构师写的BUG,非比寻常

nginx工程师,需要上承天命,下召九幽

实力解剖一枚挖矿脚本,风骚操作亮瞎双眼

又一P1故障,锅比脸圆

传统企业的人才们,先别忙着跳“互联网”!

面试官很牛,逼我尿遁

又一批长事务,P0故障谁来背锅?

一天有24个小时?别开玩笑了!

《程序人生》杀机!

可怕的“浏览器指纹”,让你在互联网上,无处可藏

2w字长文,让你瞬间拥有「调用链」开发经验

996的乐趣,你是无法想象的

作为高级Java,你应该了解的Linux知识(非广告)

必看!java后端,亮剑诛仙(最全知识点)

学完这100多技术,能当架构师么?(非广告)

Linux上,最常用的一批命令解析(10年精选)

数百篇「原创」文章,助你完成技术「体系化」

EnUneen.gif!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK