<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>@ed_gibbs</title><generator>teletype.in</generator><description><![CDATA[@ed_gibbs]]></description><link>https://teletype.in/@ed_gibbs?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=ed_gibbs</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/ed_gibbs?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/ed_gibbs?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Thu, 09 Apr 2026 12:57:01 GMT</pubDate><lastBuildDate>Thu, 09 Apr 2026 12:57:01 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@ed_gibbs/restful-xmysql</guid><link>https://teletype.in/@ed_gibbs/restful-xmysql?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=ed_gibbs</link><comments>https://teletype.in/@ed_gibbs/restful-xmysql?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=ed_gibbs#comments</comments><dc:creator>ed_gibbs</dc:creator><title>RESTful MySql</title><pubDate>Thu, 26 Nov 2020 13:22:55 GMT</pubDate><media:content medium="image" url="https://teletype.in/files/91/3e/913ed2c2-44ac-4829-bbfa-ec1d8c1756e6.png"></media:content><category>C#</category><description><![CDATA[<img src="https://teletype.in/files/f5/d5/f5d57704-6dc3-4ab7-874b-72bd44f1764e.jpeg"></img>C# for ZennoPoster]]></description><content:encoded><![CDATA[
  <figure class="m_original">
    <img src="https://teletype.in/files/f5/d5/f5d57704-6dc3-4ab7-874b-72bd44f1764e.jpeg" width="800" />
  </figure>
  <p><a href="https://t.me/joinchat/AAAAAEXzi9byc9ZFlE8bxw" target="_blank">C# for ZennoPoster</a></p>
  <h3>0. What the fuck your RESTful hm.. ?</h3>
  <p>Представим себе любое веб приложение. Как взаимодействовать с ним все мы знаем и умеем? Конечно же с помощью основных <strong>HTTP </strong>методов <strong>GET/POST</strong>.</p>
  <p>Наверняка многие уже знают или слышали про методы такие как <strong>PUT/DELETE/PATCH </strong>и так далее.</p>
  <p>Принцип не отличается от известных всеми <strong>GET/POST</strong>, где</p>
  <blockquote><strong>GET</strong> <em>- получить &quot;контент&quot;</em></blockquote>
  <blockquote><strong>POST</strong> - <em>отправить &quot;контент&quot;</em></blockquote>
  <blockquote><strong>DELETE</strong> - <em>удал.....</em></blockquote>
  <blockquote><strong>PUT </strong>- <em>обнов....</em></blockquote>
  <p>Если подсознательно дополнил определения, поздравляю, ты уже разобрались в принципе <strong>RESTful</strong>. Это тот же HTTP, где позиция метода запроса определяет поведение приложения.</p>
  <p>Иначе говоря <strong>RESTful </strong>представление позволяет нам к примеру обновлять записи путем простого указания <strong>PUT </strong>в запросе, удалять посредством <strong>DELETE. </strong></p>
  <h3>1. Introduce</h3>
  <p>Общие черты основного принципа <strong>RESTful </strong>вспомнили. На примере точно вспомните, наверняка взаимодействовали уже ранее с данным представлением.</p>
  <hr />
  <p>Все то что многие так долго искали, а кто-то просто хотел, но не мог сформулировать.</p>
  <p>Пришло время научится делать из любой mysql базы полноценную <strong>RESTFful </strong>прослойку и да она будет работать по <strong>HTTP </strong>протоколу. Даже не придётся в очередной раз гуглить, лезть на форума при составлении SQL запроса, а вспомните сколько ужаса связанного с экранированием спец символов и тому подобное.</p>
  <hr />
  <h3>2. Getting Started</h3>
  <p>Решение является кроссплатформенным, заведётся как на OS Windows, так и на unix-подобных системах с установленной <strong>node </strong>(<em>requires node &gt;= 7.6.0</em>).</p>
  <hr />
  <p>1) Убедимся что у нас стоит пакет <a href="https://nodejs.org/en/download/" target="_blank"><strong>node</strong></a> (<a href="https://nodejs.org/en/download/" target="_blank">https://nodejs.org/en/download/</a>), и работает <strong>npm </strong>менеджер пакетов (ставиться вместе с <strong>node</strong>).</p>
  <p>После установки Открываем <u>новое окно</u> терминала</p>
  <pre>C:\&gt; node -v
v12.18.4

C:\&gt; npm -v
6.14.8
</pre>
  <p>2) Установим пакет <a href="https://github.com/o1lab/xmysql" target="_blank">xmysql </a>который будет делать магию. (<a href="https://github.com/o1lab/xmysql" target="_blank">офф репозиторий</a>)</p>
  <p>Запустим терминал/консоль (<u>с правами Администратора</u>)</p>
  <pre>C:\&gt; npm install -g xmysql</pre>
  <p>Если не увидели ошибок, можем приступать.</p>
  <hr />
  <p data-align="right">У кого разбор полетов, следуйте на страничку репозитория проекта, изучите решения или задайте вопрос разработчику (https://github.com/o1lab/xmysql)</p>
  <hr />
  <p>3) Ну и конечно же нам нужна рабочая <strong>mysql </strong>бд.</p>
  <p>Я буду использовать локальную версию <strong>MariaDB 10.3.26</strong>. Вы можете любую какая вам по душе.</p>
  <pre>C:\&gt; xmysql</pre>
  <figure class="m_column">
    <img src="https://telegra.ph/file/4964e75761c0793a8dce7.png" width="1088" />
    <figcaption>run xmysql  [3]</figcaption>
  </figure>
  <hr />
  <p>4) Пропишем в параметрах наши значения для подключения к базе данных и укажем имя базы данных с которой будем работать</p>
  <pre>C:\&gt; xmysql -h localhost -u root p &quot;&quot; -d open_disposable_base</pre>
  <p>Убедитесь что у вас не занят порт 3000, и добавьте в исключение при первом запуске сработает брандмауэр windows.</p>
  <figure class="m_column">
    <img src="https://telegra.ph/file/34adf0cbe859e834c2ac6.png" width="748" />
    <figcaption>start xmysql on local db [4]</figcaption>
  </figure>
  <hr />
  <p>5) Проверим локальный адрес по порту 3000, на нем должен подняться RESTful HTTP нашей базы (по умолчанию <a href="http://localhost:3000/" target="_blank">http://localhost:3000</a>)</p>
  <p>Попробуем отправить запрос по этому адресу</p>
  <blockquote>p.s. можно также просто отрыть в браузере <a href="http://localhost:3000/" target="_blank">http://localhost:3000</a></blockquote>
  <figure class="m_original">
    <img src="https://telegra.ph/file/a561cae3572f4ee4be017.png" width="690" />
    <figcaption>curl query get routes [5]</figcaption>
  </figure>
  <p>На корневой странички увидим все доступные пути <strong>routing </strong>и методы взаимодействия <strong>RESTful </strong>(<u>какой метод использовать</u> в <strong>HTTP</strong> запросах)</p>
  <hr />
  <p>На данном этапе мы настроили и запустили все необходимое.</p>
  <hr />
  <p><strong><u><em>!!!!Однако будьте внимательны!!!!! </em></u></strong></p>
  <p><code>Если запустите на выделенном сервере и не позаботитесь о доступе по <strong><u>порту 3000</u></strong>, скорее всего любой желающий <strong><u>сможет получить данные с базы</u></strong>, или куда похуже через методы <strong>upload/download.</strong></code></p>
  <p><em><code>Решения легко найти в google. Вариантов довольно много. От парольного доступа до исключения на сетевом уровне.</code></em></p>
  <hr />
  <h3>3. Query processing</h3>
  <p>Разберем пару примеров, попробуем на что способен этот зверь =)</p>
  <pre>Модель построения запросов </pre>
  <p>host:port/api/[<strong>table_name</strong>]/?[<strong>method]</strong></p>
  <pre>Модель построения запросов с перечислением параметров</pre>
  <p>host:port/api/[<strong>table_name</strong>]/?[<strong>method]</strong>=([<strong>param1]</strong>,[<strong>param2]</strong>..)</p>
  <hr />
  <p data-align="right"><em>Полный список <a href="https://github.com/o1lab/xmysql#api-overview" target="_blank">https://github.com/o1lab/xmysql#api-overview</a></em></p>
  <figure class="m_custom">
    <img src="https://telegra.ph/file/4f4d0fc124f1df0826e58.gif" width="1064" />
    <figcaption>List of method api</figcaption>
  </figure>
  <hr />
  <hr />
  <ul>
    <li>Просмотр содержимого таблицы (аналогия запроса ниже)</li>
  </ul>
  <p><em><code>sql select * from &#x60;open_disposable_base&#x60; limit 0,20</code></em></p>
  <blockquote>GET /api/disposable_emails/</blockquote>
  <pre>[
  {
    &quot;id&quot;: 1482,
    &quot;domain&quot;: &quot;ce.mintemail.com&quot;,
    &quot;created_at&quot;: &quot;2018-05-31T01:25:56.000Z&quot;,
    &quot;updated_at&quot;: &quot;2018-05-31T01:25:56.000Z&quot;,
    &quot;deleted_at&quot;: null
  }
]</pre>
  <hr />
  <p></p>
  <ul>
    <li>Получить кол-во в таблице.</li>
  </ul>
  <blockquote>GET /api/disposable_emails/count </blockquote>
  <pre>[
  {
    &quot;no_of_rows&quot;: 663
  }
]</pre>
  <hr />
  <p>Пример передачи параметров:</p>
  <p>/<strong>findOne</strong>?_where=([<strong>Column</strong>],[<strong>Operator</strong>],[<strong>SearchValue</strong>])</p>
  <p>[<strong>SearchValue</strong>] = <u>ce.mintemail.com </u>-искомое значение</p>
  <p>[<strong>Column</strong>] = <u>domain </u> - имя столбца</p>
  <p>[<strong>Operator</strong>] = <u>eq</u> - эквивалентно (<a href="https://github.com/o1lab/xmysql#comparison-operators" target="_blank">полный список</a>)</p>
  <hr />
  <ul>
    <li>Поиск записи по указанному столбцу</li>
  </ul>
  <blockquote>GET /api/disposable_emails/findOne?_where=(domain,eq,ce.mintemail.com)</blockquote>
  <pre>[
  {
    &quot;id&quot;: 1482,
    &quot;domain&quot;: &quot;ce.mintemail.com&quot;,
    &quot;created_at&quot;: &quot;2018-05-31T01:25:56.000Z&quot;,
    &quot;updated_at&quot;: &quot;2018-05-31T01:25:56.000Z&quot;,
    &quot;deleted_at&quot;: null
  }
]</pre>
  <ul>
    <li>Фильтрация по столбцам, перечисляем через запятую имена столбцов. Также инверсионный вариант с добавлением “-” перед именем.</li>
  </ul>
  <blockquote>GET /api/disposable<em>emails/?</em>fields=id,domain</blockquote>
  <pre>[
  {
    &quot;id&quot;: 1481,
    &quot;domain&quot;: &quot;cbair.com&quot;
  },
  {
    &quot;id&quot;: 1482,
    &quot;domain&quot;: &quot;ce.mintemail.com&quot;
  }</pre>
  <blockquote>GET /api/disposable<em>emails/?</em>fields=-domain</blockquote>
  <pre>[
  {
    &quot;id&quot;: 1481,
    &quot;created_at&quot;: &quot;2018-05-31T01:25:56.000Z&quot;,
    &quot;updated_at&quot;: &quot;2018-05-31T01:25:56.000Z&quot;,
    &quot;deleted_at&quot;: null
  },
  {
    &quot;id&quot;: 1482,
    &quot;created_at&quot;: &quot;2018-05-31T01:25:56.000Z&quot;,
    &quot;updated_at&quot;: &quot;2018-05-31T01:25:56.000Z&quot;,
    &quot;deleted_at&quot;: null
  }</pre>
  <hr />
  <ul>
    <li>Создаем пагинацию (полезно при очень больших таблицах)</li>
  </ul>
  <blockquote>GET /api/disposable<em>emails/?</em>fields=domain&amp;_p<em>p=1&amp;</em>ze=3</blockquote>
  <pre>[
  {
    &quot;domain&quot;: &quot;cheaphorde.com&quot;
  },
  {
    &quot;domain&quot;: &quot;chef.asana.biz&quot;
  },
  {
    &quot;domain&quot;: &quot;chielo.com&quot;
  }
]</pre>
  <hr />
  <ul>
    <li>Также стоит отметить возможность работы с файлами. Upload, Download, в параметрах xmysql есть флаг указания каталога для файлов.</li>
  </ul>
  <hr />
  <ul>
    <li>В документации описан также метод  Dynamic queries, эта возможность присутствует в случае локального mysql сервера.</li>
  </ul>
  <blockquote>POST /dynamic  </blockquote>
  <pre>    {
        &quot;query&quot;: &quot;select * from ?? limit 1,20&quot;,
        &quot;params&quot;: [&quot;customers&quot;]
    }</pre>
  <hr />
  <h3>4. Work in ZP, try multitread inserts</h3>
  <p>На коленке написал минимальный код, для быстрого теста и попробовать многопоточную вставку. Общий принцип как начать внедрять в свои проекты xmysql.</p>
  <pre>string xsqlHost = &quot;http://localhost&quot;;   // xmysql hostname or IP
string xsqlPort = &quot;3000&quot;;
string xsqlTable = &quot;test_multithread&quot;;  // Table name

string xsqlBase = string.Concat(xsqlHost, &quot;:&quot;, xsqlPort);  // base path for query
string xsqlGetTable = string.Concat(xsqlBase, &quot;/api/&quot;, xsqlTable);   // path to query for table

var xsqlHelth = new HttpRequest().Get(xsqlBase+&quot;/_health&quot;).ToString();  // check avalible and status mysql
project.SendInfoToLog(xsqlHelth);

var xsqlRoutes = new HttpRequest().Get(xsqlBase).ToString();  // parse all avalible routes 
project.Json.FromString(xsqlRoutes);  // show routes with methods in zp varibles (json)</pre>
  <figure class="m_custom">
    <img src="https://teletype.in/files/f2/3c/f23cb5de-6f4c-4109-b37a-451dd43e87c5.gif" width="1351.2582972582973" />
    <figcaption>Project Maker sample</figcaption>
  </figure>
  <hr />
  <p></p>
  <p>Плавненько подходим к концовке. Читать данные хорошо, но что же с записью/изменению/обновлению? </p>
  <p>Произвели пару тестов, в окружении локально поднятой базой, для общей оценки и применения xmysql при работе в многопоточном режиме.</p>
  <p>Схема заполняемой таблицы выглядело примерно след. образом:</p>
  <pre>CREATE TABLE &#x60;test_multithread&#x60; (
  &#x60;id&#x60; int(11) NOT NULL AUTO_INCREMENT,
  &#x60;domain&#x60; varchar(255) NOT NULL,
  &#x60;add_date&#x60; timestamp DEFAULT CURRENT_TIMESTAMP
  PRIMARY KEY (&#x60;id&#x60;)
) ENGINE=InnoDB AUTO_INCREMENT=5958 DEFAULT CHARSET=utf8;</pre>
  <p></p>
  <p>Из списка загружались домены, причем умышленно по одному, и аналогично происходила вставка по одному INSERT.</p>
  <blockquote>Так делать не желательно, в xmysql помимо add row есть и пакетные обработки CREATE, LIST,  DELETE. Прошу заметить, средствами слоя xmysql параметры переданные в теле POST запроса преобразуются в стандартный пакетный INSERT. </blockquote>
  <p></p>
  <p>Первый тест обычными циклами средствами zp, 2 кубика, один из них шлет POST с параметром &quot;domain=test.com&quot;</p>
  <figure class="m_retina">
    <img src="https://teletype.in/files/ee/55/ee55d395-010e-47a6-9e7b-b52959648dd3.gif" width="1269" />
    <figcaption>Multithread add (25 threads)</figcaption>
  </figure>
  <p></p>
  <p>Второй тест с использованием Threading.Tasks.Parallel.For</p>
  <p>Для понимания кусок кода который отрабатывал указанное кол-во циклов параллельно</p>
  <pre>var listparams = project.Lists[&quot;domains_becnh&quot;];

System.Threading.Tasks.Parallel.For(0, icount, (i, parallelLoopState) =&gt; {
  string domain = listparams[0];
  listparams.RemoveAt(0);
  using (var request = new HttpRequest())
{
    var reqParams = new RequestParams();
    reqParams[&quot;domain&quot;] = domain;

    string addRow = request.Post(xsqlGetTable, reqParams).ToString();
}
return;
});</pre>
  <p></p>
  <figure class="m_retina">
    <img src="https://teletype.in/files/c6/ff/c6ff3064-fc6a-4f1b-8d11-5cfc35f0fcb2.gif" width="1240" />
    <figcaption>Parallel Task  rows add</figcaption>
  </figure>
  <p></p>
  <p>В конечном итоге протестировать удалось далеко еще не все.</p>
  <p>Однако как видите, даже по одиночной вставке работает более чем.</p>
  <p>Скорость вставки в моем случае следующие:</p>
  <ol>
    <li>500 строк 25 потоками  =  500 rows added in <em>7110,4820ms</em></li>
  </ol>
  <p>Используя параллельные потоки (parallels threads):</p>
  <ol>
    <li><strong>100 </strong>rows added in <em>205,8456ms</em> (  <strong><u>2,1 second</u></strong> ) </li>
    <li><strong>500 </strong>rows added in <em>4619,1725ms </em>(  <strong><u>4,6 second</u></strong> ) </li>
    <li><strong>1000 </strong>rows added in <em>7503,2164ms  </em>(  <strong><u>7,5 second</u></strong> ) </li>
  </ol>
  <p></p>
  <p></p>
  <blockquote>p.s. судя по минимальному просмотру исходного кода xmysql, я не углядел работу с транзакциями и т.д. Данный вопрос оставил на потом. Убедитесь в отсутствие необходимости локов на уровне бд если вам будет необходимо много удалять строк и тд. Надеюсь там все хорошо в этом плане, в любом случае попробуйте перед тем как бежать переносить все на xmysql.</blockquote>
  <p></p>
  <p></p>
  <p>Проект неплохо вдохновил на интересные идеи и решения. Так-же есть куча альтернативных решений, в целом личное мнение xmysql вполне способен на роль вспомогательную в проектах. Но в в идеале нужно обертку. Вполне возможно в скором времени она появится...</p>
  <hr />
  <hr />
  <p></p>
  <p data-align="right">Следите за новостями, прокачивайте умы -  <a href="https://t.me/joinchat/AAAAAEXzi9byc9ZFlE8bxw" target="_blank">C# for ZennoPoster</a></p>

]]></content:encoded></item></channel></rss>