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拦截器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java调用WebService服务的四种方法总结

    java调用WebService服务的四种方法总结

    WebService是一种跨编程语言、跨操作系统平台的远程调用技术,已存在很多年了,很多接口也都是通过WebService方式来发布的,下面这篇文章主要给大家介绍了关于java调用WebService服务的四种方法,需要的朋友可以参考下
    2021-11-11
  • druid连接池的参数配置示例全面解析

    druid连接池的参数配置示例全面解析

    这篇文章主要为大家介绍了druid连接池的参数配置示例全面解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • LoggingEventAsyncDisruptorAppender类执行流程源码解读

    LoggingEventAsyncDisruptorAppender类执行流程源码解读

    这篇文章主要介绍了LoggingEventAsyncDisruptorAppender类执行流程源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • java猜数字小游戏案例

    java猜数字小游戏案例

    这篇文章主要为大家详细介绍了java猜数字小游戏案例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • Netty粘包拆包问题解决方案

    Netty粘包拆包问题解决方案

    这篇文章主要介绍了Netty粘包拆包问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • 详解IDEA启动多个微服务的配置方法

    详解IDEA启动多个微服务的配置方法

    这篇文章主要介绍了详解IDEA启动多个微服务的配置方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • 使用纯Java实现一个WebSSH项目的示例代码

    使用纯Java实现一个WebSSH项目的示例代码

    这篇文章主要介绍了使用纯Java实现一个WebSSH项目,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • javax.management.InvalidApplicationException的问题解决

    javax.management.InvalidApplicationException的问题解决

    javax.management.InvalidApplicationException是与Java Management Extensions (JMX) API相关的一个常见异常,本文主要介绍了javax.management.InvalidApplicationException的问题解决,感兴趣的可以了解一下
    2024-08-08
  • 使用多个servlet时Spring security需要指明路由匹配策略问题

    使用多个servlet时Spring security需要指明路由匹配策略问题

    这篇文章主要介绍了使用多个servlet时Spring security需要指明路由匹配策略问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Java实现手写一个线程池的示例代码

    Java实现手写一个线程池的示例代码

    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和细节吗?本文就来通过手写一个简单的线程池框架,去掌握线程池的基本原理,感兴趣的可以学习一下
    2022-10-10

最新评论