Allot of fixes

This commit is contained in:
Ziver Koc 2010-04-15 20:52:34 +00:00
parent 694e3081bb
commit 952a388cf1
22 changed files with 1197 additions and 408 deletions

View file

@ -0,0 +1,261 @@
package zutil.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DBConnection{
public enum DBMS{
MySQL
}
// The connection
private Connection conn = null;
// The pool that this connection belongs to
private DBConnectionPool pool;
/**
* Creates an Connection from JNDI
*
* @param jndi the name of the connection, e.g. "jdbc/mysql"
*/
public DBConnection(String jndi) throws NamingException, SQLException{
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/"+jndi);
conn = ds.getConnection();
}
/**
* Creates an Connection to a MySQL server
*
* @param url is the URL of the MySQL server
* @param db is the database to connect to
* @param user is the user name
* @param password is the password
*/
public DBConnection(String url, String db, String user, String password) throws Exception{
this(DBMS.MySQL, url, db, user, password);
}
/**
* Creates an Connection to a DB server
*
* @param dbms is the DB type
* @param url is the URL of the MySQL server
* @param db is the database to connect to
* @param user is the user name
* @param password is the password
*/
public DBConnection(DBMS dbms, String url, String db, String user, String password) throws Exception{
String dbms_name = initDriver(dbms);
conn = DriverManager.getConnection ("jdbc:"+dbms_name+"://"+url+"/"+db, user, password);
}
/**
* @return the underlying connection
*/
public Connection getConnection(){
return conn;
}
/**
* Initiates the DB driver and returns its protocol name.
*
* @param db is the DB type
* @return the protocol name of the DBMS
*/
public String initDriver(DBMS db) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
switch(db){
case MySQL:
Class.forName ("com.mysql.jdbc.Driver").newInstance();
DriverManager.setLoginTimeout(10);
return "mysql";
}
return null;
}
/**
* @return the last inserted id or -1 if there was an error
*/
public int getLastInsertID() throws SQLException{
Statement s = null;
try{
s = conn.createStatement ();
s.executeQuery("SELECT LAST_INSERT_ID()");
ResultSet result = s.getResultSet();
if(result.next()){
return result.getInt(1);
}
}finally{
if(s!=null)
s.close();
}
return -1;
}
/**
* Runs a Prepared Statement.<br>
* <b>NOTE:</b> Don't forget to close the PreparedStatement or it can lead to memory leaks
*
* @param sql is the SQL query to run
* @return An PreparedStatement
*/
public PreparedStatement getPreparedStatement(String sql) throws SQLException{
return conn.prepareStatement(sql);
}
/**
* <b>NOTE:</b> Don't forget to close the Statement or it can lead to memory leaks
*
* @return an Statement for the DB
*/
public Statement getStatement() throws SQLException{
return conn.createStatement();
}
/**
* Executes an query and cleans up after itself.
*
* @param query is the query
* @return update count or -1 if the query is not an update query
*/
public int exec(String query) throws SQLException {
PreparedStatement stmt = getPreparedStatement( query );
return exec(stmt);
}
/**
* Executes an query and cleans up after itself.
*
* @param stmt is the query
* @return update count or -1 if the query is not an update query
*/
public static int exec(PreparedStatement stmt) throws SQLException {
return exec(stmt, new SQLResultHandler<Integer>(){
public Integer handle(Statement stmt, ResultSet result) {
try {
return stmt.getUpdateCount();
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
});
}
/**
* Executes an query and cleans up after itself.
* @param <T>
*
* @param query is the query
* @param handler is the result handler
* @return update count or -1 if the query is not an update query
*/
public <T> T exec(String query, SQLResultHandler<T> handler) throws SQLException {
PreparedStatement stmt = getPreparedStatement( query );
return exec(stmt, handler);
}
/**
* Executes an query and cleans up after itself.
*
* @param stmt is the query
* @param handler is the result handler
* @return the object from the handler
*/
public static <T> T exec(PreparedStatement stmt, SQLResultHandler<T> handler) throws SQLException{
try{
// Execute
stmt.execute();
// Handle result
if( handler != null ){
ResultSet result = null;
try{
result = stmt.getResultSet();
return handler.handle(stmt, result);
}finally{
if(result != null){
try {
result.close();
} catch (SQLException e) { }
result = null;
}
}
}
// Cleanup
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlex) { }
stmt = null;
}
}
return null;
}
/**
* Sets the pool that this connection belongs to
*
* @param pool is the pool
*/
protected void setPool(DBConnectionPool pool){
if( pool != null )
pool.removeConnection(this);
this.pool = pool;
}
/**
* Checks if the DB Connection is valid and functioning
*
* @return true or false depending on the validity of the connection
*/
public boolean valid(){
boolean ret = true;
try {
conn.getMetaData();
ret = ret && !conn.isClosed();
}catch (Exception e) {
return false;
}
return ret;
}
/**
* Disconnects from the database or releases the connection back to the pool
*/
public void close() throws SQLException{
if(pool!=null){
pool.releaseConnection(this);
}
else{
forceClose();
}
}
/**
* Disconnects from the database
*/
public void forceClose(){
if (conn != null) {
try {
conn.close();
} catch (SQLException sqlex) {
sqlex.printStackTrace();
}
conn = null;
}
}
public boolean equals(Object o){
return conn.equals(o);
}
}

View file

@ -0,0 +1,174 @@
package zutil.db;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import zutil.db.DBConnection.DBMS;
/**
* This class is an connection pool
*
* @author Ziver
*/
public class DBConnectionPool extends TimerTask {
public static final long DEFAULT_TIMEOUT = 10*60*60*1000; // 10 minutes;
public static final int DEFAULT_MAX_SIZE = 5;
// DB details
private DBMS dbms;
private String url;
private String db;
private String user;
private String password;
// Pool details
private int max_conn;
private long timeout;
private Timer timeout_timer;
protected class PoolItem{
public DBConnection conn;
public long timestamp;
public boolean equals(Object o){
return conn.equals(o);
}
}
// The pool
private LinkedList<PoolItem> inusePool;
private LinkedList<PoolItem> readyPool;
/**
* Creates a new pool of DB connections
*
* @param dbms is the DB type
* @param url is the URL to the DB
* @param db is the name of the database
* @param user is the user name to the DB
* @param password is the password to the DB
*/
public DBConnectionPool(DBMS dbms, String url, String db, String user, String password) throws Exception{
this.dbms = dbms;
this.url = url;
this.db = db;
this.user = user;
this.password = password;
inusePool = new LinkedList<PoolItem>();
readyPool = new LinkedList<PoolItem>();
this.setTimeout(DEFAULT_TIMEOUT);
this.setMaxSize(DEFAULT_MAX_SIZE);
}
/**
* Registers a Connection to the pool
*
* @param conn is the Connection to register
*/
protected void addConnection(DBConnection conn){
PoolItem item = new PoolItem();
item.conn = conn;
readyPool.addLast(item);
}
/**
* Removes an connection from the pool
*
* @param conn is the connection to remove
*/
protected void removeConnection(DBConnection conn){
inusePool.remove(conn);
readyPool.remove(conn);
}
/**
* Lease one connection from the pool
*
* @return an DB connection or null if the pool is empty
*/
public synchronized DBConnection getConnection() throws Exception{
if(readyPool.isEmpty()){
if( size() < max_conn ){
DBConnection conn = new DBConnection(dbms, url, db, user, password);
conn.setPool( this );
addConnection( conn );
return conn;
}
return null;
}
else{
PoolItem item = readyPool.poll();
inusePool.addLast(item);
item.timestamp = System.currentTimeMillis();
return item.conn;
}
}
/**
* Registers the Connection as not used
*
* @param conn is the connection that is not used anymore
*/
protected synchronized void releaseConnection(DBConnection conn){
int index = inusePool.indexOf(conn);
PoolItem item = inusePool.remove(index);
readyPool.addLast(item);
}
/**
* @return the current size of the pool
*/
public int size(){
return inusePool.size() + readyPool.size();
}
/**
* Closes all the connections
*/
public synchronized void close() throws SQLException{
for( PoolItem item : inusePool ){
item.conn.forceClose();
}
inusePool.clear();
for( PoolItem item : readyPool ){
item.conn.forceClose();
}
readyPool.clear();
}
/**
* Set the max size of the pool
*/
public void setMaxSize(int max){
this.max_conn = max;
}
/**
* Sets the timeout of the Connections
*/
public synchronized void setTimeout(long timeout){
this.timeout = timeout;
if(timeout_timer!=null)
timeout_timer.cancel();
timeout_timer = new Timer();
timeout_timer.schedule(this, 0, timeout / 2);
}
/**
* Checks every DB connection if they are valid and has not timed out
*/
public void run(){
long stale = System.currentTimeMillis() - timeout;
for(PoolItem item : inusePool){
if( !item.conn.valid() && stale > item.timestamp ) {
removeConnection(item.conn);
item.conn.forceClose();
}
}
}
}

View file

@ -3,6 +3,7 @@ package zutil.db;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.Iterator;
import java.util.Queue;
@ -21,29 +22,28 @@ import zutil.converters.Converter;
* @author Ziver
*
*/
public class MySQLQueue<E> implements Queue<E>{
public class DBQueue<E> implements Queue<E>{
// GO TO KNOW = SELECT LAST_INSERT_ID() as pos_id
private MySQLConnection db;
private DBConnection db;
private String table;
/**
* Initiats the queue.
* WARNING!! this will erase all rows i the table
* @param db The connection to the db
* @param table The name of the table
* @throws SQLException
* Initiates the queue.<br>
* <b>WARNING!!<b> this will erase all rows in the table
*
* @param db is the connection to the DB
* @param table is the name of the table
*/
public MySQLQueue(MySQLConnection db, String table){
public DBQueue(DBConnection db, String table){
this.db = db;
this.table = table;
}
public boolean add(Object arg0){
try {
PreparedStatement sql = db.prepareStatement("INSERT INTO "+table+" (data) VALUES(?)");
PreparedStatement sql = db.getPreparedStatement("INSERT INTO "+table+" (data) VALUES(?)");
sql.setObject(1, arg0);
sql.executeUpdate();
sql.close();
DBConnection.exec(sql);
} catch (Exception e) {
e.printStackTrace(MultiPrintStream.out);
return false;
@ -56,18 +56,23 @@ public class MySQLQueue<E> implements Queue<E>{
}
public boolean offer(Object arg0) {
// TODO Auto-generated method stub
return false;
return add(arg0);
}
@SuppressWarnings("unchecked")
public synchronized E peek() {
try {
ResultSet rs = db.query("SELECT * FROM "+table+" LIMIT 1");
if (rs.next()) {
return (E) Converter.toObject(rs.getBytes("data"));
}
rs.getStatement().close();
return db.exec("SELECT * FROM "+table+" LIMIT 1", new SQLResultHandler<E>(){
public E handle(Statement stmt, ResultSet rs) throws SQLException{
if (rs.next())
try {
return (E) Converter.toObject(rs.getBytes("data"));
} catch (Exception e) {
e.printStackTrace(MultiPrintStream.out);
}
return null;
}
});
} catch (Exception e) {
e.printStackTrace(MultiPrintStream.out);
}
@ -77,12 +82,19 @@ public class MySQLQueue<E> implements Queue<E>{
@SuppressWarnings("unchecked")
public synchronized E poll() {
try {
ResultSet rs = db.query("SELECT * FROM "+table+" LIMIT 1");
if (rs.next()) {
db.updateQuery("DELETE FROM "+table+" WHERE id="+rs.getInt("id")+" LIMIT 1");
return (E) Converter.toObject(rs.getBytes("data"));
}
rs.getStatement().close();
return db.exec("SELECT * FROM "+table+" LIMIT 1", new SQLResultHandler<E>(){
public E handle(Statement stmt, ResultSet rs) {
try{
if (rs.next()) {
db.exec("DELETE FROM "+table+" WHERE id="+rs.getInt("id")+" LIMIT 1");
return (E) Converter.toObject(rs.getBytes("data"));
}
}catch(Exception e){
e.printStackTrace(MultiPrintStream.out);
}
return null;
}
});
} catch (Exception e) {
e.printStackTrace(MultiPrintStream.out);
}
@ -100,7 +112,7 @@ public class MySQLQueue<E> implements Queue<E>{
public void clear() {
try {
db.updateQuery("TRUNCATE TABLE `"+table+"`");
db.exec("TRUNCATE TABLE `"+table+"`");
} catch (SQLException e) {
e.printStackTrace(MultiPrintStream.out);
}
@ -108,11 +120,11 @@ public class MySQLQueue<E> implements Queue<E>{
public boolean contains(Object arg0) {
try {
ResultSet rs = db.query("SELECT data FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1");
if (rs.next()) {
return true;
}
rs.getStatement().close();
return db.exec("SELECT data FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1", new SQLResultHandler<Boolean>(){
public Boolean handle(Statement stmt, ResultSet rs) throws SQLException{
return rs.next();
}
});
} catch (Exception e) {
e.printStackTrace(MultiPrintStream.out);
}
@ -135,8 +147,7 @@ public class MySQLQueue<E> implements Queue<E>{
public synchronized boolean remove(Object arg0) {
try {
ResultSet rs = db.query("DELETE FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1");
rs.getStatement().close();
db.exec("DELETE FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1");
return true;
} catch (Exception e) {
e.printStackTrace(MultiPrintStream.out);
@ -156,11 +167,13 @@ public class MySQLQueue<E> implements Queue<E>{
public int size() {
try {
ResultSet rs = db.query("SELECT count(*) FROM "+table);
if (rs.next()) {
return rs.getInt(1);
}
rs.getStatement().close();
return db.exec("SELECT count(*) FROM "+table, new SQLResultHandler<Integer>(){
public Integer handle(Statement stmt, ResultSet rs) throws SQLException{
if (rs.next())
return rs.getInt(1);
return 0;
}
});
} catch (Exception e) {
e.printStackTrace(MultiPrintStream.out);
}

View file

@ -1,108 +0,0 @@
package zutil.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class MySQLConnection {
Connection conn = null;
/**
* Connects to a MySQL server
*
* @param url is the URL of the MySQL server
* @param db is the database to connect to
* @param user is the user name
* @param password is the password
*/
public MySQLConnection(String url, String db, String user, String password)
throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException{
Class.forName ("com.mysql.jdbc.Driver").newInstance();
DriverManager.setLoginTimeout(10);
conn = DriverManager.getConnection ("jdbc:mysql://"+url+"/"+db, user, password);
}
/**
* Runs a query and returns the result.<br>
* <b>NOTE:</b> Don't forget to close the ResultSet and the Statement or it
* can lead to memory leak: rows.getStatement().close();
*
* @param sql is the query to execute
* @return the data that the DB returned
*/
public synchronized ResultSet query(String sql) throws SQLException{
Statement s = conn.createStatement ();
s.executeQuery(sql);
return s.getResultSet();
}
/**
* Returns the first cell of the first row of the query
*
* @param sql is the SQL query to run, preferably with the LIMIT 1 at the end
* @return A SQL row if it exists or else null
*/
public synchronized String simpleQuery(String sql) throws SQLException{
Statement s = conn.createStatement ();
s.executeQuery(sql);
ResultSet result = s.getResultSet();
if(result.next()){
String tmp = result.getString(1);
result.close();
return tmp;
}
return null;
}
/**
* Runs a query in the MySQL server and returns effected rows
*
* @param sql is the query to execute
* @return the number of rows effected
*/
public synchronized int updateQuery(String sql) throws SQLException{
Statement s = conn.createStatement ();
int ret = s.executeUpdate(sql);
s.close();
return ret;
}
/**
* @return the last inserted id or -1 if there was an error
* @throws SQLException
*/
public int getLastInsertID() throws SQLException{
Statement s = conn.createStatement ();
s.executeQuery("SELECT LAST_INSERT_ID()");
ResultSet result = s.getResultSet();
if(result.next()){
int tmp = result.getInt(1);
result.close();
return tmp;
}
return -1;
}
/**
* Runs a Prepared Statement.<br>
* <b>NOTE:</b> Don't forget to close the PreparedStatement or it can lead to memory leak
*
* @param sql is the SQL query to run
* @return The PreparedStatement
*/
public synchronized PreparedStatement prepareStatement(String sql) throws SQLException{
return conn.prepareStatement(sql);
}
/**
* Disconnects from the database
*/
public synchronized void close() throws SQLException{
if (conn != null){
conn.close ();
}
}
}

View file

@ -0,0 +1,15 @@
package zutil.db;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
public interface SQLResultHandler<T> {
/**
* Is called to handle an result from an query.
*
* @param stmt is the query
* @param result is the ResultSet
*/
public T handle(Statement stmt, ResultSet result) throws SQLException;
}