我正在使用带有 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
}
我刚刚意识到我不使用版本控制/乐观锁定,但我不确定这是否对这个问题有任何影响。