【问题标题】:Check if data exists in database and insert new if not found using multiple threads?检查数据库中是否存在数据,如果使用多个线程找不到则插入新数据?
【发布时间】:2018-05-01 23:12:46
【问题描述】:

我的要求是这样的:
我编写了一个代码来检查数据库中的数据,如果没有找到数据,它会使用第三方 rest API 来获取数据。执行一些逻辑,最终得到的数据存入数据库。

 public void exampleMethod(){

      MyObject myObj = getObjFromDatabase(); //getting from db

      if(myObj==null){                       //not found in db
        myObj = getObjFromThirdParty();      //consuming rest api
        //some logic here in case myobj is not in db.... 
      }else{
       //some other logic here in case myobj is in db...
      } 
     saveObjInDatabase(myObj);            //saving it in database
 } 

我只需要将它保存在数据库中一次。从第三方 API 获取响应需要一些时间,并且此方法需要从多个线程中执行。
现在,问题是我只需要将它保存在数据库中一次,但是在一个线程可以将数据保存在数据库中之前,另一个线程从数据库中获取空值,只有当“数据不在数据库中”时才应该执行的逻辑被执行并保存同一数据不止一次。 (我正在使用 mongoDB 来存储数据) 我怎么解决这个问题?谢谢你。

【问题讨论】:

  • 简短的回答是“锁定”。我会说您可能应该在数据库端进行锁定,这样如果您有多个 JVM 同时针对同一个数据库运行此代码,它就会起作用。会是这样吗?如果没有,那么您可以在 Java 代码中使用锁定。
  • 上下文不清楚,但听起来多个线程正在创建一个myObj,其中每个线程的myObj 只是same 对象的不同实例。最简单的方法是同步exampleMethod()
  • 同步exampleMethod()可能是最简单的解决方案,但是如果有很多并发读取,那会阻塞很多,不需要这样做。如果另一个线程正在更新值,线程只需要停止并等待。

标签: java multithreading


【解决方案1】:

您要问的是缓存。这是一个应该可以正常工作的示例。如果需要加载对象,它会在getObj 上同步。如果对象是新鲜的,那么getObj 会很快返回并且几乎不会阻塞其他线程,但是如果它需要加载对象,那么其他线程将等待直到对象被加载。

public class Test {

    // used when you want to refresh the cached object
    private static boolean refreshNext = false;

    // a static reference to your object that all threads can use
    private static MyObj cachedObj = null;

    private static void message(String msg) {
        System.out.println(
                System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " : " + msg);
    }

    private static void sleep(long milli) {
        try { Thread.sleep(milli); } catch (Exception e) { }
    }

    // represents the object stored in the db
    private static MyObj myObjInDb = null;

    private static void saveObjInDb(MyObj obj) {
        // TODO do real saving to db and handle errors
        message("storing in db...");
        myObjInDb = obj;
    }

    private static MyObj loadObjFromDb() {
        // TODO do real loading from db and handle errors
        message("getting from db...");
        sleep(1000);
        return myObjInDb;
    }

    private static MyObj loadObjFromVendor() {
        // TODO do real fetching from vendor and handle errors
        message("getting from vendor...");
        sleep(2000);
        return new MyObj();
    }

    private static MyObj loadObj() {
        message("loading object...");
        MyObj obj = loadObjFromDb();
        if (obj == null) {
            message("db didn't have it.");
            obj = loadObjFromVendor();
            saveObjInDb(obj);
        }
        return obj;
    }

    /** Returns the object, first loading and caching if needed. */
    public static synchronized MyObj getObj() {
        // only one thread can get the object at a time, in case it needs to be loaded. 
        if (cachedObj == null || refreshNext) {
            // load and cache the object
            cachedObj = loadObj();
            refreshNext = false;
        }
        return cachedObj;
    }

    public static void exampleMethod() {
        MyObj obj = getObj();
        message(obj.toString());
        // ... do stuff with obj
    }

    private static class MyObj {
        public final String data = "I have data!";
        @Override public String toString() { return data; }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++)
            new Thread(Test::exampleMethod).start();
    }
}

【讨论】:

    猜你喜欢
    • 2017-04-24
    • 2013-08-22
    • 2015-12-17
    • 2018-11-10
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    • 2018-01-04
    相关资源
    最近更新 更多