2014-11-14 4 views
0

Я использую org.springframework.data.repository.CrudRepository для сохранения моих объектов.Оптимистичная блокировка не работает - без увеличения версии, без исключения

Вот моя сущность:

@Entity 
@Table (name="ThirdClass") 
public abstract class ThirdClassBase 
    extends BaseDomainObject 
    implements Serializable, Cloneable{ 

    /** 
    * Default serialID to prevent warning 
    */ 
    private static final long serialVersionUID = 1L; 

    /* 
    * A T T R I B U T E S 
    */ 
    @Id 
    private String pk; 
    @Version 
    private Integer version; 

    ... 
} 

Вот моя весна-конфигурации:

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:jpa="http://www.springframework.org/schema/data/jpa" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation=" 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.2.xsd 
     http://www.springframework.org/schema/data/jpa 
     http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx.xsd" 
    default-autowire="byName"> 

    <!-- only components from this package can be wired by spring --> 
    <context:component-scan base-package="test.envmuster.*" /> 

    <!-- Directory to scan for repository classes --> 
    <jpa:repositories base-package="test.domain.repository" /> 

    <!-- jdbc.properties => used to put db-connection data to an own property-file --> 
    <bean id="domainPropertyConfigurer" 
     class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
     <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /> 
     <property name="locations"> 
      <list> 
       <value>classpath:jdbc.properties</value> 
      </list> 
     </property> 
    </bean> 

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
     <property name="driverClassName" value="${db.driver}" /> 
     <property name="url" value="${db.url}" /> 
     <property name="username" value="${db.username}" /> 
     <property name="password" value="${db.password}" /> 
    </bean> 

    <tx:annotation-driven transaction-manager="transactionManager"/> 

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" > 
     <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </bean> 

    <bean id="entityManagerFactory" 
     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 

     <property name="dataSource" ref="dataSource" /> 

     <property name="packagesToScan" > 
      <list> 
       <value>test.domain</value> 
      </list> 
     </property> 

     <property name="jpaVendorAdapter"> 
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
       <property name="showSql" value="true" /> 
       <property name="generateDdl" value="true" /> 
      </bean> 
     </property> 

    </bean> 

</beans> 

Тест:

@ContextConfiguration(locations = { "classpath:spring-test-config.xml" }) 
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false) 
@Transactional 
public class OptimisticLockingTest extends AbstractTransactionalTestNGSpringContextTests { 

    @Autowired 
    private ThirdClassRepository thirdRepository; 

    @BeforeClass 
    public void setUpData(){ 
     ThirdClass thirdClass = new ThirdClass(3L); 
     thirdClass.setPk("pk1"); 
     thirdClass.setVersion(30); 
     thirdClass = thirdRepository.save(thirdClass); 
     Assert.assertEquals(thirdClass.getVersion(), new Integer(30)); 
    } 

    @Test 
    public void optimisticLockingCheck(){ 
     ThirdClass thirdClass = thirdRepository.findByPK("pk1"); 
     Assert.assertEquals(thirdClass.getVersion(), new Integer(30)); 
     thirdClass.setValue(5L); 

     thirdClass.setVersion(5); 

     thirdClass = thirdRepository.save(thirdClass); 

    } 

    @AfterClass 
    public void deleteData(){ 
     thirdRepository.delete("pk1"); 
    } 

} 

Тест-результат в консоли:

Hibernate: select thirdclass0_.pk as pk2_8_3_, thirdclass0_.secondClass_pk as secondCl5_8_3_, thirdclass0_.value as value3_8_3_, thirdclass0_.version as version4_8_3_, secondclas1_.pk as pk2_2_0_, secondclas1_.id as id3_2_0_, secondclas1_.thirdClass_pk as thirdCla5_2_0_, secondclas1_.version as version4_2_0_, secondclas1_.wayone_pk as wayone_p6_2_0_, fourthclas2_.SecondClass_pk as SecondCl1_2_5_, fourthclas3_.pk as fourthCl2_3_5_, fourthclas3_.pk as pk2_0_1_, fourthclas3_.prop as prop3_0_1_, fourthclas3_.secondClass_pk as secondCl5_0_1_, fourthclas3_.version as version4_0_1_, thirdclass4_.pk as pk2_8_2_, thirdclass4_.secondClass_pk as secondCl5_8_2_, thirdclass4_.value as value3_8_2_, thirdclass4_.version as version4_8_2_ from ThirdClass thirdclass0_ left outer join SecondClass secondclas1_ on thirdclass0_.secondClass_pk=secondclas1_.pk left outer join SecondClass_FourthClass fourthclas2_ on secondclas1_.pk=fourthclas2_.SecondClass_pk left outer join FourthClass fourthclas3_ on fourthclas2_.fourthClass_pk=fourthclas3_.pk left outer join ThirdClass thirdclass4_ on secondclas1_.thirdClass_pk=thirdclass4_.pk where thirdclass0_.pk=? and thirdclass0_.DTYPE='ThirdClass' 
Hibernate: insert into ThirdClass (secondClass_pk, value, version, DTYPE, pk) values (?, ?, ?, 'ThirdClass', ?) 
Hibernate: select thirdclass0_.pk as pk2_8_3_, thirdclass0_.secondClass_pk as secondCl5_8_3_, thirdclass0_.value as value3_8_3_, thirdclass0_.version as version4_8_3_, secondclas1_.pk as pk2_2_0_, secondclas1_.id as id3_2_0_, secondclas1_.thirdClass_pk as thirdCla5_2_0_, secondclas1_.version as version4_2_0_, secondclas1_.wayone_pk as wayone_p6_2_0_, thirdclass2_.pk as pk2_8_1_, thirdclass2_.secondClass_pk as secondCl5_8_1_, thirdclass2_.value as value3_8_1_, thirdclass2_.version as version4_8_1_, myfirstcla3_.pk as pk2_4_2_, myfirstcla3_.flag as flag3_4_2_, myfirstcla3_.text as text4_4_2_, myfirstcla3_.version as version5_4_2_, myfirstcla3_.myID as myID6_4_2_, myfirstcla3_.property2 as property7_4_2_, myfirstcla3_.property3 as property8_4_2_ from ThirdClass thirdclass0_ left outer join SecondClass secondclas1_ on thirdclass0_.secondClass_pk=secondclas1_.pk left outer join ThirdClass thirdclass2_ on secondclas1_.thirdClass_pk=thirdclass2_.pk left outer join SuperClass myfirstcla3_ on secondclas1_.wayone_pk=myfirstcla3_.pk where thirdclass0_.pk=? and thirdclass0_.DTYPE='ThirdClass' 
Hibernate: update ThirdClass set secondClass_pk=?, value=?, version=? where pk=? and version=? 
Hibernate: select thirdclass0_.pk as pk2_8_3_, thirdclass0_.secondClass_pk as secondCl5_8_3_, thirdclass0_.value as value3_8_3_, thirdclass0_.version as version4_8_3_, secondclas1_.pk as pk2_2_0_, secondclas1_.id as id3_2_0_, secondclas1_.thirdClass_pk as thirdCla5_2_0_, secondclas1_.version as version4_2_0_, secondclas1_.wayone_pk as wayone_p6_2_0_, thirdclass2_.pk as pk2_8_1_, thirdclass2_.secondClass_pk as secondCl5_8_1_, thirdclass2_.value as value3_8_1_, thirdclass2_.version as version4_8_1_, myfirstcla3_.pk as pk2_4_2_, myfirstcla3_.flag as flag3_4_2_, myfirstcla3_.text as text4_4_2_, myfirstcla3_.version as version5_4_2_, myfirstcla3_.myID as myID6_4_2_, myfirstcla3_.property2 as property7_4_2_, myfirstcla3_.property3 as property8_4_2_ from ThirdClass thirdclass0_ left outer join SecondClass secondclas1_ on thirdclass0_.secondClass_pk=secondclas1_.pk left outer join ThirdClass thirdclass2_ on secondclas1_.thirdClass_pk=thirdclass2_.pk left outer join SuperClass myfirstcla3_ on secondclas1_.wayone_pk=myfirstcla3_.pk where thirdclass0_.pk=? and thirdclass0_.DTYPE='ThirdClass' 
Hibernate: delete from ThirdClass_FourthClass where ThirdClass_pk=? 
Hibernate: delete from ThirdClass where pk=? and version=? 
PASSED: optimisticLockingCheck 

Я знаю, что я не должен устанавливать version-property =>, но он не устанавливается автоматически или, по крайней мере, не увеличивается. Если я оставлю его нулевым, он переключится на 0 после первого сохранения ... похоже, что это нормально, но второе сохранение не увеличило его ... поэтому я попытался установить руководство по версии.

Что-то похоже на работу, потому что в консольном выпуске я вижу в инструкции обновления «где pk =? И version =?» => но почему это не исключение? Кажется, что поле версии используется как обычный столбец ...

Пожалуйста, помогите мне, я понятия не имею, что я сделал не так. Заранее большое спасибо. BR

зависимости (на всякий случай):

<dependencies> 
    <dependency> 
     <groupId>org.testng</groupId> 
     <artifactId>testng</artifactId> 
     <scope>test</scope> 
     <version>6.8.7</version> 
     <exclusions> 
      <exclusion> 
       <artifactId>junit</artifactId> 
       <groupId>junit</groupId> 
      </exclusion> 
     </exclusions> 
    </dependency> 
    <dependency> 
     <groupId>com.h2database</groupId> 
     <artifactId>h2</artifactId> 
     <version>1.4.179</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-context</artifactId> 
     <version>4.0.6.RELEASE</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.data</groupId> 
     <artifactId>spring-data-jpa</artifactId> 
     <version>1.6.1.RELEASE</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-test</artifactId> 
     <version>4.0.6.RELEASE</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-entitymanager</artifactId> 
     <version>4.2.8.Final</version> 
    </dependency> 
    <dependency> 
     <groupId>org.hibernate.javax.persistence</groupId> 
     <artifactId>hibernate-jpa-2.0-api</artifactId> 
     <version>1.0.1.Final</version> 
    </dependency> 
    </dependencies> 

Edit: Другой для меня неожиданное поведение ... Я использую CascadeType (REMOVE, MERGE) на OneToOne-отношений. После того, как я добавил аннотацию @Version, она больше не работает. Я сохраняю отношение 2 новых сущностей (1: 1) одним репозиторией. Save-call, но связанное с ним отношение не сохраняется (но не произошло никакого исключения).

+0

Прежде всего, не устанавливайте версию самостоятельно. Во-вторых, в аннотации '@ Version' вы использовали JPA или спящий режим. –

+0

Спасибо за ваш ответ, я использую: javax.persistence.Version – user3227576

+1

Тогда он должен работать, если у вас есть что-то настроенное правильно и на вашем пути к классам. Вам действительно нужно убедиться, что вы не устанавливаете версию yuorself, так как это смущает спящий режим ... Также вы можете проверить версию ПОСЛЕ выполнения тестового метода, поскольку это точка фиксации не после метода сохранения как тогда ничего не случилось. –

ответ

0

Ответ на неопровержимое поведение CascadeType: Добавление @Version, похоже, изменяет поведение сохранения ... потому что, когда я изменил CascadeType.MERGE на CascadeType.PERSIST, он снова работает.

Что-то большее, похоже, меняется путем добавления @Version: я получаю все исключения только после совершения транзакции. Если я удалю @Version, я получаю исключение в методе persist.

+0

Только для информации: на этот вопрос ответили (на мой взгляд, я - вопросник)), см. Этот ответ и комментарии по моим вопросам. – user3227576

Смежные вопросы