어제 고려했던 방식으로 코드를 짜봤다.
우선 Posts 모델에 likeCount 칼럼을 추가하고
새로 Likes 모델을 만들어 userId와 postId를 유지시켰다.
그러다가 문제가 발생했는데,....
const express = require('express');
const router = express.Router();
const { Posts, Users, Likes, sequelize } = require('../models');
const { Transaction } = require('sequelize');
const authMiddleware = require('../middlewares/auth-middleware.js');
router.patch('/posts/:postId/like', authMiddleware, async (req, res) => {
const { userId } = res.locals.user;
const { postId } = req.params;
const post = await Posts.findOne({
attributes: ['postId', 'likeCount'],
include: [
{
model: Users,
attributes: ['userId'],
},
],
where: { postId },
});
if (!post) {
res.status(404).json({
errorMessage: '존재하지 않는 게시글입니다.',
});
return;
}
const likes = await Likes.findOne({
where: { [Op.and]: [{ PostId: postId }, { UserId: userId }] },
});
const t = await sequelize.transaction({
isolationLeverl: Transaction.ISOLATION_LEVELS.READ_COMMITTED,
});
try {
if (!likes) {
await Likes.create(
{
UserId: userId,
PostId: postId,
},
{ transaction: t }
);
await Posts.update(
{ likeCount: post.likeCount + 1 },
{ where: { postId } },
{ transaction: t }
);
} else {
await Likes.destroy({ where: { postId } }, { transaction: t });
await post.update({ likeCount: post.likeCount - 1 }, { transaction: t });
}
} catch (error) {
await t.rollback();
return res
.status(400)
.json({ errorMessage: '좋아요 수정에 실패했습니다.' });
}
await t.commit();
return res.status(200).json({ message: '좋아요 변경이 완료됐습니다.' });
});
문제가 되는 부분은
...
if (!likes) {
await Likes.create(
{
UserId: userId,
PostId: postId,
},
{ transaction: t }
);
await Posts.update(
{ likeCount: post.likeCount + 1 },
{ where: { postId } },
{ transaction: t }
);
}
...
해당 부분의 await Likes.create 였는데
정말.. 이상하게도 다음과 같이 create와 update의 순서를 바꾸어 주었더니 오류가 해결되었다.
await Posts.update(
{ likeCount: post.likeCount + 1 },
{ where: { postId } },
{ transaction: t }
);
await Likes.create(
{
UserId: userId,
PostId: postId,
},
{ transaction: t }
);
아무리 생각해보아도 순서에 의해서 문제가 생긴다는게 와닿지 않았다.
혹시나 교착상태가 발생하나 고민도 해보았으나,
postId는 params 값으로, userId값은 authMiddleware에서 참조해오고 각기 다른 테이블에서 실행되기 때문에 교착상태가 생길 것 같지는 않았는데 순서를 바꿔주는 것으로 문제가 해결됐다...
다른 방식으로
Posts 모델자체를 참조해서 where로 걸러내어 update를 하는 것이 아니라
위에서 받아오고 있는
const post = await Posts.findOne({
attributes: ['postId', 'likeCount'],
include: [
{
model: Users,
attributes: ['userId'],
},
],
where: { postId },
});
이 post값을 불러와 다음과 같이 작성하였다.
await Likes.create(
{
UserId: userId,
PostId: postId,
},
{ transaction: t }
);
await post.update({ likeCount: post.likeCount + 1 }, { transaction: t });
post자체로 update를 사용하고 where을 제거해주자 create와 update의 위치와 관계없이 정상 작동 하였다.