0

我正在使用带有 JPA 注释的 Hibernate 4.2.5 和 Spring 3.2.4。

我在服务中有以下方法

@Override
@Transactional
public Foo getFoo(String fooName) {
    Foo foo = fooDao.findByName(fooName);
    if (foo == null)
        return null;
    foo.setBar(new Date());
    return fooDao.save(foo);
}

fooDao 只是一个自动装配的interface FooDao extends JpaRepository<Foo, Long>

如果现在多个线程访问 getFoo 方法,则会发生以下情况:

Thread 1: Foo foo1 = getFoo("name1");
Thread 2: Foo foo2 = getFoo("name2");

但是foo1.getName() == foo2.getName() == "name2"(或“name1”)。这可能是线程在 save 和select last_update_id

我尝试添加事务隔离,但这也无济于事。我怎样才能防止这种情况?(synchronized显然,该方法也无济于事)

编辑:我的应用程序上下文:

<?xml version="1.0" encoding="UTF-8"?>
<beans ...">
    <!-- ======== BoneCP ======== -->
    <bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
        <!-- ... -->
    </bean>
    <!-- ======== SPRING ======== -->
    <context:annotation-config />
    <context:component-scan base-package="foo.bar" />
    <jpa:repositories base-package="foo.bar" />
    <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <property name="targetDataSource">
            <ref local="mainDataSource" />
        </property>
    </bean>
    <!-- ======== HIBERNATE / JPA ======== -->
    <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="generateDdl" value="false" />
        <property name="showSql" value="false" />
        <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
        <property name="database" value="MYSQL" />
    </bean>
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="de.cmr.cmair.server.db.model" />
        <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
        <property name="persistenceUnitName" value="persistenceUnit" />
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">validate</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.use_sql_comments">true</prop>
                <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
                <prop key="hibernate.current_session_context_class">jta</prop>
            </props>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />
    <!-- the transactional advice -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="allDaoMethods" expression="execution(* de.cmr.cmair.server.db.service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="allDaoMethods" />
    </aop:config>
</beans>

Foo 类:

@Entity
@Table(name = "FOO")
public class Foo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID", unique = true, nullable = false)
    private long id;
    @Column(name = "BAR")
    private Date bar;
    @Column(name = "NAME", length = 225)
    private String name;

    // ... setters / getters
}

我刚刚意识到我不使用版本控制/乐观锁定,但我不确定这是否对这个问题有任何影响。

4

1 回答 1

0

最好的解决方案是乐观锁定,或者当用户尝试编辑记录时应该锁定记录。

于 2013-10-26T03:56:37.993 回答