首页 > 代码库 > 解决erlang和java同时操作一张表,造成锁表问题

解决erlang和java同时操作一张表,造成锁表问题

作者:张昌昌

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,javaNode@zcc}!{self(),"write_start"},
   timer:sleep(5000),
   {theMailbox,javaNode@zcc}!{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(javaNode@zcc)"

解决erlang和java同时操作一张表,造成锁表问题