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

2022-11-13 18:11:13 操作 代码 注入

  最近项目有个改动:另一个系统根据更新时间戳来拉取本系统数据。这就要求基本上所有的数据表都要及时更新时间戳。以前的方式是在新增数据或者修改数据时手动调用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并仅覆盖感兴趣的回调方法。


onFlushDirty():

onSave():

那我们去EmptyInterceptor看一下。

  • EmptyInterceptor类:

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

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

代码实现

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


public interface BaseEntityControl{

	
    default boolean writeTimeStamp() {
        return true;
    }
}
import com.xx.xxx.BaseEntityControl;
import java.io.Serializable;


public class AuditInterceptor extends EmptyInterceptor {

    
    private static final long serialVersionUID = 6892420119984901561L;

    
    @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;
    }

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

相关文章