当前位置: 首页 > 面试题库 >

Spring,JPA和Hibernate-如何在没有并发问题的情况下增加计数器

锺离俊雄
2023-03-14
问题内容

我正在使用Spring和JPA / Hibernate玩耍,我对在表中增加计数器的正确方法有些困惑。

我的REST API需要根据用户操作来增加和减少数据库中的某些值(在示例中,在下面的示例中,喜欢或不喜欢标签会使计数器在标签表中增加或减少1)。

tagRepositoryJpaRepository(Spring-data),并且我已经像这样配置了交易

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>

@Controller
public class TestController {

    @Autowired
    TagService tagService

    public void increaseTag() {
        tagService.increaseTagcount();
    }
    public void decreaseTag() {
        tagService.decreaseTagcount();

    }
}

@Transactional
@Service
public class TagServiceImpl implements TagService {


    public void decreaseTagcount() {
        Tag tag = tagRepository.findOne(tagId);
        decrement(tag)
    }

    public void increaseTagcount() {
        Tag tag = tagRepository.findOne(tagId);
        increment(tag)
    }

    private void increment(Tag tag) {
        tag.setCount(tag.getCount() + 1); 
        Thread.sleep(20000);
        tagRepository.save(tag);
    }

    private void decrement(Tag tag) {
        tag.setCount(tag.getCount() - 1); 
        tagRepository.save(tag);
    }
}

如您所见,我故意在增加20秒的睡眠.save()时间之后才能够测试并发方案。

初始标签计数器= 10;

1)用户调用crementTag,代码进入hibernate状态,因此实体的值= 11,而数据库中的值仍为10

2)用户调用reduceTag并遍历所有代码。值是数据库现在= 9

3)睡眠完成,并使用计数为11的实体命中.save,然后命中.save()

当我检查数据库时,该标记的值现在等于11。实际上(至少我想实现的目标)等于10。

这是正常现象吗?还是@Transactional注释不做是工作?


问题答案:

最简单的解决方案是将并发委托给您的数据库,并且仅依赖于当前修改的行上的数据库隔离级别锁:

增量就这么简单:

UPDATE Tag t set t.count = t.count + 1 WHERE t.id = :id;

减量查询为:

UPDATE Tag t set t.count = t.count - 1 WHERE t.id = :id;

UPDATE查询会锁定已修改的行,以防止其他事务在当前事务提交之前(只要您不使用READ_UNCOMMITTED)修改同一行。



 类似资料:
  • 我正在玩Spring和JPA/Hibernate,我对在表中增加计数器的正确方法有点困惑。 我的REST API需要根据用户操作增加或减少数据库中的一些值(在下面的例子中,喜欢或不喜欢一个标记将使标记表中的计数器增加或减少1) 是一个JpaRepository(Spring数据),我这样配置了事务 正如您所看到的,我在以测试并发场景。 初始标签计数器= 10; 1) 用户调用increaseTag

  • 我有一个现有的spring 4项目(mvc、jdbc等),我试图将其移植到spring boot,但我做不到(许多依赖项存在问题,没有人能解释我是如何做到这一点的)。但现在我只想在现有项目中使用Spring数据JPA。这是pom的一个主要依赖项: 我使用EntityManagerFactorybean(在所有示例中都使用)完成了现有配置。数据库配置: 用于测试的Derby数据库。但主要数据库类型是

  • 问题内容: 我正在尝试设置spring xml配置,而不必创建进一步的。但是,即使我将数据库属性包括在 spring.xml: 我在这里想念什么? 问题答案: 在entityManagerFactory bean定义中指定“ packagesToScan”和“ persistenceUnitName”属性。 请注意,这适用于Spring版本> 3.1

  • 我尝试在bean部分中使用环境: 但环境中只有系统属性 所以问题是如何从application.yml加载配置,以及如何以这样的函数式实现@ConfigurationProperties的模拟? 注释、和开始工作。但是注释仅存在于依赖项中,而yml解析类仅存在于中。 在包含依赖项并将添加到beans部分之后,注释开始工作,但也未包含来自application.yml的配置。所以我增加了这一节: 到

  • 问题内容: 示例问题: 实体: 用户包含姓名和朋友列表(用户参考) 博客文章包含标题,内容,日期和作者(用户) 需求: 我想要一个显示标题的页面以及指向用户朋友的最近10篇博客的链接。我还希望能够通过较旧的条目继续进行分页。 SQL解决方案: 因此在sql land中,它将类似于: 我能想到的GAE解决方案是: 加载用户,循环浏览好友列表并加载其最新博客帖子。最后合并所有博客文章以查找最新的10个

  • 问题内容: 我想在Python中实现自定义列表类作为的子类。为了获得所有列表操作的完全类型兼容性,我需要从基类中重写的最少方法集是什么? 这个问题表明至少需要重写。从进一步的研究,也和是必需的。所以我有这段代码: 下列语句即使没有覆盖方法也可以按需工作: 这些语句仅与上述类定义中的覆盖方法一起使用: 我唯一不知道如何实现的是使扩展切片返回正确的类型: 我需要在类定义中添加些什么才能获得类型? 另外