SpringBoot使用Hibernate拦截器实现时间自动注入的操作代码

 更新时间:2022年10月10日 10:18:13   作者:zhuzZi  
这篇文章主要介绍了SpringBoot使用Hibernate拦截器实现时间自动注入的操作代码,主要包括hibernate拦截器的相关知识,结合实例代码给大家讲解的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  最近项目有个改动:另一个系统根据更新时间戳来拉取本系统数据。这就要求基本上所有的数据表都要及时更新时间戳。以前的方式是在新增数据或者修改数据时手动调用setProperty(TimeStamp),因为没有用到这两个字段加上每个人的编码习惯不同,有时候没设置createTime或者updateTime,可能存在遗漏,导致数据库中有的时间戳默认值0。

前提:本系统时间戳在数据库类型为int,长度为int默认值,存储示例:1665295775,Java类型Integer,单位: /s

  因为没怎么使用过Hibernate框架,就想Hibernate有没有MybatisPlus一样的自动填充功能呢?查了一下还真有日期相关的注解:@Temporal(TemporalType.XXX),但是对应Java的类型为:java.sql.Date,java.sql.Time,java.sql.Timestamp,数据库的类型为时间相关的类型:date,time,datetime,timestamp,在不改动历史数据表字段类型的情况下,只能寻求其它方式。

Hibernate拦截器:

  • Interceptor接口:

允许用户代码检查和/或更改属性值。检查发生在属性值写入之前和从数据库中读取之后。 SessionFactory可能有一个Interceptor实例,或者可能为每个Session指定一个新实例。无论使用哪种方法,如果Session要可序列化,则拦截器必须是可序列化的。这意味着SessionFactory范围的拦截器应该实现readResolve() 。 Session不能从回调中调用(回调也不能导致集合或代理被延迟初始化)。与其直接实现此接口,不如继承EmptyInterceptor并仅覆盖感兴趣的回调方法。

/**
在刷新期间检测到对象脏时调用。拦截器可能会修改检测到的currentState ,这将被传播到数据库和持久对象。
请注意,并非所有刷新都以与数据库的实际同步结束,在这种情况下,新的currentState将传播到对象,但不一定(立即)传播到数据库。
强烈建议拦截器不要修改previousState 。
*/
onFlushDirty():
/**
在保存对象之前调用。拦截器可能会修改状态,该状态将用于 SQL INSERT并传播到持久对象。
*/
onSave():

那我们去EmptyInterceptor看一下。

  • EmptyInterceptor类:

一个什么都不做的拦截器。可用作应用程序定义的自定义拦截器的基类 。

参看上面接口的方法描述,我们只需要继承EmptyInterceptor并重写onSave()和onFlushDirty()两个方法,来分别实现保存(SQL INSERT)更新(SQL UPDATE)即可。Hibernate在检测到save和update操作时先执行自定义逻辑。

代码实现

看完了拦截器相关,来实现一下代码,如下:
为了控制每个DDO的行为,可以设计一个BaseEntityControl接口

/**
 * 数据的顶层接口
 */
public interface BaseEntityControl{

	/**
	可以加入其它逻辑
	/

    /**
     * 控制是否需要自动写入createTime和updateTime
     * @return
     */
    default boolean writeTimeStamp() {
        return true;
    }
}
import com.xx.xxx.BaseEntityControl;
import java.io.Serializable;

/**
 * Interceptor for entity audits.
 */
public class AuditInterceptor extends EmptyInterceptor {

    /**
     * Serial version UID
     */
    private static final long serialVersionUID = 6892420119984901561L;

    /**
     * @see org.hibernate.Interceptor#onFlushDirty(Object, Serializable, Object[], Object[], String[], Type[])
     */
    @Override
    public boolean onFlushDirty(final Object entity, final Serializable id, final Object[] currentState,
            final Object[] previousState, final String[] propertyNames, final Type[] types) {
        if (entity instanceof BaseEntityControl) {
            if (!((BaseEntityControl) entity).writeTimeStamp()) {
                return false;
            }
            for (int i = 0; i < propertyNames.length; i++) {
                if ("updateTime".equals(propertyNames[i])) {
                    currentState[i] = (int) (System.currentTimeMillis() / 1000);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * @see org.hibernate.Interceptor#onSave(Object, Serializable, Object[], String[], Type[])
     */
    @Override
    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        if (entity instanceof BaseEntityControl) {
            if (!((BaseEntityControl) entity).writeTimeStamp()) {
                return false;
            }
            boolean crtModify = false;
            boolean uptModify = false;
            int i = 0;
            while (true) {
                if (i >= propertyNames.length) {
                    if (crtModify || uptModify) {
                        return true;
                    }
                    break;
                }

                if ("createTime".equals(propertyNames[i])) {
                    crtModify = true;
                    state[i] = (int) (System.currentTimeMillis() / 1000L);
                }

                if ("updateTime".equals(propertyNames[i])) {
                    uptModify = true;
                    state[i] = (int) (System.currentTimeMillis() / 1000L);
                }
                ++i;
            }
        }
        return false;
    }
}

将自定义Interceptor配置到session factory

在session factory配置类中将

public class xxxConfig {
	...
	public FactoryBean<SessionFactory> getSessionFactory() {
		LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
		sessionFactoryBean.setEntityInterceptor(new AuditInterceptor());
		...
	}
	...
}

对比测试

4.0.9:加入拦截器之前
4.3.1:加入拦截器之后

单个对象20个property情况下:

到此这篇关于SpringBoot使用Hibernate拦截器实现时间自动注入的操作代码的文章就介绍到这了,更多相关SpringBoot使用Hibernate拦截器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JDK集合源码之解析TreeMap(二)

    JDK集合源码之解析TreeMap(二)

    下面小编就为大家带来一篇浅谈java中的TreeMap 排序与TreeSet 排序。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-07-07
  • Springmvc调用存储过程,并返回存储过程返还的数据方式

    Springmvc调用存储过程,并返回存储过程返还的数据方式

    这篇文章主要介绍了Springmvc调用存储过程,并返回存储过程返还的数据方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java Pattern与Matcher字符串匹配案例详解

    Java Pattern与Matcher字符串匹配案例详解

    这篇文章主要介绍了Java Pattern与Matcher字符串匹配案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • ThreadLocal的内存泄露问题

    ThreadLocal的内存泄露问题

    这篇文章主要介绍了Java中ThreadLocal的内存泄露问题,以及为什么会出现内存泄漏,感兴趣的小伙伴可以参考阅读
    2023-03-03
  • java easyUI实现自定义网格视图实例代码

    java easyUI实现自定义网格视图实例代码

    这篇文章主要给大家介绍了关于java easyUI实现自定义网格视图的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-10-10
  • java实现KFC点餐小程序

    java实现KFC点餐小程序

    这篇文章主要为大家详细介绍了java实现KFC点餐系统小程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 浅谈@PostConstruct不被调用的原因

    浅谈@PostConstruct不被调用的原因

    这篇文章主要介绍了浅谈@PostConstruct不被调用的原因及分析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • java弹幕小游戏1.0版本

    java弹幕小游戏1.0版本

    这篇文章主要为大家详细介绍了java弹幕小游戏1.0版本,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • 解决Error:(5,55)java:程序包org.springframework.cloud.netflix.eureka.server不存在问题

    解决Error:(5,55)java:程序包org.springframework.cloud.netflix.eure

    这篇文章主要介绍了解决Error:(5,55)java:程序包org.springframework.cloud.netflix.eureka.server不存在问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • SpringBoot使用MapStruct生成映射代码的示例详解

    SpringBoot使用MapStruct生成映射代码的示例详解

    MapStruct 是一个用于 Java 的代码生成器,专门用于生成类型安全的 bean 映射代码,它通过注解处理器在编译时生成映射代码,从而避免了运行时的性能开销和潜在的错误,本文给大家介绍了SpringBoot使用MapStruct生成映射代码的示例,需要的朋友可以参考下
    2024-11-11

最新评论