简体   繁体   English

处理并发的正确方法是什么?

[英]What's the correct way of handling concurrency?

I have a servlet which accesses DB through a singleton class named DBManager. 我有一个Servlet,它通过名为DBManager的单例类访问DB。 This class contains a reference to EntityManager. 此类包含对EntityManager的引用。 This is my code: 这是我的代码:

package database;


import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;

import com.btc.EMF;

import database.entities.User;



public class DBManager {
    public class UserAlreadyExistsException extends Exception{
        private static final long serialVersionUID = 1L;}
    /* attributes */
    private static DBManager instance = null;

    private final EntityManager em = EMF.get().createEntityManager();
    private int tokens = 1;
    private final EntityTransaction transaction = em.getTransaction();


    private DBManager(){
    }

    public static DBManager getInstance(){
        if(instance == null){
            instance = new DBManager();
        }
        return instance;
    }

    @SuppressWarnings("unchecked")
    public synchronized boolean createUser(String username, String password) throws UserAlreadyExistsException {
        while(tokens == 0){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        tokens--;
        Query q = em.createQuery("select u from "+User.class.getName()+" u");
        List<User> list = q.getResultList();
        if(list != null){
            if(list.size()>0){
                throw new UserAlreadyExistsException();
            }
        }
        User u = new User();
        u.setUsername(username);
        u.setPassword(password);
        transaction.begin();
        em.persist(u);
        transaction.commit();
        tokens++;
        this.notifyAll();
        return true;
    }

    @SuppressWarnings("unchecked")
    public synchronized void eraseDB(){
        while(tokens == 0){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        tokens--;
        Query q = em.createQuery("select u from "+User.class.getName()+" u");
        List<User> list = q.getResultList();
        transaction.begin();
        for(User u : list)
            em.remove(u);
        transaction.commit();
        tokens++;
        this.notifyAll();
    }

    public EntityManager getEm() {
        return em;
    }

}

The serlvet simply calls eraseDB() and createUser() in sequence. eraseDB()只需eraseDB()调用eraseDB()createUser()

I added synchronized methods and wait() and notifyAll() in order to make concurrency work but I failed. 为了使并发工作,我添加了synchronized方法以及wait()notifyAll() ,但是失败了。 If I keep pressing F5 in the browser some error occurs due to concurrency problems. 如果我在浏览器中持续按F5,则由于并发问题会发生一些错误。 And also this usage of wait and notify appears too complex. 而且,这种等待和通知的用法似乎太复杂了。

What's the correct way to do this? 正确的方法是什么?

Basically, every object that handles Connection and related resources must be initialized in the narrowest scope. 基本上,每个处理Connection和相关资源的对象都必须在最窄的范围内初始化。 Apart of this, you're naively and badly applying singleton for your DBManager which will be used among several threads because multiple requests are served by a single servlet instance (more info on this: How do servlets work? Instantiation, sessions, shared variables and multithreading ). 除此之外,您还天真地DBManager应用了singleton,它将在多个线程中使用,因为单个servlet实例会处理多个请求(有关更多信息: servlet如何工作?实例化,会话,共享变量和多线程 )。

The best option would be removing the singleton (anti) pattern from your DBManager class and make sure to initialize DBManager in the narrowest scope where the database resources should be handled. 最好的选择是从DBManager类中删除单例(反)模式,并确保在应处理数据库资源的最窄范围内初始化DBManager

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM