曾几何时在linux编c语言的时候就会碰到数据库连接的难题,虽然用ODBC可以解决一些问题,但最新的数据库支持必须用JDBC或专用接口才行,而且如ORACLE这种数据库,要想实现远程连接的话,必须安装客户端,对软件的发行产生了一定难度。而JDBC就没有这问题,只要有相关的JDBC驱动就可以正常使用,对软件的成本控制起了一定的积极作用。它很像网络中的桥接器的功能,所以我管它叫JDBC桥接器。
ICE的出现使得这个问题得到了简化,至少不用去关心网络控制和客户端的程序实现语言,只要服务端与客户端用的都是ICE的协议,这个问题就很好解决。下面就这个问题的实现做进一步的讨论。
这个JDBC桥接器的作用是:接受各种数据请求,并通过相应的JDBC数据库驱动连接数据库,并把请求结果返回到客户端。不管这个客户端是在本地还是在网络中,数据库在本地还是在网络中,都可能实现数据的透明传输与应用。
首先我们要做的是,必须在JDBC桥接器所在的机器上开放一个端口,用来接受服务,客户端利用ICE协议向服务端发送请求,并取回操作结果。
有人说,你用的着这么麻烦嘛?用JAVA直接开发客户端不就行了吗?
这个想法应该在很多人心中存在,一个JAVA应用程序的安装也是很烦琐,除非你是BS结构的。这种只能用在JAVA语言身上,但如果我用c/c++开发了一个客户端,只是想用jdbc来操作数据库的话,上面的想法就没有可能实现。并且在跨平台和操作系统的的环境中开发客户端和服务端是一件头痛的事情。
有人说,你要是使用WebService不也可能达到这样的效果吗?请看<<网络服务平台的比较----ICE应用系列文章之一>>,在whhif.cublog.cn 可以找到。
在以上环境中,ICE可以避免以上这种种问题。
首先要开发一个slice脚本来定义服务。
module jdbcAgent
{
["java:type:java.util.ArrayList"] sequence <string> row;
["java:type:java.util.ArrayList"] sequence <row> table;
interface Operator
{
int connectDB(string driver,string disp,string host,string port,string db,string name,string pass);
bool insertSQL(string sql);
bool updateSQL(string sql);
bool deleteSQL(string sql);
table querySQL(string sql);
bool closeDB();
};
};
在windows下利用slice2java.exe jdbcAgent.ice生成服务。Linux下利用slice2java jdbcAgent.ice来生成服务。
定义服务的具体内容:
下面的函数与jdbcAgent.ice中所描述的服务是一样的,只是这里给出的是具体实现。只是几个数据库连接的常用功能,编缉ICE所生成的JAVA代码,最好使用eclipse,很方便。并没有定义异常。如果要了解具体实现意义,最好参考ICE的中文白皮书和我写的上一篇入门文章《一个简单的聊天室的实现----ICE应用系列文章之四》,在http://whhif.cublog.cn 可以找到。
package jdbcProxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import Ice.*;
import jdbcProxy.jdbcAgent.*;
public class jdbcAgentI extends _OperatorDisp {
public static ArrayList m_conn_list;
jdbcAgentI()
{
m_conn_list=new ArrayList();
}
public int connectDB(String driver,String disp,String host,String port,String db,String name,String pass,Current cur)
{
try {
Class.forName(driver);
} catch (ClassNotFoundException cnfe) {
return -1;
}
Connection c = null;
try {
String _disp="jdbc:"+disp+"://"+host+":"+port+"/"+db;
c = DriverManager.getConnection(_disp,name,pass);
} catch (SQLException se) {
return -1;
}
if(c==null)
return -1;
m_conn_list.add(c);
return m_conn_list.size()-1;
}
public boolean insertSQL(String sql,Current cur)
{
Statement s = null;
if(cur.ctx.containsKey("connection_index"))
{
int index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
try {
s = c.createStatement();
} catch (SQLException se) {
return false;
}
try {
s.executeUpdate(sql);
} catch (SQLException se) {
try {
s.close();
} catch (SQLException e) {
return false;
}
return false;
}
try {
s.close();
} catch (SQLException e) {
return false;
}
return true;
}
else
{
return false;
}
}
public boolean updateSQL(String sql,Current cur)
{
Statement s = null;
if(cur.ctx.containsKey("connection_index"))
{
int index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
try {
c.setAutoCommit(true);
s = c.createStatement();
} catch (SQLException se) {
return false;
}
try {
s.executeUpdate(sql);
} catch (SQLException se) {
try {
s.close();
} catch (SQLException e) {
return false;
}
return false;
}
try {
s.close();
} catch (SQLException e) {
return false;
}
return true;
}
else
{
return false;
}
}
public boolean deleteSQL(String sql,Current cur)
{
Statement s = null;
if(cur.ctx.containsKey("connection_index"))
{
int index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
try {
s = c.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
} catch (SQLException se) {
return false;
}
try {
s.executeUpdate(sql);
} catch (SQLException se) {
try {
s.close();
} catch (SQLException e) {
return false;
}
return false;
}
try {
s.close();
} catch (SQLException e) {
return false;
}
return true;
}
else
{
return false;
}
}
public ArrayList querySQL(String sql,Current cur)
{
Statement s = null;
ArrayList ret=new ArrayList();
if(cur.ctx.containsKey("connection_index"))
{
int index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
ResultSet rs = null;
try {
s = c.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
} catch (SQLException se) {
return null;
}
try {
rs = s.executeQuery(sql);
} catch (SQLException se) {
try {
s.close();
} catch (SQLException e) {
return null;
}
return null;
}
try {
while (rs.next()) {
ResultSetMetaData rsmd=rs.getMetaData();
int col=rsmd.getColumnCount();
ArrayList tmp=new ArrayList();
for(int i=1;i<=col;++i)
{
tmp.add(rs.getString(i));
}
ret.add(tmp);
}
} catch (SQLException se) {
se.printStackTrace();
try {
s.close();
} catch (SQLException e) {
return null;
}
return null;
}
try {
s.close();
} catch (SQLException e) {
return null;
}
return ret;
}
else
return null;
}
public boolean closeDB(Current cur)
{
int index;
if(cur.ctx.containsKey("connection_index"))
{
index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
try{
if(c!=null)
{
c.close();
}
m_conn_list.remove(index);
return true;
}
catch(SQLException se)
{
return false;
}
}
return true;
}
}
服务实现完成之后,开始写服务端的代码server.java
服务端的代码实现起来非常简单,主要是绑口和加入ICE服务。
package jdbcProxy;
import Ice.*;
public class server extends Application {
public int run(String[] args)
{
ObjectAdapter adapter=communicator().createObjectAdapter("jdbcAgent");
adapter.add(new jdbcAgentI(),Util.stringToIdentity("operator"));
adapter.activate();
communicator().waitForShutdown();
return 0;
}
public static void main(String[] args)
{
server app=new server();
System.exit(app.main("server",args,"config"));
}
}
这样服务器端的代码就完成了,可以运行并等待请求过来。
下面开发两种语言的客户端java和c++的:
有心人可能看出,这两种语言的实现是非常相似的,可以说写出一种,就可以写其它各种语言的客户端,用在不同的需求之中。而且另人振奋的是,不同语言的客户端是可以同时对一个服务端发起请求的,服务器看不到程序语言的差别。
Java语言客户端
package jdbcProxy;
import java.util.HashMap;
import Ice.*;
import java.util.*;
import jdbcProxy.jdbcAgent.OperatorPrx;
import jdbcProxy.jdbcAgent.OperatorPrxHelper;
public class client extends Application {
public int run(String[] args)
{
Ice.Properties properties = communicator().getProperties();
final String proxyProperty = "jdbcAgent.Proxy";
String proxy = properties.getProperty(proxyProperty);
if(proxy.length() == 0)
{
System.err.println("property `" + proxyProperty + "' not set");
return 1;
}
OperatorPrx jaix=OperatorPrxHelper.checkedCast(communicator().stringToProxy(proxy));
int i=jaix.connectDB("org.postgresql.Driver","postgresql","192.168.30.20","5432","test","root","123456");
HashMap ctx=new HashMap();
ctx.put("connection_index",String.valueOf(i));
ArrayList ret=jaix.querySQL("select * from mytable",ctx);
if(ret==null)
return 0;
for(int j=0;j<ret.size();++j)
{
ArrayList tmp=(ArrayList)(ret.get(j));
for(int k=0;k<tmp.size();++k)
System.out.print(tmp.get(k)+" ");
System.out.println();
}
jaix.closeDB(ctx);
return 0;
}
public static void main(String[] args)
{
client app=new client();
System.exit(app.main("client",args,"config"));
}
}
C++语言客户端
#include "globe.h"
class Client : public Application
{
public:
virtual int run(int argc,char * argv[]);
Client();
~Client();
int index;
};
Client::Client()
{
index=-1;
}
Client::~Client()
{
}
int Client::run(int argc,char * argv[])
{
PropertiesPtr properties = communicator()->getProperties();
const char * buf="jdbcAgent.Proxy";
string proxy=properties->getProperty(buf);
if(proxy.empty())
{
cerr << argv[0] << ": property `" << buf << "' not set" << endl;
return EXIT_FAILURE;
}
cout<<proxy<<endl;
OperatorPrx jaix=OperatorPrx::checkedCast(communicator()->stringToProxy(proxy));
if(jaix==0)
{
cout<<"cannot get proxy===================="<<endl;
return 0;
}
Context ctx;
int i=jaix->connectDB("org.postgresql.Driver","postgresql","127.0.0.1","5432","test","root","123456");
if(i==-1)
{
cout<<"Cannot connect the db"<<endl;
return -1;
}
char buf2[20];
sprintf(buf2,"%d",i);
ctx["connection_index"]=buf2;
jaix=OperatorPrx::checkedCast(jaix->ice_newContext(ctx));
for(int i=0;i<10000;++i)
jaix->insertSQL("insert into mytable values('好人啊',100)");
table t=jaix->querySQL("select * from mytable");
for(table::iterator p=t.begin();p!=t.end();++p)
{
CString buf=q->c_str();
ConvertUtf8ToGBK(buf);
string buf2=buf;
cout<<buf2<<" ";
}
jaix->closeDB();
return 0;
}
int main(int argc,char * argv[])
{
Client app;
return app.main(argc,argv,"config");
}
只需要开发这两种客户端的逻辑代码,而不用重新开发服务的接口实现。
以下是结果:
数据库中插入四条数据:
图中乱码是因为UTF8引起的。
java客户端在eclipse中的结果:
c++客户端的结果:
文件:
cpp_client.rar
大小:
9KB
下载:
下载
文件:
java_service_client.rar
大小:
2KB
下载:
下载
在linux平台下,这两个包都可能不加改动的使用,这就是ICE的强大之处。