文章 "SQLite: MQL5 原生 SQL 数据库操纵" - 页 7

 
Renat Fatkhullin:

明天的测试版将是 2840:

  • SQLite 2.35.2 版本

  • 永久 WAL 模式,允许在不同应用程序中使用打开的数据库(以前 MetaEditor 无法与终端并行工作)。

非常高兴,谢谢
 
Edgar Akhmadeev:
非常高兴,谢谢

测试版 2840 已发布,请试用。

 
Renat Fatkhullin:

明天的测试版将是 2840:

  • SQLite 2.35.2 版本

  • 永久 WAL 模式,允许在不同应用程序中使用打开的数据库(以前 MetaEditor 无法与终端并行工作)

  • 扩展统计函数
    示例:
  • 新的数学函数
  • 还包括JSON 支持

    我们稍后将在数据库创建向导中加入新的 json 类型。



雷纳特,非常感谢你!!我没想到会这么快!
没想到这么快,非常高兴))))))。
 
fxsaber:

谁想出了这个办法,请展示一下这项任务的执行情况。

  1. 有两个终端。
  2. 需要将一个符号的实时报价从终端 1 传输到终端 2 的相应自定义符号
fxsaber:

在这项任务的框架内,我是否正确理解了在两种情况下(读取终端 2 中的基数和向终端 1 中的基数写入时)都应通过交易机制 进行阻塞?

确定数据库已更新的最简便方法是什么?

从根本上说是错误的。你描述的是一个分布式客户机-服务器应用程序,采用的是 1 个写入器、n 个读取器的方案。在设计此类系统(以及任何一般的分布式系统)时,应尽量使用无锁的数据组织和访问方式来避免任何锁。如果所使用的技术无法让你做到无锁,那么对于你的任务来说,它可能根本就不是最好的解决方案。不过,对于其他任务来说,这种技术可能很好。
在您的情况下,最好部署一个完整的服务器(可以与客户端在同一台机器上部署),并将报价写入消息队列,例如 Kafka。客户端将从所需的索引中读取这些报价。这是一种无锁数据访问方案。

fxsaber:

这么说来,数据交换 的可能性比通过文件交换 的可能性要少?

绝对不是。通过文件共享根本就不是原子性的,因此需要在读写双方都加锁。这是最容易造成死锁的方式,而且会陷入难以发现、难以理解的错误之中。

 
Vasiliy Sokolov:

从根本上说是错误的。你所描述的是一个分布式客户端-服务器应用程序,它采用 1 个写入器、n 个读取器的方案。在设计此类系统(以及任何一般的分布式系统)时,应尽量避免任何锁,使用无锁方式组织和访问数据。如果所使用的技术无法让你做到无锁,那么对于你的任务来说,它可能根本就不是最好的解决方案。不过,对于其他任务来说,这种技术可能很好。
在你的情况下,最好部署一个完整的服务器(可以与客户端在同一台机器上部署),并将报价写入消息队列,例如 Kafka。客户端将从所需的索引中读取这些报价。这是一种无锁数据访问方案。

绝对不是。通过文件共享无论如何都不是原子性的,因此读写双方都需要加锁。这是最容易造成死锁的方法,而且会让人陷入难以发现和理解的错误之中。

感谢您如此详细的回复!不幸的是,我完全忘记了当时要解决的是什么问题。这就是为什么我无法分享我对这个问题的想法。

 
Renat Fatkhullin:

测试版 2840 已发布,请试用。

雷纳特,早上好!

我也注意到了 StringFormat 中的一个问题,当输入的数据字符串比较大时,例如从资源文件中输入 3-4 个语句,例如 %d、%s、%lld、%s,我检查了几种替换变体,只是函数中访问的数据量较大,导致错误 4003。

我在项目中暂时改用了StringReplace 函数,它在输入字符串中有大量数据时也能正常工作。
 
学习了,谢谢分享。
 
在 DataBasePrepare 文件中存在一些错误。我想用字符串替换 "pair",对吗?
 

关于此解决方案的问题

- 多个 EA 同时使用同一个sqlite 数据库 会有问题吗?

- 如果 MT5 崩溃,是否会丢失一些数据?多久向磁盘写一次数据?

 

下午好,亲爱的开发人员!

当我在参数中指定表名时,函数 "DatabaseExport "无法正常工作......它给出了错误 5601(查询执行错误,但我没有执行查询)、

而当我指定 SQL 查询时,则会出现错误 4022(程序执行 取消),这可能是 MQL 函数内部的错误,也可能是我的程序库中的部分代码:


//+------------------------------------------------------------------+
void CSQLite::DataBaseToFile(void)
  {
   uint flags=DATABASE_EXPORT_COMMON_FOLDER | DATABASE_EXPORT_QUOTED_STRINGS;

   long count_rows=0;

   string tables[],
          file_name,
          separator=";",
          query="SELECT name FROM sqlite_master WHERE tbl_name <> 'sqlite_sequence' AND type='table'";

   int total=GetValuesFromDataBase(query,tables); // ТУТ ВСЕ ОК, СПИСОК ТАБЛИЦ ИЗ БАЗЫ ПОЛУЧЕН.

   if(m_handle==NULL)
      Open();

   for(int i=0; i<total; i++)
     {
      file_name=StringFormat("%s.%s",m_name,tables[i]);
      count_rows=DatabaseExport(m_handle,tables[i],file_name,flags,separator); // ОШИБКА ПОСЛЕ ВЫПОЛНЕНИЯ ДАННОЙ ФУНКЦИИ
      Print(StringFormat("Export file: %s, rows: %lld",file_name,count_rows));

      if(count_rows<0)
         Print("DB: ", m_name,", Table: ",tables[i], ", Import failed with code ", GetLastError());
      else
         if(count_rows>0)
            Print(StringFormat("Import file: %s, rows: %lld",file_name,count_rows));
     }

   Finalize();
  }
//+------------------------------------------------------------------+