Class DataSource

java.lang.Object
com.codename1.backend.DataSource

public final class DataSource extends Object

A pool of connections to ONE database, whichever engine that database is.

DbPool pools SQLite and only SQLite -- it opens connections from a file path, so there is nowhere to put a host, a user or a password. That left the server engines with the advice to share a single Database and accept that every handler queues behind whichever exchange is on the socket, because a Database over PostgreSQL or MySQL owns one wire connection and synchronizes every operation on it.

Queueing is the right default for a server whose database is a local file. It is the wrong one for a server whose database is a machine across a network that is perfectly happy to run eight statements at once: there the single connection is not a safety property, it is the bottleneck. This is the same pool for all three, so which engine is behind it stops being a question the application's structure has to answer.

DataSource db = DataSource.open("postgres://user:pw@db.internal/app");
List rows = db.query("SELECT id, title FROM notes WHERE author = ?",
        new Object[] {author});

The convenience methods above borrow a connection, run one statement and release it, which is what a handler wants: it is the borrow held ACROSS unrelated work that empties a pool. inTransaction(DataSource.Work) is the form for several statements that have to be one, and it holds exactly one connection for exactly the body.

Connections are opened lazily except the first, which is opened by open(String) so that a wrong URL, an unreachable host or a refused password fails at start-up rather than on the first request that needed the database.

An in-memory SQLite database is pooled at size one, and a configuration asking for more is REFUSED rather than quietly reduced. Each connection to ":memory:" gets its OWN private database, so a pool of them hands successive requests different empty databases -- the one case where a bigger pool is not slower but wrong, and a setting worth reporting rather than ignoring.

  • Method Details

    • open

      public static DataSource open(String url) throws IOException
      A pool of the default size for whatever engine url names.
      Throws:
      IOException
    • open

      public static DataSource open(String url, int size) throws IOException
      A pool of size connections; 0 takes the default for the engine.
      Throws:
      IOException
    • open

      public static DataSource open(String url, int size, int busyTimeoutMillis, long borrowTimeoutMillis) throws IOException
      The general form.
      Parameters:
      size - how many connections at most; 0 for the engine's default
      busyTimeoutMillis - how long SQLite waits on a locked database; ignored by the server engines, which have no such setting
      borrowTimeoutMillis - how long a borrow waits for a free connection before failing; 0 waits forever
      Throws:
      IOException
    • fromConfig

      public static DataSource fromConfig(Config config) throws IOException

      The pool a Config describes, which is the one a server normally wants: the URL comes from the deployment rather than from the source.

      With no URL configured at all this answers an in-memory SQLite database on a development profile, and refuses on any other. Defaulting silently in production is how a service comes up healthy, serves requests, writes everything into a database inside its own process and loses all of it at the next deploy.

      Throws:
      IOException
    • of

      public static DataSource of(Database db) throws IOException

      A pool of one around a connection somebody else opened, for code that has a Database already and wants the pooled API around it.

      The connection is NOT closed by close(): it belongs to whoever opened it.

      Throws:
      IOException
    • borrow

      public Database borrow() throws IOException
      Takes a connection, blocking until one is free. Release it in a finally, or prefer the methods that cannot leak one.
      Throws:
      IOException
    • release

      public void release(Database db)
      Returns a borrowed connection to the pool.
    • withConnection

      public Object withConnection(DataSource.Work body) throws Exception
      Borrows a connection, runs body, and returns it however body ends.
      Throws:
      Exception
    • inTransaction

      public Object inTransaction(DataSource.Work body) throws Exception

      One transaction on one borrowed connection.

      Everything the body does through the Database it is handed is inside that transaction. Anything it does through THIS pool is not: that borrows a second connection, which the database sees as another session entirely, and on SQLite it will simply block against the write lock the first one holds.

      Throws:
      Exception
    • execute

      public int execute(String sql, Object[] params) throws IOException
      One statement on a borrowed connection.
      Throws:
      IOException
    • query

      public List query(String sql, Object[] params) throws IOException
      One query on a borrowed connection.
      Throws:
      IOException
    • queryOne

      public Map queryOne(String sql, Object[] params) throws IOException
      One query that returns at most one row, on a borrowed connection.
      Throws:
      IOException
    • insert

      public long insert(String sql, Object[] params, String idColumn) throws IOException

      One INSERT on a borrowed connection, answering the key the database generated.

      The connection is held across the insert AND the question that reads the key back, which is what makes the answer this insert's on the engines where the key is a property of the session -- SQLite's last_insert_rowid and MySQL's LAST_INSERT_ID both answer for the connection they are asked on. A pooled insert that released between the two would read whatever the next borrower had done.

      Throws:
      IOException
    • dialect

      public Dialect dialect()
      How this pool's engine spells things. See Dialect.
    • getMaxSize

      public int getMaxSize()
      How many connections this pool may hold.
    • getOpenCount

      public int getOpenCount()
      How many are open right now, borrowed or idle.
    • getIdleCount

      public int getIdleCount()
      How many are open and free right now.
    • close

      public void close()
      Closes every connection. Borrowed ones are closed as they come back.
    • toString

      public String toString()
      Description copied from class: Object
      Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method. The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object. In other words, this method returns a string equal to the value of: getClass().getName() + '@' + Integer.toHexString(hashCode())
      Overrides:
      toString in class Object