2016-03-12 56 views
0

在我的項目中,我使用基於AspectJ的「高級映射」模式使用Spring Data Neo4j(3.4.2.RELEASE),使用嵌入式數據庫。 我也使用基於AspectJ的事務管理通過@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)Spring Data Neo4j:無限期等待RWLock而不發生DeadlockDetectedException

在我的應用程序中遇到死鎖情況下應該發生數據庫的併發讀取/寫入。雖然我沒有收到DeadlockDetectedException,但卻看到一個線程無限期地等待RWLock。不久之後,所有剩餘的線程將在第一個線程上等待並且應用程序停止響應,而不會恢復。其他線程也可能已經獲得了鎖定,但是因爲我看不到我不確定它。

堆棧跟蹤鎖定螺紋:

Thread [Processing-XXX] (Suspended) 
owns: SeasonOfCompetitionRepositoryImpl (id=134) 
waiting for: RWLock (id=174) 
Object.wait(long) line: not available [native method] 
RWLock(Object).wait() line: 502 [local variables unavailable] 
RWLock.acquireWriteLock(Object) line: 388 
LockManagerImpl.getWriteLock(Object, Object) line: 66 
CommunityLockClient.acquireExclusive(Locks$ResourceType, long) line: 116  
LockingStatementOperations.relationshipCreate(KernelStatement, int, long, long) line: 287 
OperationsFacade.relationshipCreate(int, long, long) line: 866 
NodeProxy.createRelationshipTo(Node, RelationshipType) line: 559  
DelegatingGraphDatabase.getOrCreateRelationship(Node, Node, RelationshipType, Direction, Map<String,Object>) line: 298 
Neo4jTemplate.getOrCreateRelationship(Node, Node, RelationshipType, Direction, Map<String,Object>) line: 772  
RelationshipHelper.createSingleRelationship(Node, Node) line: 198 
RelationshipHelper.createAddedRelationships(Node, Set<Node>) line: 154 
RelatedToSingleFieldAccessorFactory$RelatedToSingleFieldAccessor(RelatedToFieldAccessor).createAddedRelationships(Node, Set<Node>) line: 78 
RelatedToSingleFieldAccessorFactory$RelatedToSingleFieldAccessor.setValue(Object, Object, MappingPolicy) line: 68 
NodeEntityState(DefaultEntityState<STATE>).setValue(Neo4jPersistentProperty, Object, MappingPolicy) line: 113 
DetachedEntityState<STATE>.setValue(Neo4jPersistentProperty, Object, MappingPolicy) line: 181 
DetachedEntityState<STATE>.setValue(Field, Object, MappingPolicy) line: 145 
SeasonOfCompetition.season_aroundBody21$advice(SeasonOfCompetition, SeasonOfCompetition, Season, JoinPoint, Neo4jNodeBacking, NodeBacked, Object, AroundClosure, JoinPoint) line: 266 
SeasonOfCompetition.setSeason_aroundBody22(SeasonOfCompetition, Season) line: 108 
SeasonOfCompetition$AjcClosure23.run(Object[]) line: 1 
AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(Object, AroundClosure) line: 66  
AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation() line: 72 
AnnotationTransactionAspect(TransactionAspectSupport).invokeWithinTransaction(Method, Class<?>, InvocationCallback) line: 281 
AnnotationTransactionAspect(AbstractTransactionAspect).ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(Object, AroundClosure, JoinPoint$StaticPart) line: 70  
SeasonOfCompetition.setSeason(Season) line: 95 
SeasonOfCompetitionRepositoryImpl.getOrCreate_aroundBody0(SeasonOfCompetitionRepositoryImpl, Season, Competition) line: 32 
SeasonOfCompetitionRepositoryImpl$AjcClosure1.run(Object[]) line: 1 
AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(Object, AroundClosure) line: 66  
AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation() line: 72 
AnnotationTransactionAspect(TransactionAspectSupport).invokeWithinTransaction(Method, Class<?>, InvocationCallback) line: 281 
AnnotationTransactionAspect(AbstractTransactionAspect).ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(Object, AroundClosure, JoinPoint$StaticPart) line: 70  
SeasonOfCompetitionRepositoryImpl.getOrCreate(Season, Competition) line: 26 

這是應該給定參數創建獨特SeasonOfCompetition個自定義RepositoryExtension部分:

@Override 
@Transactional 
public synchronized SeasonOfCompetition getOrCreate(Season season, Competition competition) 
{ 
    String uri = buildUri(season, competition); 
    SeasonOfCompetition soc = getOrCreateByUri(uri); 
    if(soc.getSeason() == null) 
    { 
     soc.setSeason(season); 
    } 
    if(soc.getCompetition() == null) 
    { 
     soc.setCompetition(competition); 
    } 
    return soc; 
} 

請注意,我已經與@Transactionalsychronized - 這兩個我最初沒有使用,因爲我認爲(但不確定),他們不需要在這裏玩了一下。

這是一個選擇域實體SeasonOfCompetition,其中螺紋卡:

@NodeEntity 
public class SeasonOfCompetition extends UriEntity 
{ 
    @RelatedTo(type = "inSeason", direction = Direction.OUTGOING) 
    private Season season; 

    @Transactional 
    public void setSeason(Season season) 
    { 
     this.season = season; 
    } 
} 

什麼我錯在這裏做什麼?我假設通過SDN訪問圖數據庫是線程安全的,除了使用事務之外,我不需要任何特殊處理。 在這種情況下,如何調試或如何使其拋出DeadlockDetectedException的建議也是受歡迎的。

我以前也有其他併發相關的問題(意味着是唯一的,重複的關係等重複實體),並沒有完全承認,我還需要如何處理這個問題。有關如何爲NodeEntities和Relationships實現線程安全的#getOrCreate的輸入,我們感激不盡。

編輯: 我試圖實現#getOrCreate的MERGE -query基於版本,不使用任何自定義同步通過@cybersam的建議:

@Override 
@Transactional 
@SuppressWarnings("deprecation") 
public T getOrCreateByUri(String uri) 
{ 
    checkArgument(!StringUtils.isEmpty(uri)); 

    Class<T> clazz = getEntityType(); 
    String queryString = "MERGE (n:" + clazz.getSimpleName() + " {uri: {uri}}) RETURN n"; 
    Map<String, Object> parameters = new HashMap<>(); 
    parameters.put("uri", uri); 
    Node node = (Node) template.getGraphDatabase().queryEngine().query(queryString, parameters).single().get("n"); 
    template.postEntityCreation(node, clazz); 
    T result = (T) template.convert(node, clazz); 
    return result.persist(); 
} 

然而,這未能創造出獨特的節點。創建100個線程並對其並行調用的簡單測試失敗,因爲創建了多個節點。 這可能與result.persist()有關,但是如果沒有返回的實體沒有附加到圖表並且缺少一些信息。

回答

1

neo4j documentation包含這樣的警告:

重要

死鎖因使用其它同步的比Neo4j的管理仍可能發生鎖 。由於Neo4j API中的所有操作都是線程安全的,除非另有規定,因此不需要外部同步。其他需要同步的代碼 應該以這樣一種方式同步,即它不會在同步塊中執行任何Neo4j 操作。

getOrCreate(),執行Neo4j操作,目前​​。所以,死鎖可能是由您自己的代碼的Java同步引起的。您將需要重新設計代碼,以避免在執行Neo4j操作時使用Java同步。

+0

但是,Spring Data Neo4j如何適合圖片?這是Neo4j上的一個附加層。如何在那裏實例化獨特的實體? – geld0r

+0

請參閱本文檔的這一部分:neo4j.com/docs/stable/transactions-unique-nodes.html。 – cybersam