INT-2562: JPA: Add 'flush' Operation
JIRA: https://jira.springsource.org/browse/INT-2562 INT-2562: Add 'flush-size' & 'clear-on-flush' attrs INT-2562: Documentation INT-2562: Polishing INT-2562: Addressing PR's comments INT-2562: Fix typos and JavaDocs
This commit is contained in:
committed by
Gary Russell
parent
34683bd560
commit
14c966c1fa
@@ -67,6 +67,7 @@ public class JpaInboundChannelAdapterParser extends AbstractPollingInboundChanne
|
||||
jpaExecutorBuilder.addPropertyValue("maxResultsExpression", definition);
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "delete-after-poll");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "flush-after-delete", "flush");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "delete-in-batch");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "expect-single-result");
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.integration.jpa.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
@@ -25,7 +27,6 @@ import org.springframework.integration.config.xml.AbstractOutboundChannelAdapter
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.jpa.outbound.JpaOutboundGatewayFactoryBean;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* The parser for JPA outbound channel adapter
|
||||
@@ -55,6 +56,9 @@ public class JpaOutboundChannelAdapterParser extends AbstractOutboundChannelAdap
|
||||
final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getJpaExecutorBuilder(element, parserContext);
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "persist-mode");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "flush");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "flush-size");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "clear-on-flush");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "parameter-source-factory");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "use-payload-as-parameter-source");
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ public class RetrievingJpaOutboundGatewayParser extends AbstractJpaOutboundGatew
|
||||
}
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "delete-after-poll");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "flush-after-delete", "flush");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "delete-in-batch");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "expect-single-result");
|
||||
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
package org.springframework.integration.jpa.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.jpa.support.OutboundGatewayType;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* The Parser for Updating JPA Outbound Gateway.
|
||||
@@ -42,6 +43,9 @@ public class UpdatingJpaOutboundGatewayParser extends AbstractJpaOutboundGateway
|
||||
final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getOutboundGatewayJpaExecutorBuilder(gatewayElement, parserContext);
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "persist-mode");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "flush");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "flush-size");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "clear-on-flush");
|
||||
|
||||
final BeanDefinition jpaExecutorBuilderBeanDefinition = jpaExecutorBuilder.getBeanDefinition();
|
||||
final String gatewayId = this.resolveId(gatewayElement, jpaOutboundGatewayBuilder.getRawBeanDefinition(), parserContext);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.util.Assert;
|
||||
abstract class AbstractJpaOperations implements JpaOperations, InitializingBean {
|
||||
|
||||
protected EntityManager entityManager;
|
||||
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
|
||||
|
||||
@@ -65,4 +66,9 @@ abstract class AbstractJpaOperations implements JpaOperations, InitializingBean
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
this.entityManager.flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -203,17 +203,28 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
|
||||
@Override
|
||||
public Object merge(Object entity) {
|
||||
return this.merge(entity, 0, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object merge(Object entity, int flushSize, boolean clearOnFlush) {
|
||||
Assert.notNull(entity, "The object to merge must not be null.");
|
||||
return persistOrMerge(entity, true);
|
||||
return this.persistOrMerge(entity, true, flushSize, clearOnFlush);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persist(Object entity) {
|
||||
Assert.notNull(entity, "The object to persist must not be null.");
|
||||
persistOrMerge(entity, false);
|
||||
this.persist(entity, 0, false);
|
||||
}
|
||||
|
||||
private Object persistOrMerge(Object entity, boolean isMerge) {
|
||||
@Override
|
||||
public void persist(Object entity, int flushSize, boolean clearOnFlush) {
|
||||
Assert.notNull(entity, "The object to persist must not be null.");
|
||||
persistOrMerge(entity, false, flushSize, clearOnFlush);
|
||||
}
|
||||
|
||||
private Object persistOrMerge(Object entity, boolean isMerge, int flushSize, boolean clearOnFlush) {
|
||||
Object result = null;
|
||||
|
||||
if (entity instanceof Iterable) {
|
||||
|
||||
@@ -237,6 +248,12 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
entityManager.persist(iteratedEntity);
|
||||
}
|
||||
savedEntities++;
|
||||
if (flushSize > 0 && savedEntities % flushSize == 0) {
|
||||
entityManager.flush();
|
||||
if (clearOnFlush) {
|
||||
entityManager.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,30 +263,34 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
}
|
||||
|
||||
if (isMerge) {
|
||||
return mergedEntities;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
result = mergedEntities;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isMerge) {
|
||||
return entityManager.merge(entity);
|
||||
result = entityManager.merge(entity);
|
||||
}
|
||||
else {
|
||||
entityManager.persist(entity);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (flushSize > 0) {
|
||||
entityManager.flush();
|
||||
if (clearOnFlush) {
|
||||
entityManager.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a JPQL query, this method gets all parameters defined in this query and
|
||||
* use the {@link JPAQLParameterSource} to find their values and set them
|
||||
* use the {@link ParameterSource} to find their values and set them.
|
||||
*
|
||||
*/
|
||||
private void setParametersIfRequired(String queryString,
|
||||
ParameterSource source, Query query) {
|
||||
private void setParametersIfRequired(String queryString, ParameterSource source, Query query) {
|
||||
Set<Parameter<?>> parameters = query.getParameters();
|
||||
|
||||
if(parameters != null && !parameters.isEmpty()) {
|
||||
@@ -311,4 +332,5 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Amol Nayak
|
||||
* @author Artem Bilan
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@@ -84,7 +85,14 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
private volatile ParameterSourceFactory parameterSourceFactory = null;
|
||||
private volatile ParameterSource parameterSource;
|
||||
|
||||
private volatile boolean flush = false;
|
||||
|
||||
private volatile int flushSize = 0;
|
||||
|
||||
private volatile boolean clearOnFlush = false;
|
||||
|
||||
private volatile boolean deleteAfterPoll = false;
|
||||
|
||||
private volatile boolean deleteInBatch = false;
|
||||
|
||||
private volatile boolean expectSingleResult = false;
|
||||
@@ -194,6 +202,13 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
this.usePayloadAsParameterSource = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.flushSize > 0) {
|
||||
this.flush = true;
|
||||
}
|
||||
else if (this.flush) {
|
||||
this.flushSize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,14 +243,17 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
else {
|
||||
|
||||
if (PersistMode.PERSIST.equals(this.persistMode)) {
|
||||
this.jpaOperations.persist(message.getPayload());
|
||||
this.jpaOperations.persist(message.getPayload(), this.flushSize, this.clearOnFlush);
|
||||
result = message.getPayload();
|
||||
}
|
||||
else if (PersistMode.MERGE.equals(this.persistMode)) {
|
||||
result = this.jpaOperations.merge(message.getPayload());
|
||||
result = this.jpaOperations.merge(message.getPayload(), this.flushSize, this.clearOnFlush);
|
||||
}
|
||||
else if (PersistMode.DELETE.equals(this.persistMode)) {
|
||||
this.jpaOperations.delete(message.getPayload());
|
||||
if (this.flush) {
|
||||
this.jpaOperations.flush();
|
||||
}
|
||||
result = message.getPayload();
|
||||
}
|
||||
else {
|
||||
@@ -310,6 +328,9 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
this.jpaOperations.delete(payload);
|
||||
}
|
||||
|
||||
if (this.flush) {
|
||||
this.jpaOperations.flush();
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
@@ -453,6 +474,45 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
this.usePayloadAsParameterSource = usePayloadAsParameterSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@code true} the {@link javax.persistence.EntityManager#flush()} will be called
|
||||
* after persistence operation.
|
||||
* Has the same effect, if the {@link #flushSize} is specified to {@code 1}.
|
||||
* For convenience in cases when the provided entity to persist is not an instance of {@link Iterable}.
|
||||
*
|
||||
* @param flush defaults to 'false'.
|
||||
*/
|
||||
public void setFlush(boolean flush) {
|
||||
this.flush = flush;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the provided value is greater than {@code 0}, then {@link javax.persistence.EntityManager#flush()}
|
||||
* will be called after persistence operations as well as within batch operations.
|
||||
* This property has precedence over the {@link #flush}, if it is specified to a value greater than {@code 0}.
|
||||
* If the entity to persist is not an instance of {@link Iterable} and this property is greater than {@code 0},
|
||||
* then the entity will be flushed as if the {@link #flush} attribute was set to {@code true}.
|
||||
*
|
||||
* @param flushSize defaults to '0'.
|
||||
*/
|
||||
public void setFlushSize(int flushSize) {
|
||||
Assert.state(flushSize >= 0, "'flushSize' cannot be less than '0'.");
|
||||
this.flushSize = flushSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@code true} the {@link javax.persistence.EntityManager#clear()} will be called,
|
||||
* and only if the {@link javax.persistence.EntityManager#flush()} was called after performing persistence operations.
|
||||
*
|
||||
* @see #setFlush(boolean)
|
||||
* @see #setFlushSize(int)
|
||||
*
|
||||
* @param clearOnFlush defaults to 'false'.
|
||||
*/
|
||||
public void setClearOnFlush(boolean clearOnFlush) {
|
||||
this.clearOnFlush = clearOnFlush;
|
||||
}
|
||||
|
||||
/**
|
||||
* If not set, this property defaults to <code>false</code>, which means that
|
||||
* deletion occurs on a per object basis if a collection of entities is being
|
||||
|
||||
@@ -158,6 +158,19 @@ public interface JpaOperations {
|
||||
*/
|
||||
Object merge(Object entity);
|
||||
|
||||
/**
|
||||
* The entity to be merged with the {@link EntityManager}. The provided object can
|
||||
* also be an {@link Iterable} in which case each object of the {@link Iterable}
|
||||
* is treated as an entity and merged with the {@link EntityManager}.
|
||||
* In addition the {@link javax.persistence.EntityManager#flush()} is called after the merge
|
||||
* and after each batch, as it is specified using {@code flushSize} parameter and if
|
||||
* provided object is {@link Iterable}.
|
||||
* {@code clearOnFlush}parameter specifies, if the {@link javax.persistence.EntityManager#clear()}
|
||||
* should be called after each {@link javax.persistence.EntityManager#flush()}.
|
||||
*/
|
||||
|
||||
Object merge(Object entity, int flushSize, boolean clearOnFlush);
|
||||
|
||||
/**
|
||||
* Persists the entity. The provided object can also be an {@link Iterable}
|
||||
* in which case each object of the {@link Iterable} is treated as an entity
|
||||
@@ -169,4 +182,22 @@ public interface JpaOperations {
|
||||
*/
|
||||
void persist(Object entity);
|
||||
|
||||
/**
|
||||
* Persists the entity. The provided object can also be an {@link Iterable}
|
||||
* in which case each object of the {@link Iterable} is treated as an entity
|
||||
* and persisted with the {@link EntityManager}. {@code Null} values returned
|
||||
* while iterating over the {@link Iterable} are ignored.
|
||||
* In addition the {@link javax.persistence.EntityManager#flush()} is called after the persist
|
||||
* and after each batch, as it is specified using {@code flushSize} parameter and if
|
||||
* provided object is {@link Iterable}.
|
||||
* {@code clearOnFlush}parameter specifies, if the {@link javax.persistence.EntityManager#clear()}
|
||||
* should be called after each {@link javax.persistence.EntityManager#flush()}.
|
||||
*/
|
||||
void persist(Object entity, int flushSize, boolean clearOnFlush);
|
||||
|
||||
/**
|
||||
* Executes {@link javax.persistence.EntityManager#flush()}.
|
||||
*/
|
||||
void flush();
|
||||
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
Specifies whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
@@ -411,6 +411,39 @@
|
||||
<xsd:union memberTypes="persistMode xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="flush" type="xsd:string" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specifies whether EntityManager.flush() should be called after performing persistence operations.
|
||||
If 'flush-size' is configured to a value greater than '0' this attribute will be ignored.
|
||||
Defaults to 'false'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="flush-size" type="xsd:string" default="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specifies the number of entities after which to call EntityManager.flush()
|
||||
when performing persistence operations.
|
||||
This attribute is applicable for payload instances of "java.lang.Iterable".
|
||||
Defaults to '0' - 'flush' won't be called.
|
||||
This attribute has precedence over the 'flush' attribute,
|
||||
if it is configured to a value greater than '0'.
|
||||
If the entity to persist is not an instance of "java.lang.Iterable"
|
||||
and 'flush-size' is greater than '0',
|
||||
then the entity will be flushed as if the 'flush' attribute was set to 'true'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="clear-on-flush" type="xsd:string" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specifies whether EntityManager.clear() should be called after EntityManager.flush().
|
||||
Applies only if 'flush-size > 0' or 'flush = true'.
|
||||
Defaults to 'false'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="commonRetrievingJpaAttributes">
|
||||
@@ -495,6 +528,15 @@
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="flush-after-delete" type="xsd:string" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specifies whether EntityManager.flush() should be called after performing 'deletes' for retrieved entities.
|
||||
Applies only if 'delete-after-poll = true'.
|
||||
Defaults to 'false'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="coreJpaComponentAttributes">
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.springframework.integration.test.util.TestUtils;
|
||||
/**
|
||||
* @author Gunnar Hillert
|
||||
* @author Amol Nayak
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
@@ -95,6 +96,8 @@ public class JpaInboundChannelAdapterParserTests {
|
||||
|
||||
assertEquals("13", TestUtils.getPropertyValue(expression, "literalValue"));
|
||||
|
||||
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "deleteAfterPoll", Boolean.class));
|
||||
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "flush", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
max-results="13"
|
||||
delete-after-poll="true"
|
||||
flush-after-delete="true"
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
@@ -39,6 +39,7 @@ import org.springframework.integration.test.util.TestUtils;
|
||||
/**
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@@ -81,6 +82,8 @@ public class JpaMessageHandlerParserTests {
|
||||
assertNotNull(jpaParameters);
|
||||
assertTrue(jpaParameters.size() == 3);
|
||||
|
||||
assertEquals(Integer.valueOf(10), TestUtils.getPropertyValue(jpaExecutor, "flushSize", Integer.class));
|
||||
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "clearOnFlush", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
jpa-query="from Student"
|
||||
persist-mode="PERSIST"
|
||||
flush-size="10"
|
||||
clear-on-flush="true"
|
||||
order="1"
|
||||
channel="target">
|
||||
<int-jpa:parameter name="firstName" value="kenny" type="java.lang.String"/>
|
||||
|
||||
@@ -80,6 +80,9 @@ public class JpaOutboundGatewayParserTests extends AbstractRequestHandlerAdvice
|
||||
TestUtils.getPropertyValue(jpaExecutor, "maxResultsExpression", LiteralExpression.class);
|
||||
assertNotNull(maxResultsExpression);
|
||||
assertEquals("55", TestUtils.getPropertyValue(maxResultsExpression, "literalValue"));
|
||||
|
||||
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "deleteAfterPoll", Boolean.class));
|
||||
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "flush", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -160,6 +163,8 @@ public class JpaOutboundGatewayParserTests extends AbstractRequestHandlerAdvice
|
||||
|
||||
assertEquals(PersistMode.PERSIST, persistMode);
|
||||
|
||||
assertEquals(Integer.valueOf(100), TestUtils.getPropertyValue(jpaExecutor, "flushSize", Integer.class));
|
||||
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "clearOnFlush", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
order="1"
|
||||
max-number-of-results="55"
|
||||
delete-after-poll="true"
|
||||
flush-after-delete="true"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
@@ -72,6 +74,8 @@
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
flush-size="100"
|
||||
clear-on-flush="true"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:updating-outbound-gateway id="advised"
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
package org.springframework.integration.jpa.core;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.text.ParseException;
|
||||
@@ -255,8 +257,7 @@ public class AbstractJpaOperationsTests {
|
||||
Assert.assertNull(student2.getRollNumber());
|
||||
Assert.assertNull(student3.getRollNumber());
|
||||
|
||||
Object savedStudents = jpaOperations.merge(students);
|
||||
entityManager.flush();
|
||||
Object savedStudents = jpaOperations.merge(students, 10, true);
|
||||
|
||||
Assert.assertTrue(savedStudents instanceof List<?>);
|
||||
|
||||
@@ -329,9 +330,10 @@ public class AbstractJpaOperationsTests {
|
||||
final StudentDomain student = JpaTestUtils.getTestStudent();
|
||||
|
||||
Assert.assertNull(student.getRollNumber());
|
||||
jpaOperations.persist(student);
|
||||
entityManager.flush();
|
||||
jpaOperations.persist(student, 1, false);
|
||||
Assert.assertNotNull(student.getRollNumber());
|
||||
|
||||
assertTrue(entityManager.contains(student));
|
||||
}
|
||||
|
||||
public void testPersistCollection() {
|
||||
@@ -355,11 +357,14 @@ public class AbstractJpaOperationsTests {
|
||||
Assert.assertNull(student2.getRollNumber());
|
||||
Assert.assertNull(student3.getRollNumber());
|
||||
|
||||
jpaOperations.persist(students);
|
||||
entityManager.flush();
|
||||
jpaOperations.persist(students, 1, true);
|
||||
Assert.assertNotNull(student1.getRollNumber());
|
||||
Assert.assertNotNull(student2.getRollNumber());
|
||||
Assert.assertNotNull(student3.getRollNumber());
|
||||
|
||||
assertFalse(entityManager.contains(student1));
|
||||
assertFalse(entityManager.contains(student2));
|
||||
assertFalse(entityManager.contains(student3));
|
||||
}
|
||||
|
||||
public void testPersistNullCollection() {
|
||||
@@ -401,8 +406,8 @@ public class AbstractJpaOperationsTests {
|
||||
Assert.assertNull(student2);
|
||||
Assert.assertNull(student3.getRollNumber());
|
||||
|
||||
jpaOperations.persist(students);
|
||||
entityManager.flush();
|
||||
jpaOperations.persist(students, 10, false);
|
||||
|
||||
Assert.assertNotNull(student1.getRollNumber());
|
||||
Assert.assertNotNull(student3.getRollNumber());
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
<import resource="classpath:/commonJpa-context.xml" />
|
||||
|
||||
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
|
||||
|
||||
<bean id="vendorAdaptor" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"
|
||||
parent="abstractVendorAdaptor">
|
||||
<property name="database" value="H2" />
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
<import resource="classpath:/commonJpa-context.xml" />
|
||||
|
||||
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.OpenJpaDialect"/>
|
||||
|
||||
<!-- EclipseLink vendor adaptor with workaround platform class for HSQL usage -->
|
||||
<bean id="vendorAdaptor" class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"
|
||||
parent="abstractVendorAdaptor">
|
||||
|
||||
@@ -278,6 +278,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
jpaExecutor.setJpaQuery("from Student s");
|
||||
jpaExecutor.setDeleteAfterPoll(true);
|
||||
jpaExecutor.setDeleteInBatch(true);
|
||||
jpaExecutor.setFlush(true);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
@@ -306,9 +307,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
|
||||
assertTrue(students.size() == 3);
|
||||
|
||||
Long studentCount = waitForDeletes(students);
|
||||
|
||||
assertEquals(Long.valueOf(0), studentCount);
|
||||
assertEquals(Long.valueOf(0), entityManager.createQuery("select count(*) from Student", Long.class).getSingleResult());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation=
|
||||
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation=
|
||||
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd">
|
||||
|
||||
<import resource="classpath:/hibernateJpa-context.xml" />
|
||||
<import resource="classpath:/hibernateJpa-context.xml"/>
|
||||
|
||||
<int:channel id="in"/>
|
||||
<int:channel id="out"/>
|
||||
<int:channel id="in"/>
|
||||
<int:channel id="out"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway
|
||||
id="retrievingGateway"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
<int-jpa:retrieving-outbound-gateway
|
||||
id="retrievingGateway"
|
||||
entity-manager="entityManager"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
first-result-expression="payload"
|
||||
max-results-expression="headers['maxResults']"
|
||||
reply-timeout="100"/>
|
||||
delete-after-poll="true"
|
||||
flush-after-delete="true"
|
||||
reply-timeout="100">
|
||||
<int-jpa:transactional/>
|
||||
</int-jpa:retrieving-outbound-gateway>
|
||||
</beans>
|
||||
|
||||
@@ -16,9 +16,13 @@
|
||||
package org.springframework.integration.jpa.outbound;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.FlushModeType;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -29,6 +33,7 @@ import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.core.SubscribableChannel;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -52,6 +57,9 @@ public class JpaOutboundGatewayIntegrationTests {
|
||||
@Qualifier("out")
|
||||
private SubscribableChannel responseChannel;
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
/**
|
||||
* Sends a message with the payload as a integer representing the start number in the result
|
||||
* set and a header with value maxResults to get the max number of results
|
||||
@@ -63,12 +71,13 @@ public class JpaOutboundGatewayIntegrationTests {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
assertEquals(1, ((List)message.getPayload()).size());
|
||||
assertEquals(2, ((List) message.getPayload()).size());
|
||||
assertEquals(1, entityManager.createQuery("from Student").getResultList().size());
|
||||
}
|
||||
});
|
||||
Message<Integer> message = MessageBuilder
|
||||
.withPayload(1)
|
||||
.setHeader("maxResults", "1")
|
||||
.setHeader("maxResults", "10")
|
||||
.build();
|
||||
requestChannel.send(message);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.jpa.test;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @since 3.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class TestHibernateJpaDialect extends HibernateJpaDialect {
|
||||
|
||||
@Override
|
||||
public Object prepareTransaction(EntityManager entityManager, boolean readOnly, String name) throws PersistenceException {
|
||||
entityManager.setFlushMode(FlushModeType.COMMIT);
|
||||
return super.prepareTransaction(entityManager, readOnly, name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
<property name="dataSource" ref="dataSource" />
|
||||
<property name="persistenceUnitName" value="persistenceUnit" />
|
||||
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
|
||||
<!-- <property name="jpaProperties" ref="jpaProperties" /> -->
|
||||
<property name="jpaDialect" ref="jpaDialect"/>
|
||||
</bean>
|
||||
|
||||
<bean id="abstractVendorAdaptor" abstract="true">
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
|
||||
<import resource="classpath:/commonJpa-context.xml" />
|
||||
|
||||
<bean id="jpaDialect" class="org.springframework.integration.jpa.test.TestHibernateJpaDialect"/>
|
||||
|
||||
<bean id="vendorAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
|
||||
parent="abstractVendorAdaptor">
|
||||
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect"/>
|
||||
<property name="showSql" value="true"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -411,7 +411,8 @@
|
||||
max-number-of-results="" ]]><co id="inboundAdapterMaxResults"/><![CDATA[
|
||||
max-results="" ]]><co id="inboundAdapterMaxResults2"/><![CDATA[
|
||||
max-results-expression="" ]]><co id="inboundAdapterMaxResultsExpression"/><![CDATA[
|
||||
delete-after-poll="true"> ]]><co id="inboundAdapterDeleteAfterPoll"/><![CDATA[
|
||||
delete-after-poll="true" ]]><co id="inboundAdapterDeleteAfterPoll"/><![CDATA[
|
||||
flush-after-delete="true"> ]]><co id="inboundAdapterFlushAfterDelete"/><![CDATA[
|
||||
<int:poller fixed-rate="2000" >
|
||||
<int:transactional propagation="REQUIRED" transaction-manager="transactionManager"/>
|
||||
</int:poller>
|
||||
@@ -484,6 +485,14 @@
|
||||
<emphasis>java.lang.IllegalArgumentException: Removing
|
||||
a detached instance ...</emphasis>
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="inboundAdapterFlushAfterDelete">
|
||||
<para>
|
||||
Set this value to <code>true</code> if you want
|
||||
to the persistence context immediately after deleting received entities
|
||||
and if you don't want rely on the<interfacename>EntityManager</interfacename>'s flushMode.
|
||||
The default value is set to <code>false</code>.
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
<section id="jpaInboundChannelAdapterParameters">
|
||||
@@ -852,6 +861,9 @@ public class Student {
|
||||
order="" ]]><co id="outAdaptOrder"/><![CDATA[
|
||||
parameter-source-factory="" ]]><co id="outAdaptParamSourceFact"/><![CDATA[
|
||||
persist-mode="MERGE" ]]><co id="outAdaptPersistMode"/><![CDATA[
|
||||
flush="true" ]]><co id="outAdaptFlush"/><![CDATA[
|
||||
flush-size="10" ]]><co id="outAdaptFlushSize"/><![CDATA[
|
||||
clear-on-flush="true" ]]><co id="outAdaptclearOnFlash"/><![CDATA[
|
||||
use-payload-as-parameter-source="true" ]]><co id="outAdaptUserPayloadAsParamSrc"/><![CDATA[
|
||||
<int:poller/>
|
||||
<int-jpa:transactional/> ]]><co id="outAdaptTransactional"/><![CDATA[
|
||||
@@ -948,6 +960,38 @@ public class Student {
|
||||
<emphasis>NULL</emphasis> values returned by the iterator are ignored.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="outAdaptFlush">
|
||||
<para>
|
||||
Set this value to <code>true</code> if you want
|
||||
to flush the persistence context immediately after persist, merge or delete operations
|
||||
and don't want to rely on the <interfacename>EntityManager</interfacename>'s flushMode.
|
||||
The default value is set to <code>false</code>. Applies only if the <code>flush-size</code>
|
||||
attribute isn't specified. If this attribute is set to <code>true</code>,
|
||||
then <code>flush-size</code> will be implicitly set to <code>1</code>, if it wasn't configured to any other value.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="outAdaptFlushSize">
|
||||
<para>
|
||||
Set this attribute to a value greater than '0' if you want
|
||||
to flush the persistence context immediately after persist, merge or delete operations
|
||||
and don't want to rely on the <interfacename>EntityManager</interfacename>'s flushMode.
|
||||
The default value is set to <code>0</code> which means 'no flush'.
|
||||
This attribute is geared towards messages with <interfacename>Iterable</interfacename> payloads.
|
||||
For instance, if <code>flush-size</code> is set to <code>3</code>,
|
||||
then <code>entityManager.flush()</code> is called after every third entity.
|
||||
Furthermore, <code>entityManager.flush()</code> will be called once more after the entire loop.
|
||||
There is no reason to configure the <code>flush</code>
|
||||
attribute, if the 'flush-size' attribute is specified with a value greater than '0'.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="outAdaptclearOnFlash">
|
||||
<para>
|
||||
Set this value to 'true' if you want
|
||||
to clear persistence context immediately after each flush operation.
|
||||
The attribute's value is applied only if the <code>flush</code> attribute is set to
|
||||
<code>true</code> or if the <code>flush-size</code> attribute is set to a value greater than <code>0</code>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="outAdaptUserPayloadAsParamSrc">
|
||||
<para>
|
||||
If set to true, the payload of the Message will be used as a source for providing parameters.
|
||||
|
||||
@@ -366,7 +366,7 @@
|
||||
</para>
|
||||
</section>
|
||||
<section id="3.0-jpa-persist-merge-collections">
|
||||
<title>JPA Support Improvements</title>
|
||||
<title>JPA Support: Improvements</title>
|
||||
<para>
|
||||
Payloads to <emphasis>persist</emphasis> or
|
||||
<emphasis>merge</emphasis> can now be of type
|
||||
@@ -380,6 +380,11 @@
|
||||
<interfacename>EntityManager</interfacename>.
|
||||
<emphasis>NULL</emphasis> values returned by the iterator are ignored.
|
||||
</para>
|
||||
<para>
|
||||
The JPA adapters now have additional attributes to optionally 'flush' and 'clear'
|
||||
entities from the associated persistence context after performing persistence operations.
|
||||
</para>
|
||||
<para>For more information see <xref linkend="jpa"/>.</para>
|
||||
</section>
|
||||
<section id="3.0-json-transformers">
|
||||
<title>Jackson Support (JSON)</title>
|
||||
|
||||
Reference in New Issue
Block a user