乐观锁定不起作用 - 没有版本增量,也没有例外

时间:2014-11-14 09:14:40

标签: java spring hibernate optimistic-locking

我正在使用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;

    ...
}

这是我的spring-config:

 <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 =&gt;但它不是自动设置的,或者至少不会增加。如果我把它保留为null,它会在第一次保存后切换到0 ......这似乎没问题,但是第二次保存并没有增加它...所以我试着设置版本手册。

有些东西似乎有效,因为在控制台输出中,我在更新语句中看到&#34;其中pk =?和版本=?&#34; =&GT;但为什么没有例外抛出?似乎版本字段的使用方式与普通列一样......

请帮助我,我不知道我做错了什么。非常感谢提前。 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>

编辑: 另一个对我意外的行为...我在OneToOne-Relations上使用CascadeType(REMOVE,MERGE)。在我添加@Version注释后,它不再起作用了。我通过一个repository.save保存2个新实体(1:1)关系 - 调用但未保存关联关系(但没有发生异常)。

1 个答案:

答案 0 :(得分:0)

回答CascadeType的未预料到的行为: 添加@Version似乎改变了保存行为......因为当我将CascadeType.MERGE更改为CascadeType.PERSIST时,它再次起作用。

通过添加@Version似乎更改了一些:我只在事务提交后才收到所有异常。如果我删除了@Version,我会在persist方法中收到异常。