Spring Boot - Hibernate Envers - Liquibase - @Audit aware <insert> statements possible?

问题描述 投票:0回答:1

我们的应用程序过去通过 liquibase

config
<insert>
语句填充我们的
<update>
表条目。 这个
config
表是一个 jpa 实体并利用 hibernate-envers
@Audit
功能。

也有相应的

config_audit
表格。

为了审核通过 liquibase 插入/更新的条目,我正在考虑切换到

<customChange>
变更集。例如

    <changeSet id="my_id" author="author">
        <customChange class="com.app.MyCustomTaskChange">
            <param name="field1" value="val1" />
            <param name="field2" value="val2" />
        </customChange>
    </changeSet>
public class MyCustomTaskChange implements CustomTaskChange, CustomTaskRollback {
    @Setter
    private String field1;

    @Setter
    private String field2;

    @Setter
    private static ConfigJpaRepository configJpaRepository;

    @Override
    public void execute(Database database) throws CustomChangeException {
        configJpaRepository.save(new ConfigEntity(field1, field2));
    }
    
    //other methods excluded for clarity

明确地说,上述方法工作正常,条目按预期添加到

config
config_audit
表中;但是,我想知道是否有更优雅和面向未来的方式允许 liquibase
<insert>
<update>
(或类似)语句锁定到 @Audit 功能中?

spring-boot liquibase hibernate-envers
1个回答
1
投票

首先,我建议不要在数据库迁移中使用

spring
hibernate
的想法,无论它是否有吸引力,它都会使很多事情复杂化,主要问题是一旦您修改,此类迁移就会过时领域模型,所以,迟早
hibernate
可能无法将数据写入数据库。在你的情况下,你能够以某种方式将存储库实例“注入”到
CustomTaskChange
类中只是因为
spring
在运行 liquibase 迁移之前初始化了实体管理器和存储库,但是在最近的
spring
版本中
spring-data-jpa
团队在
liquibase 
hibernate
这样的方法应该行不通,但是可以做类似的事情(抱歉,不记得如何启用
envers
):

public class HibernateCustomTaskChange implements CustomTaskChange {

    @Override
    public void execute(Database database) throws CustomChangeException {
        EntityManagerFactory entityManagerFactory = null;
        EntityManager entityManager = null;
        try {
            entityManagerFactory = getEntityManagerFactory(database, MyEntity.class);
            entityManager = entityManagerFactory.createEntityManager();

            // some logic here


        } finally {
            if (entityManager != null) {
                entityManager.close();
            }
            if (entityManagerFactory != null) {
                entityManagerFactory.close();
            }
        }
    }


    protected EntityManagerFactory getEntityManagerFactory(Database database, Class<?>... entityClasses) {
        DataSource dataSource = createDataSource(database);
        ClassLoader classLoader = Scope.getCurrentScope().getClassLoader();
        MutablePersistenceUnitInfo pui = new MutablePersistenceUnitInfo() {
            @Override
            public ClassLoader getNewTempClassLoader() {
                return classLoader;
            }
        };
        pui.setNonJtaDataSource(dataSource);
        for (Class<?> entityClass : entityClasses) {
            pui.addManagedClassName(entityClass.getName());
        }
        Map<String, Object> settings = new HashMap<>();
        settings.put(AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, true);
        pui.setPersistenceUnitName("liquibase");
        return new EntityManagerFactoryBuilderImpl(
                new PersistenceUnitInfoDescriptor(pui),
                settings,
                classLoader
        ).build();
    }

    protected DataSource createDataSource(Database database) {
        Connection connection = ((JdbcConnection) database.getConnection()).getUnderlyingConnection();
        connection = createConnectionProxy(connection);
        return new SingleConnectionDataSource(connection, true);
    }

    protected Connection createConnectionProxy(Connection con) {
        return (Connection) Proxy.newProxyInstance(
                ConnectionProxy.class.getClassLoader(),
                new Class<?>[]{ConnectionProxy.class},
                new CommitSuppressInvocationHandler(con));
    }

    static class CommitSuppressInvocationHandler implements InvocationHandler {

        private final Connection target;

        public CommitSuppressInvocationHandler(Connection target) {
            this.target = target;
        }

        @Override
        @Nullable
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (ReflectionUtils.isEqualsMethod(method)) {
                return (proxy == args[0]);
            } else if (ReflectionUtils.isHashCodeMethod(method)) {
                return System.identityHashCode(proxy);
            } else if (method.getName().equals("unwrap")) {
                if (((Class<?>) args[0]).isInstance(proxy)) {
                    return proxy;
                }
            } else if (method.getName().equals("isWrapperFor")) {
                if (((Class<?>) args[0]).isInstance(proxy)) {
                    return true;
                }
            } else if (method.getName().equals("close")) {
                return null;
            } else if (method.getName().equals("commit")) {
                return null;
            } else if (method.getName().equals("isClosed")) {
                return false;
            } else if (method.getName().equals("getTargetConnection")) {
                return this.target;
            }

            try {
                return method.invoke(this.target, args);
            } catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }

    }

    // some liquibase method omitted

}

© www.soinside.com 2019 - 2024. All rights reserved.