Commit f6507fc6 authored by LAVENIER's avatar LAVENIER
Browse files

[enh] Oracle: force lock for update, with NOWAIT (add config option...

[enh] Oracle: force lock for update, with NOWAIT (add config option 'javax.persistence.lock.timeout')
[fix] Fix unique key error, when saving FISHING_AREA (fix IMAGINE-529)
parent cb2177bf
......@@ -893,6 +893,10 @@ public class SumarisConfiguration extends PropertyPlaceholderConfigurer {
return applicationConfig.getOption(SumarisConfigurationOption.SEQUENCE_SUFFIX.getKey());
}
public Integer getLockTimeout() {
return applicationConfig.getOptionAsInt(SumarisConfigurationOption.LOCK_TIMEOUT.getKey());
}
public String getCsvSeparator() {
return applicationConfig.getOption(SumarisConfigurationOption.CSV_SEPARATOR.getKey());
}
......
......@@ -557,6 +557,12 @@ public enum SumarisConfigurationOption implements ConfigOptionDef {
"_SEQ",
String.class),
LOCK_TIMEOUT(
"javax.persistence.lock.timeout",
n("sumaris.config.option.javax.persistence.lock.timeout.description"),
"0",
Integer.class),
ENABLE_TECHNICAL_TABLES_UPDATE(
"sumaris.persistence.technicalTables.update",
n("sumaris.config.option.persistence.technicalTables.update.description"),
......
......@@ -23,6 +23,7 @@ package net.sumaris.core.dao.technical.jpa;
*/
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.querydsl.jpa.impl.JPAQuery;
import lombok.extern.slf4j.Slf4j;
import net.sumaris.core.config.SumarisConfiguration;
......@@ -37,6 +38,7 @@ import net.sumaris.core.exception.SumarisTechnicalException;
import net.sumaris.core.util.Beans;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
......@@ -54,6 +56,7 @@ import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.lang.Nullable;
import javax.annotation.PostConstruct;
import javax.persistence.*;
import javax.persistence.criteria.*;
import javax.sql.DataSource;
......@@ -76,7 +79,8 @@ public abstract class SumarisJpaRepositoryImpl<E extends IEntity<ID>, ID extends
private boolean debugEntityLoad = false;
private boolean checkUpdateDate = true;
private boolean lockForUpdate = false;
private boolean enablePageTotalElement = false;
private LockModeType lockForUpdateMode = LockModeType.PESSIMISTIC_WRITE;
private Map<String, Object> lockForUpdateProperties = null;
private EntityManager entityManager;
......@@ -101,6 +105,12 @@ public abstract class SumarisJpaRepositoryImpl<E extends IEntity<ID>, ID extends
this.entityManager = entityManager;
}
@PostConstruct
protected void init() {
// Init lock timeout
lockForUpdateProperties = ImmutableMap.of("javax.persistence.lock.timeout", configuration.getLockTimeout());
}
public boolean isCheckUpdateDate() {
return checkUpdateDate;
}
......@@ -117,6 +127,14 @@ public abstract class SumarisJpaRepositoryImpl<E extends IEntity<ID>, ID extends
this.lockForUpdate = lockForUpdate;
}
public LockModeType getLockForUpdateMode() {
return lockForUpdateMode;
}
public void setLockForUpdateMode(LockModeType lockForUpdateMode) {
this.lockForUpdateMode = lockForUpdateMode;
}
public SumarisConfiguration getConfig() {
return configuration;
}
......@@ -331,7 +349,21 @@ public abstract class SumarisJpaRepositoryImpl<E extends IEntity<ID>, ID extends
*/
@SuppressWarnings("unchecked")
protected <C> C find(Class<C> clazz, Serializable id) {
return this.entityManager.find(clazz, id);
return this.entityManager.find(clazz, id, LockModeType.OPTIMISTIC);
}
/**
* <p>find.</p>
*
* @param clazz a {@link Class} object.
* @param id a {@link Serializable} object.
* @param lockModeType a {@link LockModeType} object.
* @param <C> a C object.
* @return a C object.
*/
@SuppressWarnings("unchecked")
protected <C> C find(Class<C> clazz, Serializable id, LockModeType lockModeType) {
return this.entityManager.find(clazz, id, lockModeType);
}
/**
......@@ -422,19 +454,27 @@ public abstract class SumarisJpaRepositoryImpl<E extends IEntity<ID>, ID extends
}
protected void lockForUpdate(IEntity<?> entity) {
lockForUpdate(entity, LockModeType.PESSIMISTIC_WRITE);
lockForUpdate(entity, (LockModeType)null, (Map)null);
}
protected void lockForUpdate(IEntity<?> entity, LockModeType modeType) {
lockForUpdate(entity, modeType, (Map)null);
}
protected void lockForUpdate(IEntity<?> entity, LockModeType modeType, Map<String, Object> properties) {
modeType = modeType != null ? modeType : getLockForUpdateMode();
properties = properties != null ? properties : lockForUpdateProperties;
// Lock entityName
try {
entityManager.lock(entity, modeType);
entityManager.lock(entity, modeType, properties);
} catch (LockTimeoutException e) {
throw new DataLockedException(I18n.t("sumaris.persistence.error.locked",
getTableName(entity.getClass().getSimpleName()), entity.getId()), e);
}
}
protected String getTableName(String entityName) {
return I18n.t("sumaris.persistence.table." + entityName.substring(0, 1).toLowerCase() + entityName.substring(1));
}
......
......@@ -237,7 +237,8 @@ public abstract class DataRepositoryImpl<E extends IDataEntity<Integer>, V exten
else {
entity.setQualificationDate(newUpdateDate);
}
// Apply a find, because can return a null value (e.g. if id is not in the DB instance)
// Apply a find (and NOT a getReference)
// because can return a null value (e.g. if id is not in the DB instance)
entity.setQualityFlag(find(QualityFlag.class, qualityFlagId));
// TODO UNVALIDATION PROCESS HERE
......
......@@ -72,6 +72,8 @@ public class FishingAreaRepositoryImpl
this.config = config;
this.locationRepository = locationRepository;
this.referentialDao = referentialDao;
setCheckUpdateDate(false);
setLockForUpdate(false);
}
@Override
......@@ -174,13 +176,17 @@ public class FishingAreaRepositoryImpl
// Save
sources.forEach(fishingArea -> {
save(fishingArea);
existingIds.remove(fishingArea.getId());
boolean exists = fishingArea.getId() != null && existingIds.remove(fishingArea.getId());
// Reset the id, because a fishingArea could have been deleted by changes on trip.metiers (fix IMAGINE-436)
if (!exists) fishingArea.setId(null);
});
// Delete remaining objects
// Delete remaining objects (BEFORE to save, because of unique key)
existingIds.forEach(this::deleteById);
// Save
sources.forEach(this::save);
return sources;
}
}
......@@ -86,7 +86,8 @@ public class OperationGroupRepositoryImpl
protected OperationGroupRepositoryImpl(EntityManager entityManager) {
super(Operation.class, OperationGroupVO.class, entityManager);
setLockForUpdate(true);
setLockForUpdate(false);
setCheckUpdateDate(false);
}
@Override
......
......@@ -39,7 +39,6 @@ import java.util.List;
@FieldNameConstants
@Entity
@Table(name = "operation")
@Cacheable
@NamedQueries({
@NamedQuery(name = "Operation.updateUndefinedOperationDates",
query = "UPDATE Operation o " +
......
......@@ -68,6 +68,7 @@ import org.springframework.transaction.event.TransactionalEventListener;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
......@@ -95,7 +96,7 @@ public class ConfigurationServiceImpl implements ConfigurationService {
private Version dbVersion;
private final List<ConfigurationEventListener> listeners = Lists.newArrayList();
private final List<ConfigurationEventListener> listeners = new CopyOnWriteArrayList<>();
@Autowired
public ConfigurationServiceImpl(SumarisConfiguration configuration) {
......@@ -407,7 +408,7 @@ public class ConfigurationServiceImpl implements ConfigurationService {
publisher.publishEvent(event);
// Emit to registered listeners
for(ConfigurationEventListener listener: listeners) {
for (ConfigurationEventListener listener: listeners) {
try {
listener.onUpdated(event);
} catch (Throwable t) {
......
......@@ -111,6 +111,7 @@ sumaris.persistence.table.grouping=GROUPING
sumaris.persistence.table.groupingClassification=GROUPING_CLASSIFICATION
sumaris.persistence.table.groupingLevel=GROUPING_LEVEL
sumaris.persistence.table.imageAttachment=IMAGE_ATTACHMENT
sumaris.persistence.table.landing=LANDING
sumaris.persistence.table.location=LOCATION
sumaris.persistence.table.locationLevel=LOCATION_LEVEL
sumaris.persistence.table.matrix=MATRIX
......
......@@ -50,6 +50,7 @@ spring.jpa.properties.hibernate.dialect=${spring.jpa.database-platform}
sumaris.extraction.query.timeout=300000
spring.jpa.properties.javax.persistence.query.timeout=30000
spring.jpa.properties.org.hibernate.timeout=30
spring.jpa.properties.javax.persistence.lock.timeout=0
# Schema management / Liquibase
spring.jpa.properties.hibernate.hbm2ddl.auto=none
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment