分享自己写的db4o 连接池

初步实现,如有问题欢迎拍砖。

package com.glt.table.db4oUtil;

import java.util.LinkedList;

import org.apache.log4j.Logger;

import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectServer;
import com.db4o.config.Configuration;

/**
* 必须实现connection pool,因为在web应用中,servlet必定是多线程的。
* 1. 支持多客户端;
* 2. 事务必须手工commit;
* 3. 一个JVM中只能同时连接一个数据库。
* 4. 使用reset()更改参数。
*
* @author guolt
*/
public class Db4oCP {
private static final Logger log = Logger
.getLogger("com.glt.table.db4oUtil");
//数据库文件路径
private static String DATAFILE = "data/tableBuying.yap";
//连接池最小保持数
private static int MIN = 5;
//连接池最大保持数
private static int MAX = 10;
// 当前已经被获取使用的连接个数
private static int counts = 0;

//存放ObjectContainer对象
private static LinkedList connectionList=null;

private static ObjectServer objectServer = null;

// must be static 否则不会主动运行,不会在static 方法之前运行
static{
try {
init();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 初始化Connection Pool中的Db4o的连接
* @throws Exception
*/
private static void init() throws Exception {
try {
connectionList=new LinkedList();
if(DATAFILE==null ||MIN==MAX){
log.error("Db4oCP initi faild, Please check configuration...");
System.exit(-1);
}
objectServer = Db4o.openServer(DATAFILE, 0);
Configuration cfg=Db4o.configure();
log.info("Db4o configuration: activationDepth:"+cfg.activationDepth());
//Db4o级联保存设置
//The default setting is 1: Only the object passed to ObjectContainer.set(java.lang.Object) will be updated.
//In client-server environment this setting should be used on both client and server sides
Db4o.configure().updateDepth(1);
for (int i = 0; i < MIN; i++) {
// 放在末尾
connectionList.add(objectServer.openClient());
}
} catch (Exception e) {
throw new Exception("Db4o init Faild");
}
log.info("Db4oCP init OK[DataFile:"+DATAFILE + "|MIN:"+MIN +"|MAX:"+MAX+ "|Free:" + connectionList.size()+"]");
}

public synchronized static ObjectContainer getODBConnection() throws Exception {
if (connectionList == null) {
log.error("Db4oCP is null.");
}
while (connectionList.isEmpty()) {
// 如果在MIX,MAX之间仍然创建并返回;否则出错。
if (counts < MAX) {
log.debug("DB4oCP free over MIN ,now new One CP..");
connectionList.add(objectServer.openClient());
} else {
throw new Exception("DB4oCP over MAX.");
}
}
// 移除并返回此列表的第一个元素
ObjectContainer odb = (ObjectContainer) connectionList.removeFirst();
counts++;
log.info("Db4oCP getODBConnection OK[used:" + counts + " |MAX:" + MAX + "|Free:" + connectionList.size()+"]");
return odb;
}

/**
* 释放,回收连接。
*/
public synchronized static void release(ObjectContainer odb) {
if(odb==null){
return;
}
counts--;
connectionList.add(odb);
log.info("Db4oCP release OK[used:" + counts + "|MAX:"+MAX+"|Free:"
+ connectionList.size()+"]");
//must set null ,or else be conflict.
odb=null;
}

/**
* 关闭数据库连接池
* @deprecated 调用会产生不可预料结果
* */
public static void cloesDB(){
connectionList=null;
counts=0;
objectServer.close();
}

/**
* 重置数据库连接池
* */
public static void reset(String dataFile,int min,int max){
DATAFILE=dataFile;
MIN=min;
MAX=max;
connectionList=null;
counts=0;
objectServer.close();
try {
init();
log.info("Db4oCP reset OK[DataFile:"+DATAFILE + "|MIN:"+MIN +"|MAX:"+MAX+ "|Free:" + connectionList.size()+"]");
} catch (Exception e) {
e.printStackTrace();
}
}

}

线程测试类:
public class Db4oCPTest extends TestCase {
private static final Logger log=Logger.getLogger("com.glt.table.test");
protected void setUp() throws Exception {
super.setUp();
}

protected void tearDown() throws Exception {
super.tearDown();
}

public void testGetODBConnection() {
Db4oCP.reset("data/sb.yap",5,10);
for(int i=0;i<17;i++){
Thread thread=new Thread(new Db4oClient(i));
thread.start();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//必须sleep,否则
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main test over");
//下面是关闭数据库连接池的,不要调用,因为下面的方法可能会先于线程而调用!!!
//Db4oCP.cloesDB();
}

}

package com.glt.table.test;

import org.apache.log4j.Logger;

import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.glt.table.db4oUtil.Db4oCP;
import com.glt.test.util.bean.Car;
import com.glt.test.util.bean.Person;

public class Db4oClient implements Runnable {
private static final Logger log=Logger.getLogger("com.glt.table.test");
private long wait;


public Db4oClient(long wait) {
super();
this.wait = wait;
}

/**
* @return the wait
*/
public long getWait() {
return wait;
}

/**
* @param wait the wait to set
*/
public void setWait(long wait) {
this.wait = wait;
}

public void run() {

ObjectContainer odb=null;
try {
odb=Db4oCP.getODBConnection();
Person person=new Person();
person.setName("name_"+wait);
Car car1=new Car();
car1.setDesc("XXX");
person.setCar(car1);
//odb.set(new StringBuffer("Hello, i'am waiting for "+wait));
odb.set(person);
odb.commit();

log.debug("thread:"+this+" sleep :"+wait);
Thread.sleep(wait);

ObjectSet objectset=odb.get(Person.class);
log.debug(this+"result.size:"+objectset.size());
while(objectset.hasNext()){
log.debug(this+" |"+objectset.next().toString());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Db4oCP.release(odb);
}
}

}

INFO - Db4o configuration: activationDepth:5
INFO - Db4oCP init OK[DataFile:data/tableBuying.yap|MIN:5|MAX:10|Free:5]
INFO - Db4o configuration: activationDepth:5
INFO - Db4oCP init OK[DataFile:data/sb.yap|MIN:5|MAX:10|Free:5]
INFO - Db4oCP reset OK[DataFile:data/sb.yap|MIN:5|MAX:10|Free:5]
INFO - Db4oCP getODBConnection OK[used:1 |MAX:10|Free:4]
INFO - Db4oCP getODBConnection OK[used:2 |MAX:10|Free:3]
INFO - Db4oCP getODBConnection OK[used:3 |MAX:10|Free:2]
INFO - Db4oCP getODBConnection OK[used:4 |MAX:10|Free:1]
INFO - Db4oCP getODBConnection OK[used:5 |MAX:10|Free:0]
DEBUG - DB4oCP free over MIN ,now new One CP..
INFO - Db4oCP getODBConnection OK[used:6 |MAX:10|Free:0]
DEBUG - DB4oCP free over MIN ,now new One CP..
DEBUG - thread:com.glt.table.test.Db4oClient@29e357 sleep :2
DEBUG - thread:com.glt.table.test.Db4oClient@ca470 sleep :0
DEBUG - thread:com.glt.table.test.Db4oClient@1ffc686 sleep :4
DEBUG - thread:com.glt.table.test.Db4oClient@1a082e2 sleep :3
DEBUG - thread:com.glt.table.test.Db4oClient@1f297e7 sleep :1
INFO - Db4oCP getODBConnection OK[used:7 |MAX:10|Free:0]
DEBUG - DB4oCP free over MIN ,now new One CP..
DEBUG - thread:com.glt.table.test.Db4oClient@14e3f41 sleep :5
INFO - Db4oCP getODBConnection OK[used:8 |MAX:10|Free:0]
DEBUG - DB4oCP free over MIN ,now new One CP..
DEBUG - com.glt.table.test.Db4oClient@ca470result.size:25
DEBUG - com.glt.table.test.Db4oClient@29e357result.size:25
DEBUG - com.glt.table.test.Db4oClient@1a082e2result.size:26
DEBUG - com.glt.table.test.Db4oClient@1f297e7result.size:26
DEBUG - thread:com.glt.table.test.Db4oClient@476128 sleep :6
INFO - Db4oCP getODBConnection OK[used:9 |MAX:10|Free:0]
DEBUG - DB4oCP free over MIN ,now new One CP..
DEBUG - com.glt.table.test.Db4oClient@1ffc686result.size:26
DEBUG - thread:com.glt.table.test.Db4oClient@164dbd5 sleep :7
DEBUG - com.glt.table.test.Db4oClient@ca470 |[Person:name_1|car:][Car:XXX|]
INFO - Db4oCP getODBConnection OK[used:10 |MAX:10|Free:0]
DEBUG - com.glt.table.test.Db4oClient@29e357 |[Person:name_1|car:][Car:XXX|]
java.lang.Exception: DB4oCP over MAX.
at com.glt.table.db4oUtil.Db4oCP.getODBConnection(Db4oCP.java:85)
at com.glt.table.test.Db4oClient.run(Db4oClient.java:39)
at java.lang.Thread.run(Thread.java:534)
java.lang.Exception: DB4oCP over MAX.
at com.glt.table.db4oUtil.Db4oCP.getODBConnection(Db4oCP.java:85)
at com.glt.table.test.Db4oClient.run(Db4oClient.java:39)
at java.lang.Thread.run(Thread.java:534)
DEBUG - com.glt.table.test.Db4oClient@1a082e2 |[Person:name_1|car:][Car:XXX|]
java.lang.Exception: DB4oCP over MAX.
at com.glt.table.db4oUtil.Db4oCP.getODBConnection(Db4oCP.java:85)
at com.glt.table.test.Db4oClient.run(Db4oClient.java:39)
at java.lang.Thread.run(Thread.java:534)
java.lang.Exception: DB4oCP over MAX.
at com.glt.table.db4oUtil.Db4oCP.getODBConnection(Db4oCP.java:85)
at com.glt.table.test.Db4oClient.run(Db4oClient.java:39)
at java.lang.Thread.run(Thread.java:534)
java.lang.Exception: DB4oCP over MAX.
at com.glt.table.db4oUtil.Db4oCP.getODBConnection(Db4oCP.java:85)
at com.glt.table.test.Db4oClient.run(Db4oClient.java:39)
at java.lang.Thread.run(Thread.java:534)
java.lang.Exception: DB4oCP over MAX.
at com.glt.table.db4oUtil.Db4oCP.getODBConnection(Db4oCP.java:85)
at com.glt.table.test.Db4oClient.run(Db4oClient.java:39)
at java.lang.Thread.run(Thread.java:534)
java.lang.Exception: DB4oCP over MAX.
at com.glt.table.db4oUtil.Db4oCP.getODBConnection(Db4oCP.java:85)
at com.glt.table.test.Db4oClient.run(Db4oClient.java:39)
at java.lang.Thread.run(Thread.java:534)
DEBUG - com.glt.table.test.Db4oClient@1f297e7 |[Person:name_1|car:][Car:XXX|]
DEBUG - com.glt.table.test.Db4oClient@14e3f41result.size:28
DEBUG - thread:com.glt.table.test.Db4oClient@1d95492 sleep :8

。。。。。。。。。。。。。。。。。。。。

[该贴被gltbeyond于2008-05-30 15:11修改过]

更新一下代码,时过3年,再次改写连接池:


package com.sdb.ebank.dbaccess;

import java.util.LinkedList;

import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectServer;
..............

/**
* Db4o Connection Pool,use C/S model
* @[author]author[/author] Guolt
* **/

public final class Db4oCP {

// private static final String DB4OCSFLAG = "C";//LianaStandard.getSelfDefineSettingsValue("db4oCSFlag");
// private static final String Db4oServerIP ="10.14.36.27";// LianaStandard.getSelfDefineSettingsValue("db4oServerIP");
// private static final int Db4oServerPort = 30001;//Integer.parseInt(LianaStandard.getSelfDefineSettingsValue("db4oServerPort"));
// private static String DATAFILE ="D:/db4o.yap."+System.currentTimeMillis(); // LianaStandard.getSelfDefineSettingsValue("tempDownloadDir")+ "/db4o.yap";

private static final String DB4OCSFLAG = LianaStandard.getSelfDefineSettingsValue(
"db4oCSFlag");
private static final String Db4oServerIP = LianaStandard.getSelfDefineSettingsValue(
"db4oServerIP");
private static final int Db4oServerPort = Integer.parseInt(LianaStandard.getSelfDefineSettingsValue(
"db4oServerPort"));
private static String DATAFILE = LianaStandard.getSelfDefineSettingsValue(
"tempDownloadDir")+ "/db4o.yap."+System.currentTimeMillis();


private static final String _DEFAULT_DATAFILE =
"db4o.yap."+System.currentTimeMillis();
//perServer,perClient connection size.
private static int MIN = 1;
private static int MAX = 10;

private static int counts = 0;

private static LinkedList connectionList = new LinkedList();

private static ObjectServer objectServer = null;

private static void init() throws Exception {
try {
cloesDB();
counts = 0;
//cascadeOnUpdate cascadeOnDelete
Db4o.configure().objectClass(CacheV2Element.class).cascadeOnUpdate(true);
Db4o.configure().objectClass(CacheV2Element.class).cascadeOnDelete(true);

// Db4o.configure().objectClass(DataElement.class).cascadeOnUpdate(true);
// Db4o.configure().objectClass(DataElement.class).cascadeOnDelete(true);
//
// Db4o.configure().objectClass(KeyedCollection.class).cascadeOnUpdate(true);
// Db4o.configure().objectClass(KeyedCollection.class).cascadeOnDelete(true);

Trace.logDebug(Trace.COMPONENT_JDBC,
"Db4o.configure() cascadeOnUpdate cascadeOnDelete :true");

connectionList = new LinkedList();
DATAFILE = (DATAFILE == null) ? _DEFAULT_DATAFILE : DATAFILE;
if (DB4OCSFLAG.equalsIgnoreCase(
"S")) {
// server model
objectServer = Db4o.openServer(DATAFILE, 30001);
objectServer.grantAccess(
"db4o", "db4o");
}

} catch (Exception e) {
Trace.logError(Trace.COMPONENT_JDBC,
"Db4oCP init Error."
+ e.getMessage());
e.printStackTrace();
}

try{

for (int i = 0; i < MIN; i++) {
ObjectContainer container = Db4o.openClient(Db4oServerIP,
Db4oServerPort,
"db4o", "db4o");
connectionList.add(container);
}

}catch(Exception e){}


Trace.logWarn(Trace.COMPONENT_JDBC,
"Db4oCP init OK.[DB4OCSFLAG:"+DB4OCSFLAG+",Db4oServerIP:"+Db4oServerIP+"|Port:"+Db4oServerPort+"|DataFile:"
+ DATAFILE +
"|MIN:" + MIN + "|MAX:" + MAX + "|Free:"
+ connectionList.size() +
"]");
}

/**
* 获取连接池中的ObjectContainer对象。
* */

public static synchronized ObjectContainer getODBConnection()
throws Exception {
if (connectionList == null) {
Trace.logError(Trace.COMPONENT_JDBC,
"Db4oCP is null.");
throw new Exception(
"db4o connectionList is null!");
}
//连接池空了,并且当前申请的未超MAX值。
if ( connectionList.isEmpty() && counts < MAX ) {
Trace.logInfo(Trace.COMPONENT_JDBC,
"DB4oCP available 0,And not excess MAX:"+MAX+",now new One CP..");
connectionList.add(Db4o.openClient(Db4oServerIP,
Db4oServerPort,
"db4o", "db4o"));// add where ?
}else if(connectionList.isEmpty() && counts >= MAX){
//当前申请的超MAX值
Trace.logError(Trace.COMPONENT_JDBC,
"Db4oCP available 0, And over MAX="+MAX);
throw new Exception(
"Db4oCP is over MAX="+MAX);
}

// 从linkedList头部获取一个objectContainer实例
ObjectContainer odb = (ObjectContainer) connectionList.removeFirst();
counts += 1;
// Trace.logDebug(Trace.COMPONENT_JDBC,
// "Db4oCP getODBConnection OK[hashCode:"
// + odb.hashCode() + "|used:" + counts + " |MAX:" + MAX
// + "|Free:" + connectionList.size() + "]");
return odb;
}

public static synchronized void release(ObjectContainer odb) {
if (odb == null) {
return;
}
counts -= 1;
connectionList.add(odb);
// Trace.logDebug(Trace.COMPONENT_JDBC, "Db4oCP release OK[used:" + counts
// + "|MAX:" + MAX + "|Free:" + connectionList.size() + "]");

odb = null;
}

/** @deprecated */
public static void cloesDB() {
try {
connectionList = null;
counts = 0;
if (objectServer != null) {
objectServer.close();
}

Trace.logDebug(Trace.COMPONENT_JDBC,
"db4o connection closed..");
} catch (Exception e) {
Trace.logError(Trace.COMPONENT_JDBC,
"db4o connection closed,ERROR"
+ e.getMessage());
}

}

public static void reset(String dataFile, int min, int max) {
try {
DATAFILE = dataFile;
MIN = min;
MAX = max;
cloesDB();

init();
Trace.logDebug(Trace.COMPONENT_JDBC,
"Db4oCP reset OK[DataFile:"
+ DATAFILE +
"|MIN:" + MIN + "|MAX:" + MAX + "|Free:"
+ connectionList.size() +
"]");
} catch (Exception e) {
e.printStackTrace();
}
}

/** @deprecated */
public static void refreshx(Object object, int deepth) {
for (int i = 0; i < connectionList.size(); ++i) {
ObjectContainer odb = (ObjectContainer) connectionList.get(i);
Trace.logDebug(Trace.COMPONENT_JDBC,
"refresh |odb:"
+ odb.hashCode() +
"|object:" + object);
odb.ext().refresh(object, deepth);
}
}

static {
try {
init();
} catch (Exception e) {
e.printStackTrace();
}
}

public static void test(){

}
}



[该贴被gltbeyond于2011-05-26 14:43修改过]

如果对象有复合成员变量,必须cascadeOnUpdate,cascadeOnDelete !!!

//cascadeOnUpdate cascadeOnDelete 如果对象有复合成员变量,必须cascadeOnUpdate,cascadeOnDelete !!!
Db4o.configure().objectClass(CacheV2Element.class).cascadeOnUpdate(true);
Db4o.configure().objectClass(CacheV2Element.class).cascadeOnDelete(true);
Db4o.configure().objectClass(PAFileNameTxInfo.class).cascadeOnDelete(true);
Db4o.configure().objectClass(PAFileNameTxInfo.class).cascadeOnUpdate(true);
Db4o.configure().objectClass(TranStatInfo.class).cascadeOnUpdate(true);