여러 스레드에서 여러 서버 노드에서 실행되는 가져 오기 서비스에서 여러 개체 생성을 방지하려고합니다. 저의 유일한 기회는 모든 것을 다시 모으는 유일한 단일 지점 인 데이터베이스에 고유 한 제한 조건을 사용하는 것 같습니다.이론적으로 사용할 수 있지만 중첩 된 트랜잭션 중첩 된 트랜잭션
이제 내 서비스가 개체 생성을 시도하고 DataIntegrityViolationException을 수신합니다. 그 후에 다른 프로세스에 의해 이미 생성 된 객체는 쿼리되고 사용되어야한다. 여태까지는 그런대로 잘됐다.
하지만이 개체에 대한 쿼리는 현재 트랜잭션이 중단되었다는 오류 메시지 SQL state [25P02]; error code [0]
과 함께 Postgres에 의해 거부됩니다. 짧은 내 코드에서
은 다음과 같습니다
@Transactional
public void connectToCollections(Product product) {
for (Collection coll : product.getCollections()) {
Set<CollectionMaster> collCandidates = new HashSet<CollectionMaster>();
CollectionMaster oldMaster = coll.getMaster();
newMaster = collectionMasterRepository.findByTitleAndSubtitle(product, coll);
if (newMaster == null) {
newMaster = createNewMaster(product,coll);
if(newMaster == null) {
// Maybe already created by another process; search again!
newMaster = collectionMasterRepository.findByTitleAndSubtitle(product, coll);
}
}
// Do something with newMaster
}
}
private CollectionMaster createNewMaster(Product product, Collection coll) {
CollectionMaster oldMaster = coll.getMaster();
CollectionMaster newMaster = null;
oldMaster.setCreatedBy(product.getCreatedBy());
oldMaster.setLastModifiedBy(product.getCreatedBy());
try {
newMaster = create(oldMaster);
}
catch(DataIntegrityViolationException e) {
return null;
}
coll.setMaster(newMaster);
return newMaster;
}
@Transactional(propagation=Propagation.NESTED)
public CollectionMaster create(CollectionMaster collMaster) {
CollectionMaster result = null;
result = collectionMasterRepository.saveAndFlush(collMaster);
return result;
}
진입 점은 connectToCollections입니다. CollectionMaster가 조회되면 발견되지 않으면 작성하려고 시도하고, 실패하면 다시 조회합니다. NESTED (또는 REQUIRES_NEW)와 같은 전파에 대한 @Transactional 속성은 무시되고 데이터베이스에 저장 점이 설정되거나 사용되지 않는 것으로 보입니다. 일반적으로 사용 된 기술 스택이 그렇게 할 수 있어야합니다. 내가 뭘 놓치고 있니?
pom.xml 파일의 관련 부분은 다음과 같습니다
<hibernate.version>4.1.7.Final</hibernate.version>
<postgresql.version>9.3-1102-jdbc41</postgresql.version>
<commons-dbcp2.version>2.0.1</commons-dbcp2.version>
<spring.version>3.2.9.RELEASE</spring.version>
<spring-data-jpa.version>1.6.0.RELEASE</spring-data-jpa.version>
<aspectj.version>1.8.0</aspectj.version>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${commons-dbcp2.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
<exclusions>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
</exclusion>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
<exclusions>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
<exclusion>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>transaction-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.version}</version>
</dependency>
그리고
마침내 Spring 애플리케이션 컨텍스트의 관련 부분 :<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driverClassName}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="${database.dialect}" />
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="javax.persistence.validation.factory" value-ref="validator" />
<entry key="hibernate.show_sql" value="${hibernate.show_sql}"/>
<entry key="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl}"/>
<entry key="org.hibernate.envers.track_entities_changed_in_revision" value="true"/>
</map>
</property>
<property name="persistenceUnitName" value="mvb.vlx.model" />
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="nestedTransactionAllowed" value="true"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj" />
Java 버전 jdk1.7.0_40
입니다
개인 트랜잭션의 @Transactional은 우리가 사용하는 aspectj와 작동합니다. 명시 적으로 트랜잭션 관리자를 autowire하고 트랜잭션을 수동으로 시작하면 HibernateDialect를 구성하더라도 "JPA dialect는 중첩 트랜잭션을 지원하지 않습니다"예외가 발생합니다. 그것은 이상한 현상으로 남아 ... –
끝날 때까지 나는 중첩 된 또는 "정말로"새로운 거래를 만들 수 없었다. 그러나 RetryTemplate이 트릭을했습니다! 감사. –