SQLite - The database file is locked?

Discussion in 'Plugin Development' started by bfgbfggf, Apr 4, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    bfgbfggf

    I have that error
    [SEVERE] Database query error: [SQLITE_BUSY] The database file is locked (database is locked)
    error is only in SQLite (i have one code for MySql and SQLite in that part of code)
    error show if i use a result set in PlayerLoginEvent and PlayerJoinEvent. How to fix that? (I can't delete any result) and if error show that one time then not work any command using datebase ;/ just db is locked...
     
  2. Offline

    blablubbabc

    Make sure you always only have one active connection to your sqlite database. Create one connection and share it everywhere you need to connect to the database, OR close your connections after you are finished using them. On disable: close the connection too.
     
  3. Offline

    bfgbfggf

    hyym how to connect to db in one code? that must work in all code . on enable, on commend and in events.
    And/or how to close :D

    for db i use that code from this forum
    Code:java
    1.  
    2. public class Db {
    3. private final Plugin plugin;
    4. private final String url;
    5. private Logger log;
    6.  
    7. public Db(final Plugin plugin, final String host, final String database,
    8. final String user, final String password) {
    9. this.plugin = plugin;
    10. url = "jdbc:mysql://" + host + "/" + database + "?user=" + user
    11. + "&password=" + password;
    12. log = plugin.getServer().getLogger();
    13. initDriver("com.mysql.jdbc.Driver");
    14. }
    15.  
    16. public Db(final Plugin plugin, final String filePath) {
    17. this.plugin = plugin;
    18. url = "jdbc:sqlite:" + new File(filePath).getAbsolutePath();
    19. log = plugin.getServer().getLogger();
    20. initDriver("org.sqlite.JDBC");
    21. }
    22.  
    23. private void initDriver(final String driver) {
    24. try {
    25. Class.forName(driver);
    26. } catch (final Exception e) {
    27. log.severe("Database driver error:" + e.getMessage());
    28. }
    29. }
    30.  
    31. public int resultInt(ResultSet result, int column) {
    32. if (result == null)
    33. return 0;
    34. try {
    35. result.next();
    36. int integer = result.getInt(column);
    37. result.close();
    38.  
    39. return integer;
    40. } catch (SQLException e) {
    41. log.severe("Database result error: " + e.getMessage());
    42. }
    43. return 0;
    44. }
    45.  
    46. public String resultString(ResultSet result, int column) {
    47. if (result == null)
    48. return null;
    49. try {
    50. result.next();
    51. String string = result.getString(column);
    52. result.close();
    53. return string;
    54. } catch (SQLException e) {
    55. log.severe("Database result error: " + e.getMessage());
    56. }
    57. return null;
    58. }
    59.  
    60. public ResultSet query(final String query) {
    61. return query(query, false);
    62. }
    63.  
    64. public ResultSet query(final String query, final boolean retry) {
    65. try {
    66. final Connection connection = DriverManager.getConnection(url);
    67. final PreparedStatement statement = connection
    68. .prepareStatement(query);
    69. if (statement.execute())
    70. return statement.getResultSet();
    71. } catch (final SQLException e) {
    72. final String msg = e.getMessage();
    73. log.severe("Database query error: " + msg);
    74. if (retry && msg.contains("_BUSY")) {
    75. log.severe("Retrying query...");
    76. plugin.getServer().getScheduler()
    77. .scheduleSyncDelayedTask(plugin, new Runnable() {
    78. @Override
    79. public void run() {
    80. query(query);
    81. }
    82. }, 20);
    83. }
    84. }
    85. return null;
    86. }
    87. }
    88.  
     
  4. Offline

    blablubbabc

    Code:
    public ResultSet query(final String query, final boolean retry) {
    try {
    final Connection connection = DriverManager.getConnection(url); // <- the Connection should be closed after execution
    final PreparedStatement statement = connection
    .prepareStatement(query);  // <- the (Prepared)Statement should be closed after execution
    if (statement.execute())
    return statement.getResultSet(); // <- the ResultSet should be closed after execution
    } catch (final SQLException e) {
    final String msg = e.getMessage();
    log.severe("Database query error: " + msg);
    if (retry && msg.contains("_BUSY")) {
    log.severe("Retrying query...");
    plugin.getServer().getScheduler()
    .scheduleSyncDelayedTask(plugin, new Runnable() {
    @Override
    public void run() {
    query(query);
    }
    }, 20);
    }
    }
    return null;
    }
    }
    Also, instead of closing the connection or the prepared statements, you could set them up on top of your class and keep using them (the same object), instead of creation a new one each time..
     
  5. Offline

    bfgbfggf

    hyym that is another class. in mainclass I using only

    Code:java
    1.  
    2. Db base = null; // for use MySql and SQlite in one code (or 2 if that not possible in syntax)
    3. if (MySqlStatus == true) {
    4. String Host = config.getString("Global.MySql.host");
    5. String user = config.getString("Global.MySql.user");
    6. String db = config.getString("Global.MySql.db");
    7. String pass = config.getString("Global.MySql.pass");
    8. base = new Db(this, Host, db, user, pass);
    9. } else {
    10. base = new Db(this, getDataFolder() + File.separator + "SQLite.db");
    11. }

    All code in "onEnable" "on command" and some another. Works great.
    I use tak code in every place. one in "onEnable" one in "onCommand"ane in... I don't know how to write only one :D
    only in that 2 events. (register: getServer().getPluginManager().registerEvents(this, this); )

    f5

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 31, 2016
  6. Offline

    lycano

    blablubbabc you did not suggest leaving a connection open after executing your queries didn't you?

    Of course you can share the same connection for multiple queries (i hope that is what you ment xD) but don't leave a connection open when you are done with whatever you wanted to do as this might lead to file corruption when the connection is still open and the server crashes.
     
  7. Offline

    bfgbfggf

    but how to close it. using that code?
     
  8. Offline

    lycano

    bfgbfggf You can check out my github page and checkout the database folder in xAuth plugin. Its not the best written code as i didnt have really spend much time in refactoring the database backend but you can use the codebase if you like. Should at least give you a good start or show you how you can do it.

    Remove everything you dont need like the autoupdater methods and so on. Basically you need ConnectionPool.java, Table.java, DatabaseController.

    Of course you can use the DatabaseUpdater too but i dont suggest using it as it stores the current state of the table in a file and thats what i really dont like.
     
  9. Offline

    bfgbfggf

    But... new code ? ;/ I have some code. that too many changes. There are any method to close without new code? ;/
    just edit that code http://pastebin.com/SzxdH5fN or use something in mainclass? (I have only 3 class. one for db, one for auto updates and mainClass with all code)
    or another method to fix that bug

    EDIT: My events http://pastebin.com/bfbJSF7y // sorry for polish in some places (I don't have time to translate it :D )
     
  10. Offline

    blablubbabc

    I already showed you where in your code you have to take care about closing the Connection/the Statement/the ResultSet. You can close them via "object.close();" with "object" being one of those 3 types (Connection, Statement, ResultSet). If you return a result set in one of your methods, you will have to close this ResultSet in the calling method, otherwise you will get memory leaks.
     
    bfgbfggf likes this.
  11. Offline

    bfgbfggf

    blablubbabc
    if I use that in my main class I have error.
    ResultSet.close(); this same with Connection and Statement.
    Hymm I have one another question. If that SQLite not support multi threads then... how write code like this:
    Code:java
    1.  
    2. ResultSet res1 = base.query("SELECT id,PTimed,TimeEnd FROM ProWarns WHERE Ostrzegany = '"+ cel + "'");
    3. String prl = "a";
    4. long TimeEnd = 0l;
    5. int Timed = 0;
    6. while (res1.next()) {
    7. Timed = res1.getInt("Timed");
    8. if (Timed == 1) {
    9. TimeEnd = res1.getLong("TimeEnd");
    10. Date dt = new Date();
    11. long EndTime = dt.getTime();
    12. if (TimeEnd <= EndTime) {
    13. int id = res1.getInt("id");
    14. base.query("DELETE FROM ProWarns WHERE id = '"+ id + "'");
    15. }
    16. }
    17. }
    18.  

    In MySql that works

    ok i find error in my close... :D but how about that code?
    blablubbabc
    EDIT: but works only ResultSet.close because in my mainclass i not have a Connection.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 31, 2016
  12. Offline

    blablubbabc

    Take a look at your query-method: it creates a new connection there and it doesn't close it or re-use it later. SQLite only allows you to have one open connection to the database. Every time you call the query method it will try to create a new connection currently without the old one being closed before. So when you call the second query
    base.query("DELETE FROM ProWarns WHERE id = '"+ id + "'");

    You try to create a second connection to the SQLite database -> not supported by SQLite -> Error

    You have 2 possibilities what you can do here: Only create 1 connection once somehwere in your code and reuse it for every query, or close the connection when you are done.

    I would prefer to re-use 1 connection.
     
  13. Offline

    bfgbfggf

    Hyym I learning a java very short time. and I don't know how to reuse ;/and how to close connection if isn't in main class :D
     
  14. Offline

    blablubbabc

    ..

    Code:
    // Somewhere in ypur DB class:
    private Connection connection;
     
    public void closeConnection() {
            try {
                connection.close();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
     
    public boolean isConnected() {
            try {
                return((connection==null || connection.isClosed()) ? false:true);
            } catch (SQLException e) {
                e.printStackTrace();
                return false;
            }
        }
     
    public void initialize() {
            try {
                connection = DriverManager.getConnection(url);
            } catch (SQLException ex) {
                log("ERROR: SQL Exception!");
                ex.printStackTrace();
            } catch (ClassNotFoundException ex) {
                log("ERROR: Could not find SQLite driver class!");
                ex.printStackTrace();
            }
        }
     
    //Some class that should help you to close the statement and the resultSet from outside of this class:
     
    public class Result {
        private ResultSet resultSet;
        private Statement statement;
     
        public Result(Statement statement, ResultSet resultSet) {
            this.statement = statement;
            this.resultSet = resultSet;
        }
     
        public ResultSet getResultSet() {
            return this.resultSet;
        }
     
        public void close() {
            try {
                this.statement.close();
                this.resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
     
    }
     
    // Your query method (with bad formatting):
    public Result query(final String query, final boolean retry) {
     
    PreparedStatement statement;
    try {
    if (!isConnected()) initialize();
    statement = connection.prepareStatement(query);
    if (statement.execute())
    return new Result(statement, statement.getResultSet());
    } catch (final SQLException e) {
    final String msg = e.getMessage();
    log.severe("Database query error: " + msg);
    if (retry && msg.contains("_BUSY")) {
    log.severe("Retrying query...");
    plugin.getServer().getScheduler()
    .scheduleSyncDelayedTask(plugin, new Runnable() {
    @Override
    public void run() {
    query(query);
    }
    }, 20);
    }
    }
    if (statement != null) statement.close();
    return null;
    }
    }
     
     
     
    
     
Thread Status:
Not open for further replies.

Share This Page