毫不保留的说,我们正处在一个充满并发计算的世界里。为了保证业务数据的一致性状态不遭受破坏,开发者通常需要对潜在的并发以及异常场景做出估量并采取适当的原子性保护。与此同时,几乎所有主流的编程语言都提供了良好的并发框架支持,例如,Java 中的 concurrent 包就提供了全面的锁特性实现。借由这些能力,我们很容易在单进程应用中解决原子性方面的问题。但是,微服务架构让应用程序处理并发原子性问题变得更加复杂,这是由分布式系统的复杂性所决定的。尤其是对于实例(进程)内施加的锁机制无法解决分布式的问题。如下图所示:
对于 MongoDB 来说,更多的应用实践倾向于利用单文档事务性来解决原子性问题,当然,你也可以使用高版本中的多文档事务实现,但缺点是必须接受多文档事务所带来的性能损失。而关于MongoDB 的文档级原子性,尽管大多数人已经知道这一点,但在一些真实的项目案例中,仍然可以发现各种考虑不周的情形。下面,以案例来说明此类问题。案例一 为了能了解网站上在售课程的受欢迎程度,我们增加了课程的关注功能,即喜欢该课程的用户可以通过点击关注以获得更新通知。这样,在课程的信息页面上也可以清楚的看到关注的人数。为此,每个课程文档需要增加 favCount 字段用来表示得到的关注数量,如下:
对于 MongoDB 来说,更多的应用实践倾向于利用单文档事务性来解决原子性问题,当然,你也可以使用高版本中的多文档事务实现,但缺点是必须接受多文档事务所带来的性能损失。而关于MongoDB 的文档级原子性,尽管大多数人已经知道这一点,但在一些真实的项目案例中,仍然可以发现各种考虑不周的情形。下面,以案例来说明此类问题。案例一 为了能了解网站上在售课程的受欢迎程度,我们增加了课程的关注功能,即喜欢该课程的用户可以通过点击关注以获得更新通知。这样,在课程的信息页面上也可以清楚的看到关注的人数。为此,每个课程文档需要增加 favCount 字段用来表示得到的关注数量,如下:
@Data
@Document(collection="Course")
public class Course {
@Id
private String id;
private String courseName;
//收藏数量
private Integer favCount;
...
这里对 Course 类添加了@Document 注解,这表示框架将处理文档和对象之间的关系,这是Spring Data Mongo 提供的 ORM 实现。那么,对于"加关注"这一逻辑功能,很容易实现如下:
@Autowired
private CourseRepository courseRepository;
public boolean incrFavCount(String courseId) {
Assert.hasLength(courseId, "courseId required");
Course course = courseRepository.findById(courseId).orElse(null);
if (course == null) {
return false;