1

I have built this database object below.

I want the methods update and query to be: 1. work in a multithread way (meaning 2 threads can access them at the same time - what synchronized prevents - that is why I cannot add it the the mehtod singutare). 2. if one thread had started open the database and the 2nd thread (that started after it) is trying to use that database - I don't want to get a situation where the 2nd thread is accessing the database when it is not yet open. in other words - I want it to be multithreaded in general but thread safe (atomic) when 1 thread is opening the data base for the first time.

Thanks, The class below is where I need to insert my logic (more specific - to the query and update methods).

public class SingeltonDB {
    private static DBconnImpl db = null;
    private static SingeltonDB singalDb = null;

    private SingeltonDB(String username, String password) {
        db = new DBconnImpl();
    }

    public static boolean isOpen() {
        return (db != null);
    }

    public synchronized static SingeltonDB getInstance(String username,
            String password) throws Exception {
        if (db != null) {
            throw (new Exception("The database is  open"));
        } else {
            System.out.println("The database is now open");
            singalDb = new SingeltonDB(username, password);
        }
        db.connect(username, password);
        System.out.println("The database was connected");
        return singalDb;
    }

    public synchronized static SingeltonDB getInstance() throws Exception {
        if (db == null) {
            throw (new Exception("The database is not open"));
        }

        return singalDb;
    }

    public void create(String tableName) throws Exception {
        db.create(tableName);
    }

    public  User query(String tableName, int rowID) throws Exception {
        if (db == null) {
            System.out.println("Error: the database is not open");
            return null;
        }
        return (db.query(tableName, rowID));
    }

    public  void update(String tableName, User user) throws Exception {
        if (db == null) {
            System.out.println("Error: the database is not open");
            return;
        }
        db.update(tableName, user);
    }

}

1 Answer 1

1

I would move the connect call from the getInstance static method to the SingeltonDB constructor. This will guarantee that the db is opened whenever you get a reference to the static db field. I would also add the db == null check to all non-static methods.

public class SingeltonDB {
    private static DBconnImpl db = null;
    private static SingeltonDB singalDb = null;

    private SingeltonDB(String username, String password) {
        db = new DBconnImpl();
        db.connect(username, password);
        System.out.println("The database was connected");
    }

    public static boolean isOpen() {
        return (db != null);
    }

    public synchronized static SingeltonDB getInstance(String username,
            String password) throws Exception {
        if (db != null) {
            throw (new Exception("The database is  open"));
        } else {
            System.out.println("The database is now open");
            singalDb = new SingeltonDB(username, password);
        }
        return singalDb;
    }

    public synchronized static SingeltonDB getInstance() throws Exception {
        if (db == null) {
            throw (new Exception("The database is not open"));
        }

        return singalDb;
    }

    private static void checkDbOpened() throws Exception {
        if (db == null) {
            throw new Exception("The database is not open");
        }
    }

    public void create(String tableName) throws Exception {
        checkDbOpened();
        db.create(tableName);
    }

    public  User query(String tableName, int rowID) throws Exception {
        checkDbOpened();
        return (db.query(tableName, rowID));
    }

    public  void update(String tableName, User user) throws Exception {
        checkDbOpened();
        db.update(tableName, user);
    }

}

Here is an updated singleton that will allow you to determine if a table was created

public class SingeltonDB {
    private static DBconnImpl db = null;
    private static SingeltonDB singalDb = null;
    private static ConcurrentSkipListSet<String> tableNames = new ConcurrentSkipListSet<String>();

    private SingeltonDB(String username, String password) {
        db = new DBconnImpl();
        db.connect(username, password);
        System.out.println("The database was connected");
    }

    public static boolean isOpen() {
        return (db != null);
    }

    public synchronized static SingeltonDB getInstance(String username,
            String password) throws Exception {
        if (db != null) {
            throw (new Exception("The database is  open"));
        } else {
            System.out.println("The database is now open");
            singalDb = new SingeltonDB(username, password);
        }
        return singalDb;
    }

    public synchronized static SingeltonDB getInstance() throws Exception {
        if (db == null) {
            throw (new Exception("The database is not open"));
        }

        return singalDb;
    }

    private static void checkDbOpened() throws Exception {
        if (db == null) {
            throw new Exception("The database is not open");
        }
    }

    private static void checkForTable(String tableName) {
        if (tableNames.add(tableName)) {
           db.create(tableName);
        }
    }

    public void create(String tableName) throws Exception {
        checkDbOpened();
        checkForTable(tableName);
    }

    public  User query(String tableName, int rowID) throws Exception {
        checkDbOpened();
        checkForTable(tableName);
        return (db.query(tableName, rowID));
    }

    public  void update(String tableName, User user) throws Exception {
        checkDbOpened();
        checkForTable(tableName);
        db.update(tableName, user);
    }

}

The checkForTable function will determine if the given tableName was already created or not. If it wasn't, it will then create the table. This update will insure that the table was created prior to it being used. The issue with this code is that it does not work across processes but is only going to work within a single process unless the db class knows how to manage tables that are being created across process boundaries.

Sign up to request clarification or add additional context in comments.

2 Comments

And how does it thread safe? say thread 1 is calling getInstance for the first time, after it thread 2 is trying to create a table - but because thread 1 has not finish yet he sees db as null - what should not happened in this desirable workflow. is the fact that getInstance is a synchronized method prevent such a scenario to happen? beacuse synchronized only tells us that this specific method could be run by one thread at a time - but in my case the problem is that create() is not synchronized.
This only insure that the database is opened prior to accessing it. The problem with this solution is that the created tableName can be different for each non-create call. T1 will create table "foo" while T2 will create table "bar". If T3 wants to update table "foo" then it needs to know that table "foo" was created prior to it being processed. The class needs to contain references to the tables that have been created before allow a caller to perform a task. I'll update the code to perform that task.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.