发出休眠拦截器

时间:2018-07-13 15:05:49

标签: java spring hibernate hibernate-5.x

我在Spring 4和Hibernate 5中进行了以下设置: 这是设置Hibernate的applicationContext.xml的摘录

    <bean id="myAuditLogInterceptorManager" class="company.audit.AuditLogManager">
        <constructor-arg>
            <ref bean="interceptorSessionFactory" />
        </constructor-arg>
    </bean>


    <bean id="auditInterceptor"
        class="company.interceptor.audit.AuditLogInterceptor">
        <property name="sessionFactory" ref="interceptorSessionFactory" />
        <property name="auditLogManager" ref="myAuditLogInterceptorManager" />
    </bean>

    <bean id="interceptorSessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.order_inserts">${hibernate.order_inserts}</prop>
                <prop key="hibernate.order_updates">${hibernate.order_updates}</prop>
                <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
                <prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
                <prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>

            </props>
        </property>
        <property name="dataSource">
            <ref bean="myDataSource" />
        </property>
    </bean>


    <bean id="mySessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
        depends-on="flyway">

        <property name="entityInterceptor" ref="auditInterceptor" />

        <property name="packagesToScan">
            <list>******
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.order_inserts">${hibernate.order_inserts}</prop>
                <prop key="hibernate.order_updates">${hibernate.order_updates}</prop>
                <prop key="hibernate.event.merge.entity_copy_observer">allow</prop>
                <prop key="hibernate.generate_statistics">true</prop>
                        <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
                <prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
                <prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>




            </props>
        </property>
        <property name="dataSource">
            <ref bean="myDataSource" />
        </property>
    </bean>

    <bean id="myDataSource" class="org.apache.tomcat.jdbc.pool.DataSource"
        destroy-method="close" p:driverClassName="${datasource.driverClass}"
        p:url="${datasource.url}" p:username="${datasource.user}" p:password="${datasource.pass}"
        p:maxWait="${datasource.maxWait}" p:minIdle="${datasource.minIdle}"
        p:maxIdle="${datasource.maxIdle}" p:maxActive="${datasource.maxActive}"
        p:fairQueue="true" p:jmxEnabled="${datasource.jmxEnabled}"
        p:removeAbandoned="${datasource.removeAbandoned}"
        p:removeAbandonedTimeout="${datasource.removeAbandonedTimeout}"
        p:logAbandoned="${datasource.logAbandoned}" p:testOnBorrow="${datasource.testOnBorrow}"
        p:timeBetweenEvictionRunsMillis="${datasource.timeBetweenEvictionRunsMillis}"
        p:minEvictableIdleTimeMillis="${datasource.minEvictableIdleTimeMillis}"
        p:validationInterval="${datasource.validationInterval}"
        p:abandonWhenPercentageFull="${datasource.abandonWhenPercentageFull}"
        p:validationQuery="SELECT 1"
        p:jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.ConnectionState" />

我有两个会话工厂,一个用于AuditLogManager,另一个用于其余的应用程序。 AuditLogManager是负责在数据库中编写审核的类:

然后是AuditLogManager类:

public class AuditLogManager {

private final Logger    log = Logger.getLogger(this.getClass().getName());

protected SessionFactory    sessionFactory;

public AuditLogManager(final SessionFactory sessionFactory) {
    super();
    this.sessionFactory = sessionFactory;
}

private static Long getCurrentUserId() {
    Object currentUserID = null;
    if (SecurityContextHolder.getContext().getAuthentication() != null) {
        currentUserID = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        if (currentUserID == null)
            return Long.valueOf(-1);

        else if (currentUserID.toString().contains("anonymousUser"))
            return Long.valueOf(-1);
        return Long.parseLong(currentUserID.toString());
    }
    return Long.valueOf(-1);
}

public void log(final String message, final AuditType type, final Long customerGroupId, final String objectType, final String objectName) {

    if (message.isEmpty())
        return;

    this.log(message, type, customerGroupId, objectType, objectName, "");
}

public SessionFactory getSessionFactory() {

    final SessionFactory mySessionFactory = this.sessionFactory;

    return mySessionFactory;
}

public void log(final String message, final AuditType type, final Long customerGroupId, final String objectType, final String objectName, final String operation) {

    if (message.isEmpty())
        return;

    final Long userId = AuditLogManager.getCurrentUserId();
    final Date timestamp = new Date();
    StatelessSession session = null;
    try {
        session = this.getSessionFactory().openStatelessSession();

        final StringBuilder query = new StringBuilder();

        query.append(" SET NOCOUNT ON; ");
        query.append(" INSERT INTO [dbo].[SystemAudits] ");
        query.append("            ( [message] ");
        query.append("            ,[user_fk] ");
        query.append("            ,[customerGroup_fk] ");
        query.append("            ,[type] ");
        query.append("            ,[operation] ");
        query.append("           ,[timestamp] ");
        query.append("           ,[objectType] ");
        query.append("           ,[objectName]) ");
        query.append("     VALUES ");
        query.append("           ( :message  ");
        query.append("           , :userId ");
        query.append("           , :customerGroupId ");
        query.append("           , :type ");
        query.append("           , :operation ");
        query.append("           , :timestamp ");
        query.append("           , :objectType ");
        query.append("           , :objectName");
        query.append("       ) ");

        query.append(" SET NOCOUNT OFF; ");

        final Transaction tx = session.beginTransaction();
        final SQLQuery sqlQuery = session.createSQLQuery(query.toString());
        sqlQuery.setParameter("message", message);
        sqlQuery.setParameter("userId", userId);
        sqlQuery.setParameter("customerGroupId", customerGroupId);
        sqlQuery.setParameter("type", type.name());
        sqlQuery.setParameter("operation", operation);
        sqlQuery.setParameter("timestamp", timestamp);
        sqlQuery.setParameter("objectType", objectType);
        sqlQuery.setParameter("objectName", objectName);
        sqlQuery.executeUpdate();
        tx.commit();

    } catch (final Exception e) {
        this.log.error(e, "Error");
    } finally {
        if (session != null)
            session.close();
    }
}

}

拦截器收集实现接口IAuditLog的对象。我根据对象的状态将它们放在三个Set中(Create / Delete / Update)。在postFlush函数上,我迭代对象列表并记录一个条目:

public class AuditLogInterceptor extends EmptyInterceptor {

protected Logger            log     = Logger.getLogger(this.getClass().getName());

private AuditLogManager         auditLogManager;

private final Set<IAuditLog>    inserts = Collections.synchronizedSet(new HashSet());
private final Set<IAuditLog>    updates = Collections.synchronizedSet(new HashSet());
private final Set<IAuditLog>    deletes = Collections.synchronizedSet(new HashSet());

@Override
public boolean onSave(final Object entity, final Serializable id, final Object[] state, final String[] propertyNames, final Type[] types) throws CallbackException {

    this.log.trace("onSave");
    if (entity instanceof IAuditLog)
        this.inserts.add((IAuditLog) entity);
    return false;

}

@Override
public boolean onFlushDirty(final Object entity, final Serializable id, final Object[] currentState, final Object[] previousState, final String[] propertyNames, final Type[] types) throws CallbackException {
    this.log.trace("onFlushDirty");
    if (entity instanceof IAuditLog)
        this.updates.add((IAuditLog) entity);
    return false;

}

@Override
public void onDelete(final Object entity, final Serializable id, final Object[] state, final String[] propertyNames, final Type[] types) {
    this.log.trace("onDelete");
    if (entity instanceof IAuditLog)
        this.deletes.add((IAuditLog) entity);
}

// called before commit into database
@Override
public void preFlush(final Iterator iterator) {
}

// called after committed into database
@Override
public void postFlush(final Iterator iterator) {
    this.log.trace("postFlush");
    try {

        final Iterator<IAuditLog> iter = this.inserts.iterator();

        while (iter.hasNext()) {
            final IAuditLog entity = iter.next();
            final String objectType = entity.getAuditLogObjectType();
            if (objectType != null) {
                final String objectName = entity.getAuditLogObjectName();
                final AuditType type = entity.getAuditType();
                final Long customerGroupId = entity.getAuditCustomerAdministratorId();
                final List<String> changes = entity.getChanges();

                this.auditLogManager.log(StringUtils.join(changes, ","), type, customerGroupId, objectType, objectName, "CREATE");

            }

        }

    } catch (final Exception e) {
        this.log.error(e, "Error");

    } finally {
        this.inserts.clear();
    }

    try {
        final Iterator<IAuditLog> iter = this.updates.iterator();
        while (iter.hasNext()) {
            final IAuditLog entity = iter.next();
            final String objectType = entity.getAuditLogObjectType();
            if (objectType != null) {
                final String objectName = entity.getAuditLogObjectName();
                final AuditType type = entity.getAuditType();
                final Long customerGroupId = entity.getAuditCustomerAdministratorId();
                final List<String> changes = entity.getChanges();
                this.auditLogManager.log(StringUtils.join(changes, ","), type, customerGroupId, objectType, objectName, "UPDATE");
            }

        }

    } catch (final Exception e) {
        this.log.error(e, "Error");

    } finally {
        this.updates.clear();
    }

    try {
        final Iterator<IAuditLog> iter = this.deletes.iterator();
        while (iter.hasNext()) {
            final IAuditLog entity = iter.next();
            final String objectType = entity.getAuditLogObjectType();
            if (objectType != null) {
                final String objectName = entity.getAuditLogObjectName();
                final AuditType type = entity.getAuditType();
                final Long customerGroupId = entity.getAuditCustomerAdministratorId();
                final List<String> changes = entity.getChanges();
                this.auditLogManager.log(StringUtils.join(changes, ","), type, customerGroupId, objectType, objectName, "DELETE");
            }

        }
    } catch (final Exception e) {
        this.log.error(e, "Error");

    } finally {
        this.deletes.clear();
    }
}

public AuditLogManager getAuditLogManager() {
    return this.auditLogManager;
}

public void setAuditLogManager(final AuditLogManager auditLogManager) {
    this.auditLogManager = auditLogManager;
}

}

有时,我会收到以下错误消息:

java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
    at java.util.HashMap$KeyIterator.next(HashMap.java:1466)
    at compnay.interceptor.audit.AuditLogInterceptor.postFlush(AuditLogInterceptor.java:72)

我不知道怎么了 谢谢

0 个答案:

没有答案