How to implement a listener for access events of a sqlite database in Java

怎甘沉沦 提交于 2019-12-25 06:36:02

问题


I'd like to display a 'indeterminate JProgressBar' in my Java application each time it accesses the SQLite database for reading / writing. I think the most important thing is to realize a trigger signal from the database. Then implement a listener to this trigger to display the progress bar.

I use SQLite with the Xerial JDBC driver with JDK 1.7. The application is 'stand alone'. The SQLite database is on the hdd. I have a good basic understanding of Java, but i'm no expert. Approaches with Hibernate / Spring etc. are way too much for me.

What i've found so far from an internet search (click header links for details):

Idea 1 (Manual approach):

Manually start the progress bar each time needed. Then execute Swingworker. Use its overridden done() method to stop the progress bar.

Pro:

  • Very easy approach

Con:

  • A lot of coding necessary for every event you need the progress bar

Idea 2 (Overriding methods):

Override the commit() and the close() method of java.sql.Connection and send a trigger signal everytime these methods are executed.

Pro:

  • Very easy approach
  • No extra coding necessary
  • Exact start and stop trigger for database access
  • JDBC approach

Con:

  • Parsing of commits necessary to find out if read or write access

Idea 3 (Man in the middle):

Use jdbctools as a middle layer for monitoring. Use JDBCLogger or JDBCCallFilter to detect accesses.

Pro:

  • No extra coding necessary
  • Exact start and stop trigger for database access

Con:

  • Little documentation / no examples
  • Outdated (2008)?

Idea 4 (Pooling):

Use ConnectionEventListener from javax.sqlto monitor database connection.

Pro:

  • Built-in Java SQL functionality

Con:

  • Needs a PooledConnection object which is a bit over the top for the task
  • No trigger for connection start

Idea 5 (use SQLite C interface):

Use 'Query Progress Callbacks' from SQLite C Interface which is intended for the use case.

Pro:

  • Native SQLite functionality

Con:

  • Because it is in 'C' it must be implemented in the JDBC driver to use this functionality. The Xerial driver doesn't seem to have it implemented
  • Limited to SQLite database

Summary: I'd tend to try 'idea 2' but i'd like to hear what the experts are saying first: Which approach would you prefer or how would you implement that kind of trigger signal?


回答1:


At first:

  • Idea 2 (Overriding methods) didn't work because the methods are static and cannot be overridden.

  • Idea 5 (use SQLite C interface) needs a Java implementation for 'Query Progress Callbacks'. There's already some work done but it has not been merged into the JDBC driver by Xerial yet. For more details see here.

  • Idea 3 & 4 seem to be feasable but make my project too complicated and harder to maintain.

So i came across to extend Idea 1:

  1. The best triggers for a progress bar are the moments when you open and close a database connection.
  2. These triggers can fire events which can be caught by an event listener that will open a dialog with a progress bar

At first you need to create some classes for the event mechanisms. You can find details about the idea of EventObjects here and here.

Db_Status.java:

public class Db_Status 
{
    public final static Db_Status CONNECTED = new Db_Status("connected");
    public final static Db_Status PENDING = new Db_Status("pending");
    public final static Db_Status CLOSED = new Db_Status("closed"); // Closed database connection
    public final static Db_Status IDLE = new Db_Status("idle"); // Initial status of database after app start
    public final static Db_Status ERROR = new Db_Status("error"); // Error while accessing / closing database

    private String status;

    public String toString() {
        return status;
    }

    private Db_Status(String statusstring) {
        status = statusstring;
    }

}

Db_ActionEvent.java:

public class Db_ActionEvent extends EventObject 
{
    private Db_Status status;

    public Db_ActionEvent(Object source, Db_Status DBstate) {
        super(source);
        status = DBstate;
    }
    public Db_Status Status() {
        return status;
    }

}

Db_ActionListener.java:

public interface Db_ActionListener {

    public void DbActionReceived(Db_ActionEvent event );

}

You must then implement the listener. This is the place for the reaction after the listener has caught a database event, here: ouput to console:

public class UI_DbProgressbar implements Db_ActionListener{
    public void DbActionReceived(Db_ActionEvent event) {
        if(event.Status() == Db_Status.PENDING)
        {
            System.out.println("DB is busy!" );
        }
        else if(event.Status() == Db_Status.CLOSED)
        {
            System.out.println("DB connection is closed!");
        }
        else if(event.Status() == Db_Status.CONNECTED)
        {
            System.out.println("DB is connected!");
        }
        else
        {
            System.out.println("DB idle!" );
        }
    }
}

Finally you must establish the trigger mechanism. You may have a central class that handles all of the database accesses. There you will have to

  • Create two central methods to open and close connections
  • Add some methods to control the listener
  • Adapt the constructor to add right from the creation of the class a listener to it.

    public class Db_DataExchange{

    //
    // Adaptions to the constructor
    //
    
    public Db_DataExchange() 
    {
        this.DBStateListeners = new ArrayList();
    
        // Your constructor code here ...
    
        UI_DbProgressbar listener = new UI_DbProgressbar();
        this.addDbActionListener(listener);
    }
    
    //
    // Add some methods to control the listener
    //
    
    private Db_Status DBAccessStatus = Db_Status.IDLE;
    private List DBStateListeners;
    
    public synchronized void addDbActionListener(Db_ActionListener l) {
        DBStateListeners.add( l );
    }
    
    public synchronized void removeDbActionListener(Db_ActionListener l) {
        DBStateListeners.remove( l );
    }
    
    private synchronized void fireDbActionEvent(Db_Status AccessStatus) 
    {
        DBAccessStatus = AccessStatus;
        Db_ActionEvent status = new Db_ActionEvent(this, DBAccessStatus);
        Iterator listeners = DBStateListeners.iterator();
        while(listeners.hasNext()) {
            ((Db_ActionListener) listeners.next()).DbActionReceived(status);
        }
    }
    
    //
    // Create two central methods to open and close connections
    //
    
    /**
     * Your method to establish a jdbc database connection  
     */
    public Connection EstablishDBConnection(String ConnectionURL){
        Connection c = null;
    
        try {
            // Load JDBC sqlite driver
            Class.forName(this.DBDriverName);
    
            // url - a database url of the form jdbc:subprotocol:subname
            c = DriverManager.getConnection(ConnectionURL);
    
            c.setAutoCommit(false);
    
            System.out.println("Database connected successfully!");
            // this ist the important trigger:
            this.fireDbActionEvent(Db_Status.CONNECTED);
    
            return c;
    
        } catch ( Exception e ) {
            System.err.println( e.getClass().getName() + ": " + e.getMessage() );
            this.fireDbActionEvent(Db_Status.ERROR);
            return c;
        }
    
    }
    
    /**
     * Your method to close a jdbc database connection 
     */
    public boolean CloseDBConnection(Connection c){
        try 
        {
            c.close(); // finally close
            // this ist the important trigger:
            this.fireDbActionEvent(Db_Status.CLOSED);
    
            return true;
    
        } catch ( Exception e ) 
        {
            //System.err.println( e.getClass().getName() + ": " + e.getMessage() );
            logger.error("Error in {}: {}",e.getClass().getName(),e.getMessage());
            this.fireDbActionEvent(Db_Status.ERROR);
    
            return false;
        }
    }
    

    }



来源:https://stackoverflow.com/questions/36306324/how-to-implement-a-listener-for-access-events-of-a-sqlite-database-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!