Я использую Hibernate 4.2.5 и Spring 3.2.4 с аннотациями JPA.Параллелизм с JPA, Hibernate и Spring
У меня есть следующий метод внутри службы
@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 это просто autowired 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
по методу не поможет, очевидно)
EDIT: мой ApplicationContext:
<?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
}
Я просто понял, что я не использую управление версиями/оптимистичная блокировка, но я не уверен, влияет ли это на эту проблему.
, пожалуйста, укажите конфигурацию пружины. –
Почему вы сохраняете сущность, которая уже существует? Что ты пытаешься сделать? –
«.save» JPADao на самом деле является «saveOrUpdate», насколько я знаю. В приложении я пытаюсь сохранить дату входа в систему. Кроме того, в документе говорится: «Использовать возвращаемый экземпляр для дальнейших операций, поскольку операция сохранения может полностью изменить экземпляр объекта». Я добавил конфигурацию пружины. – incaseoftrouble