作者:张昌昌
1、问题描述
Erlang端通过odbc去写oracle一张表,同时java通过jdbc驱动也去写这张表,当同时多次发生这种写操作时,这个表就被锁。
2、问题解决
思路:利用适配器原理,适配erlang和java的数据库连接,让erlang端对数据表的操作与java端对该数据表的操作,分时序顺序进行,其中一端在进行写操作时上锁
另一端就不能操作,直到他操作完成释放锁,另一端才能操作。
该适配器采用java编写,通过otp.jar让erlang与java进行通信,erlang和java对数据表操作的连接都要从该适配器入
实现方式:
(1)java端
public class ConnectionAdaptor {
private static final ConnectionAdaptor instance = new ConnectionAdaptor("javaNode","theMailbox","secret");
private OtpNode node;
private static OtpMbox mbox;
private ReentrantLock lock = new ReentrantLock();
public static ConnectionAdaptor getInstance(){
return instance;
}
private ConnectionAdaptor(String nodeName,String mboxName,String cookie){
super();
try{
node=new OtpNode(nodeName,cookie);
}catch(IOException e){
e.printStackTrace();
}
System.out.print(node);
mbox = node.createMbox(mboxName);
}
private void process(){
while(true){
try{
OtpErlangObject msg = mbox.receive();
OtpErlangTuple t = (OtpErlangTuple)msg;
OtpErlangPid from = (OtpErlangPid)t.elementAt(0);
String name = ((OtpErlangString)t.elementAt(1)).stringValue();
if(name.equals("write_start"))
adaptor(1);
}catch(Exception e){
}
}
}
public static void main(String[] args){
//启动一个线程用于erlang消息的侦听
new Thread(){
public void run(){
ConnectionAdaptor.getInstance().process();
}
}.start();
//启动一个线程进行java端的数据表操作
new Thread(){
public void run()
{
for(int i=0;i<10;i++)
{
try{
try{
ConnectionAdaptor.getInstance().adaptor(2);
}catch(Exception e){
e.printStackTrace();
}
}catch(Exception e)
{
e.printStackTrace();
}
}
}
}.start();
}
public void adaptor(int type){
lock.lock();
if (type == 1)
{
while(true)
{
OtpErlangObject msg = mbox.receive();
OtpErlangTuple t = (OtpErlangTuple)msg;
OtpErlangPid from = ((OtpErlangString)t.elementAt(1)).stringValue();
if(name.equals("write_end"))
{
System.out.println("erlang write table end");
lock.unlock();
}
}
}
else
{
Thread.sleep(5000);
System.out.println("java write table end");
lock.unlock();
}
}
}
erlang端:
-module(erl_to_java).
-export([write_table/0,start/1]).
write_table() ->
{theMailbox,[email protected]}!{self(),"write_start"},
timer:sleep(5000),
{theMailbox,[email protected]}!{self(),"write_end"}.
start(N) ->
case N =:= 0 of
true -> ok;
false -> write_table(),start(N-1)
end.
3、时序图
4、问题总结
(1)java单例模式
(2)java与erlang通信
(3)java线程间锁机制
首先利用单例模式获取一个适配器对象,然后启动一个线程执行process(),侦听来自erlang端的写表消息,一旦有erlang发出写表请求,需加锁,在erlang进程中执行
写表操作后,向java进程发送写表结束请求,然后java进程释放锁,一旦有java端写表操作,便获取锁进行写表操作,之后释放锁,在java写表期间,erlang的写表操作必须等待,直到锁释放,反之亦然。
5、使用方法
(1)运行该适配器的java端需要安装erl的运行环境,需要导入OtpErlang.jar包;
(2)erlang端节点启动时,要和适配器单例创建时的cookie保持一致,同时
erl -sname erlangNode -setcookie secret -pa "erl_to_java.bin所在的路径" -eval "net_adm:ping([email protected])"