交易/ spring事务传播是否解决了这个并发问题? [英] Would transactions/spring Transaction propagation solve this concurrency issue?
问题描述
如果可能,我有关于Spring中的事务的几个问题。
让我们假设我有这个DAO类:
public class MyDAO {
/ *
*验证DB中的某条记录是否包含名为publishFlag的特定列中的True
* /
@Transactional
public bloolean isBeingPublished(Long recordID){
...
}
/ **
*将记录的publishFlag列设置为true,表示正在发布
* /
@Transactional
public boolean setBeingPublished(Long recordID){
...
}
}
而下面的类使用它:
public class MyClass {
@Autowired
MyDAO dao;
public void publishRecords(List< Long> ids){
(Long id:ids){
if(!dao.isBeingPublished
dao.setBeingPublished(id);
//做某事发布记录
}
}
}
}
我的问题是:
-
!dao.isBeingPublished(id)
和dao.setBeingPublished(id)
在同一个事务中执行, ? -
第二个问题关于并发性,可以创建多个
MyClass
实例, c $ c> publishRecord 方法,因此对!dao.isBeingPublished(id)
的两个并发调用可能都给出相同的结果,记录发布两次!
我会考虑使publishRecords
同步,但应用程序可能部署在多个服务器上,无用的,因此我的问题关于交易,因为数据库是部署在这些服务器上的应用程序之间的唯一共享资源。
什么将是我的问题的解决方案?我阅读关于spring的事务传播,发现 REQUIRES_NEW
会创建一个新的事务,即使一个正在执行,但仍然,我只是看不到这将是
很少需要考虑的事情,DAO是关注单个实体的操作,而服务是关注一个或多个实体的操作,所以事务应该放在服务层,这样你可以重用DAO的操作没有任何事务,但让服务决定何时开始和结束事务
- 不是在单个事务中,而是两个单独的事务。
- 这是当前设计的问题并发问题,请参阅以下建议。
strong>
public interface MyClass {
public void publishRecords(List< Long> ids);
}
实施
@Service
@Transactional(readOnly = false)
class DefaultMyClass implements MyClass {
@Autowired
MyDAO dao;
//单个事务
@Override
public void publishRecords(List< Long> ids){
(Long id:ids){
if (!dao.isBeingPublished(id)){
dao.setBeingPublished(id);
//做某事发布记录
}
}
}
}
DAO
class MyDAO {
public bloolean isBeingPublished(Long recordID){
// bigbang
}
public boolean setBeingPublished(Long recordID){
// bigbang
}
}
使用上述设计,两个问题都解决了。 >
I have a couple of questions about Transactions in Spring if you may. Let's suppose i have this DAO class :
public class MyDAO {
/**
* verifies if a certain record in DB contains 'True' in a certain Column named publishFlag
*/
@Transactional
public bloolean isBeingPublished(Long recordID){
...
}
/**
* sets the record's publishFlag column to true indicating that it's being published
*/
@Transactional
public boolean setBeingPublished(Long recordID){
...
}
}
And the following class using it :
public class MyClass {
@Autowired
MyDAO dao;
public void publishRecords(List<Long> ids){
for(Long id : ids){
if(!dao.isBeingPublished(id)){
dao.setBeingPublished(id);
//do something to publish the record
}
}
}
}
My questions are :
First of all, will the
!dao.isBeingPublished(id)
anddao.setBeingPublished(id)
be executed in the same transaction or in separate ones?Second question's about concurrency, Multiple
MyClass
instances can be created and concurrent calls to thepublishRecord
method can occur, so two concurrent calls to!dao.isBeingPublished(id)
might both give the same result and thus making the record published twice! I would consider making thepublishRecords
synchronized but the application may be deployed on multiple servers which renders the synchronized declaration useless, hence my question about transactions since the database is the only shared resource between the apps deployed on those servers.
What would be the solution to my problem exactly? I read about spring's transaction propagation and found out that REQUIRES_NEW
would create a new transaction even if one is currently being executed, but still, I just can't see how that's going to be a solution to my problem.
Thank you in advance for your help.
Few things need consider, DAO is focus on operation on single entity, and service is focus on operation of one or more entities, so the transaction should put on service layer, so you can reuse DAO's operation without any transaction, but let service to decide when start and end transaction
- It is not in single transaction, but two separate transaction.
- That is the problem concurrency issue with your current design, see the following suggestion.
Interface
public interface MyClass {
public void publishRecords(List<Long> ids);
}
Implementation
@Service
@Transactional(readOnly = false)
class DefaultMyClass implements MyClass {
@Autowired
MyDAO dao;
// single transaction
@Override
public void publishRecords(List<Long> ids) {
for(Long id : ids){
if(!dao.isBeingPublished(id)){
dao.setBeingPublished(id);
//do something to publish the record
}
}
}
}
DAO
class MyDAO {
public bloolean isBeingPublished(Long recordID){
// bigbang
}
public boolean setBeingPublished(Long recordID){
// bigbang
}
}
Using the above design, both problems are being resolved.
这篇关于交易/ spring事务传播是否解决了这个并发问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!