Задача написания класса расширенного пула соединений с БД, была поставлена в связи с тем, что стандартный пул работал некорректно. При вызове метода getConnection() и всех занятых соединениях пула, пул не обрабатывал запрос, т.е. не выдавал соединения и запрос утрачивал силу. Необходимо было расширить класс пула, для того чтобы все запросы на соединения выполнялись.
Для решения поставленной задачи я решил дополнить класс очередью отложенных действий, а также самостоятельно выдавать и забирать соединения и следить за их количеством и состоянием.
Суть очереди отложенных действий состоит в том, что у нас запросы на соединение выполняются потоками и при отсутствии доступного соединения, поток переходит в состояние ожидания и становятся в очередь. Также есть еще один поток, который обрабатывает запросы в очереди, при появлении нового соединения. Для того чтобы не загружать выделенную память поток на время отсутствия запросов находиться в режиме ожидания.
С помощью написанного клиентского приложения, которое с помощью нескольких потоков отправляло запросы на соединение, я смог протестировать работоспособность написанного класса. Класс работал корректно, а при больших тестах выполнял работу за приемлемое время. Задание было зачтено.
Заключение.
В ходе прохождения производственно практики, мною были выполнены все поставленные задачи и достигнуты цели. По итогам практики были закреплены полученные знания в ходе обучения в университете, изучены новые технологии и получен опыт работы на предприятии. По окончанию практики получен положительный отзыв от руководителя практики. По результатам практики я был принят в компанию на постоянную работу с испытательным сроком.
Список литературы:
1. Арнолд, Гослинг, Холмс. Язык программирования Java. Вильямс, 2001.
2. Хабибуллин И. Самоучитель Java. - СПб, БХВ 2008.
3. Документация, справочники, руководства, дистрибутивы Java. [Online] http://java.sun.com
4. Взаимодействие с базой данных через JDBC [Online] http://citforum.ru/database/oracle/java_oracle_data/
Приложение 1.
Код приложение для лицензирования.
import com.macrovision.flexlm.FeatureSpecifier;
import com.macrovision.flexlm.FlexlmException;
import com.macrovision.flexlm.License;
import com.macrovision.flexlm.LicenseSource;
import com.macrovision.flexlm.VendorInfo;
import com.macrovision.flexlm.licsource.LicenseServer;
public class LicenseFlexNet {
// занять 1 лицензию и вернуть ее объект пользвателю или null если
произошел сбой
public static FlexlmException LastError;
static int errOk = 0;
static int errKey = 1;
static int errHostId = 2;
static int errBeforeStart = 3;
static int errExpired = 4;
static int errNotFound = 10;// (в файле нет строки для нашего
приложения и версии)
static int errOpenFile = 11;
static int errNoMoreLicenses = 21; //(лицензии кончились)
public static Object checkout(String licenseFileName, String app, String
version)
{
License lc = null;
try
{
FeatureSpecifier fs = new FeatureSpecifier(app, version);
VendorInfo vf = new GEOLIDERInfo();
lc = new License(fs, licenseFileName, vf, null);
lc.checkout(1);
}
catch (FlexlmException e)
{
LastError = e;
System.out.print(e.getMessage());
lc = null;
}
return lc;
}
/** освободить лицензию*/
public static boolean checkin(String licenseFileName, String app, String
version, Object
license)
{
License lc = null;
lc = (License)license;
try
{
lc.checkin();
}
catch(FlexlmException e)
{
LastError = e;
return true;
}
return false;
}
public static String GetLastError()
{
switch (LastError.getMajor())
{
case 0:
return String.valueOf(errOk);
case -44:
return String.valueOf(errKey);
case -503:
return String.valueOf(errHostId);
case -15:
return String.valueOf(errBeforeStart);
case -50:
return String.valueOf(errExpired);
case -1:
return String.valueOf(errNotFound);
case -30:
return String.valueOf(errOpenFile);
case -101:
return String.valueOf(errNoMoreLicenses);
default: return "";
}
}
public static int getUsedLicQuantity(String licenseFileName, String app,
String version)
{
License lc = null;
int res = -1;
try
{
FeatureSpecifier fs = new FeatureSpecifier(app, version);
VendorInfo vf = new GEOLIDERInfo();
lc = new License(fs, licenseFileName, vf, null);
res = lc.getCount();
}
catch (FlexlmException e)
{
LastError = e;
}
return res;
}
public static final String defPath = "@localhost&license.lic";
public static final String defVersion = "1.000";
public static final void main(String arg[])
{
if (arg.length < 1)
{
System.out.print("Incorrect parametrs");
System.exit(1);
}
String LicName = arg.length > 2? arg[2]: defPath;
String ver = arg.length > 1? arg[1]: defVersion;
String app = arg[0];
Object lic = checkout(LicName, app, ver);
if (lic!= null)
{
System.out.print("yes");
//checkin(LicName, app, ver, lic);
}
else
{
System.out.print("no");
}
}
}
Приложение 2.
Класс приложения расширенного пула.
import java.sql.*;
import java.util.LinkedList;
import java.util.Properties;
import oracle.jdbc.pool.OracleConnectionCache;
import oracle.jdbc.pool.OracleConnectionCacheCallback;
import oracle.jdbc.pool.OracleConnectionCacheManager;
import oracle.jdbc.pool.OracleConnectionPoolDataSource;
import oracle.jdbc.pool.OracleDataSource;
import oracle.jdbc.driver.*;
public class Pool
{
//Thread for queue actions
private class ThreadGetConnection implements Runnable
{
public Object t1,t2;
public ThreadGetConnection(Object f1, Object f2)
{
t1 = f1; t2 = f2;
}
@Override
public void run()
{
synchronized (t1)
{
try
{
t1.wait();
}
catch (InterruptedException e)
{
System.out.println(e.getMessage());
}
}
synchronized (t2) {
t2.notifyAll();
}
}
}
//processor queue actions
private class PoolWorker extends Thread
{
public void run() {
Object r;
while (true) {
synchronized(queue) {
while (queue.isEmpty() || MaxLimitConnection -
CountActive == 0)
{
try{
queue.wait();
}catch (InterruptedException ignored){ }
}
r = queue.removeFirst();
}
synchronized (r)
{
CountActive++;
r.notifyAll();
}
}
}
}
public String defUser = "administrator";
public String defPass = "";
public String defHost = "xeon";
public String defPort = "1521";
public String defService = "PVIV";
public int INF = 100;
private OracleDataSource ods = null;
private int MaxLimitConnection;
private int MinLimitConnection;
private int CountInitConnection;
private int MaxLimitStatment;
private Connection []Conns;
private int[] Used;
private int[] CountUsed;
public int CountAlive;
public int CountActive;
private LinkedList<Object> queue = new LinkedList<Object>();
private PoolWorker pw;
public Pool()
{
ods = null;
}
public Pool(String[] args, int[] args2)
{
String User = args.length > 0? args[0]: defUser;
String Pass = args.length > 1? args[1]: defPass;
String Host = args.length > 2? args[2]: defHost;
String Port = args.length > 3? args[3]: defPort;
String Service = args.length > 4? args[4]: defService;
String url = "jdbc:oracle:thin:" + "@//" + Host + ":" + Port
+ "/" + Service;
MaxLimitConnection = args2.length > 0? args2[0]: INF;
MinLimitConnection = args2.length > 1? args2[1]: 0;
CountInitConnection = args2.length > 2? args2[2]: 0;
MaxLimitStatment = args2.length > 3? args2[3]: INF;
try
{
ods = new OracleDataSource();
ods.setURL(url);
if (Pass == "")
{
Properties props = new Properties();
props.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_VSESSION_OSUSER,
User);
ods.setConnectionProperties(props);
}
else
{
ods.setUser(User);
ods.setPassword(Pass);
}
Conns = new Connection[MaxLimitConnection];
Used = new int[MaxLimitConnection];
CountUsed = new int[MaxLimitConnection];
for (int i=0; i<CountInitConnection; i++)
Conns[i] = ods.getConnection();
CountAlive = CountInitConnection;
CountActive = 0;
pw = new PoolWorker();
pw.start();
}
catch (SQLException e)
{
System.out.println(e.getMessage());
}
}
private synchronized Connection getNewConnection()
{
try
{
for (int i=0; i<MaxLimitConnection; i++)
if (Conns[i]!= null && Used[i] == 0)
{
Used[i] = 1;
CountUsed[i]++;
return Conns[i];
}
for (int i=0; i<MaxLimitConnection; i++)
if (Conns[i] == null)
{
Conns[i] = ods.getConnection();
Used[i] = 1;
CountUsed[i]++;
CountAlive++;
return Conns[i];
}
}
catch (SQLException e) {
System.out.println(e.getMessage());
}
return null;
}
public Connection getConnection()
{
Object f1 = new Object();
Object f2 = new Object();
ThreadGetConnection tgc = new ThreadGetConnection(f1,f2);
new Thread(tgc).start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
synchronized (queue)
{
queue.addLast(f1);
queue.notifyAll();
}
synchronized (f2)
{
try
{
f2.wait();
}
catch (InterruptedException e)
{
System.out.println(e.getMessage());
}
}
return getNewConnection();
}
public synchronized Connection releaseConnection(Connection cn)
{
try
{
for (int i=0; i<MaxLimitConnection; i++)
if (Conns[i] == cn)
{
Used[i] = 0;
if (CountUsed[i] == MaxLimitStatment &&
CountAlive > MinLimitConnection)
{
CountUsed[i] = 0;
Conns[i].close();
Conns[i] = null;
}
CountActive--;
break;
}
}
catch (SQLException e) {
System.out.println(e.getMessage());
}
synchronized (queue)
{
queue.notifyAll();
}
return null;
}
public String getInfo()
{
String res = "";
res += MaxLimitConnection + " максимальное " +
MinLimitConnection + " минимальное количество поддерживаемых соединений\n";
res += CountAlive + " всего соединений из них: ";
res += CountActive + " активных и " + (CountAlive -
CountActive) + " доступных\n";
return res;
}
@SuppressWarnings("deprecation")
public void close()
{
pw.stop();
for (int i = 0; i < Conns.length; i++)
try {
if (Conns[i]!= null)
Conns[i].close();
} catch (SQLException e) {
System.out.println(e.getMessage());
queue.clear();
}
}
}