So, I was working on a simple Spring MVC + JPA (hibernate) project where there are Users who can makes Posts and make Comments on their friends Posts (somewhat like a small social network) . I am still relatively new using JPA Hibernate. So, when I try to test from browser sending multiple requests for some task ( containing transactions) very quickly 2-3 times while a previous request is being processed I get an OptimisticLockException . Here 's the stack trace ..
org.springframework.web.util.NestedServletException: Request processing   failed; nested exception is org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [org.facebookjpa.persistance.entity.Post] with identifier [19]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [org.facebookjpa.persistance.entity.Post#19]
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
Now, how do i fix this? How do i handle this ObjectOptimisticLockException properly when multiple transaction requests occurs simultaneously ? Is there any good patten that i should follow ? Do i need to use some sort of Pessimistic Locking mechanism ?
Here's the DAO that i am currently using .. Thanks in advance . :)
@Repository
@Transactional
public class PostDAOImpl implements PostDAO {
@Autowired
UserDAO userDAO;
@Autowired
CommentDAO commentDAO;
@Autowired
LikeDAO likeDAO;
@PersistenceContext
private EntityManager entityManager;
public PostDAOImpl() {
}
@Override
public boolean insertPost(Post post) {
    entityManager.persist(post);
    return true;
}
@Override
public boolean updatePost(Post post) {
    entityManager.merge(post);
    return true;
}
@Override
public Post getPost(int postId) {
    TypedQuery<Post> query = entityManager.createQuery("SELECT p FROM Post AS p WHERE p.id=:postId", Post.class);
    query.setParameter("postId", postId);
    return getSingleResultOrNull(query);
}
@Override
public List<Post> getAllPosts() {
    return entityManager.createQuery("SELECT p FROM Post AS p ORDER BY p.created DESC", Post.class).getResultList();
}
@Override
  public List<Post> getNewsFeedPostsWithComments(int userId) {
    List<Post> newsFeedPosts = getUserPosts(userId);
    newsFeedPosts.addAll(getFriendsPost(userDAO.getUser(userId)));
    for (Post post : newsFeedPosts) {
        post.setComments(commentDAO.getPostComments(post.getId()));
        post.setLikes(likeDAO.getPostLikes(post.getId()));
    }
    return newsFeedPosts;
}
public List<Post> getFriendsPost(User user) {
    List<Post> friendsPosts = new ArrayList<Post>();
    for (User u : user.getFriends()) {
        friendsPosts.addAll(getUserPosts(u.getId()));
    }
    return friendsPosts;
}
@Override
public List<Post> getUserPosts(int userId) {
    TypedQuery<Post> query = entityManager.createQuery("SELECT p FROM Post AS p WHERE p.user.id = :userId ORDER BY p.created DESC", Post.class);
    query.setParameter("userId", userId);
    return query.getResultList();
}
@Override
public List<Post> getUserPostsWithComments(int userId) {
    List<Post> userPostsWithComments = getUserPosts(userId);
    for (Post post : userPostsWithComments) {
        post.setComments(commentDAO.getPostComments(post.getId()));
        post.setLikes(likeDAO.getPostLikes(post.getId()));
    }
    return userPostsWithComments;
}
@Override
public boolean removePost(Post post) {
    entityManager.remove(post);
    return true;
}
@Override
public boolean removePost(int postId) {
    entityManager.remove(getPost(postId));
    return true;
}
private Post getSingleResultOrNull(TypedQuery<Post> query) {
    query.setMaxResults(1);
    List<Post> list = query.getResultList();
    if (list.isEmpty()) {
        return null;
    }
    return list.get(0);
}
}
 
    