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

相关文章

  • mybatis的坑-integer类型为0的数据if test失效问题

    mybatis的坑-integer类型为0的数据if test失效问题

    这篇文章主要介绍了mybatis的坑-integer类型为0的数据if test失效问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • springboot工程如何使用阿里云OSS传输文件

    springboot工程如何使用阿里云OSS传输文件

    阿里云对象存储OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,多种存储类型供选择,全面优化存储成本,非常适合存储非结构化数据,本文给大家介绍springboot工程使用阿里云OSS传输文件的操作,感兴趣的朋友一起看看吧
    2023-08-08
  • Java 按行读取文件按行写入文件并以空格分割字符串的方法

    Java 按行读取文件按行写入文件并以空格分割字符串的方法

    今天小编就为大家分享一篇Java 按行读取文件按行写入文件并以空格分割字符串的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • Spring Boot2.x集成JPA快速开发的示例代码

    Spring Boot2.x集成JPA快速开发的示例代码

    这篇文章主要介绍了Spring Boot2.x集成JPA快速开发,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • Spring Boot使用Servlet及Filter过程详解

    Spring Boot使用Servlet及Filter过程详解

    这篇文章主要介绍了Spring Boot使用Servlet及Filter过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • 2021年最新Redis面试题汇总(1)

    2021年最新Redis面试题汇总(1)

    在程序员面试过程中redis相关的知识是常被问到的话题。这篇文章主要介绍了几道Redis面试题,整理一下分享给大家,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • 详解Java中Iterable与Iterator用法

    详解Java中Iterable与Iterator用法

    在本文中小编给大家分享了关于Java中Iterable与Iterator的用法知识点内容,有兴趣的朋友们可以学习下。
    2018-10-10
  • 使用JMX监控Zookeeper状态Java API

    使用JMX监控Zookeeper状态Java API

    今天小编就为大家分享一篇关于使用JMX监控Zookeeper状态Java API,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Java中避免写嵌套if样式的代码详解

    Java中避免写嵌套if样式的代码详解

    这篇文章主要给大家介绍了在Java中如何避免写嵌套if样式的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。
    2017-07-07
  • Spring Boot集成Druid出现异常报错的原因及解决

    Spring Boot集成Druid出现异常报错的原因及解决

    Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。本文讲述了Spring Boot集成Druid项目中discard long time none received connection异常的解决方法,出现此问题的同学可以参考下
    2021-05-05

最新评论