<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>База Данных on Dev TLDRLSS</title>
        <link>https://dev.tldrlss.com/ru/categories/%D0%B1%D0%B0%D0%B7%D0%B0-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85/</link>
        <description>Recent content in База Данных on Dev TLDRLSS</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>ru</language>
        <lastBuildDate>Tue, 19 May 2026 18:10:00 +0800</lastBuildDate><atom:link href="https://dev.tldrlss.com/ru/categories/%D0%B1%D0%B0%D0%B7%D0%B0-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Не позволяйте непринужденности SQLite обмануть вас! В чем подвох динамической типизации? Почему ALTER TABLE неполноценен? Как построить архитектуру оборонительного программирования на Node.js для безболезненного обновления схем?</title>
        <link>https://dev.tldrlss.com/ru/article/2026/05/sqlite-pitfall-intro/</link>
        <pubDate>Tue, 19 May 2026 18:10:00 +0800</pubDate>
        
        <guid>https://dev.tldrlss.com/ru/article/2026/05/sqlite-pitfall-intro/</guid>
        <description>&lt;img src="https://dev.tldrlss.com/global-assets/images/database/sqlite-type-pitfall-1.jpg" alt="Featured image of post Не позволяйте непринужденности SQLite обмануть вас! В чем подвох динамической типизации? Почему ALTER TABLE неполноценен? Как построить архитектуру оборонительного программирования на Node.js для безболезненного обновления схем?" /&gt;&lt;p&gt;Представьте себе мусорный бак для вторсырья, на который вы четко наклеили этикетку с надписью «Только пластиковые бутылки», но когда кто-то бросает туда кусок бумаги, он молча принимает его без единого слова протеста?&lt;/p&gt;
&lt;p&gt;Это тот самый леденящий душу опыт, с которым сталкиваются разработчики, когда впервые знакомятся с системой типов &lt;code&gt;SQLite&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Если вы привыкли к строгому стилю таможенника &lt;code&gt;PostgreSQL&lt;/code&gt; (где некорректные типы данных немедленно депортируются обратно), непринужденность &lt;code&gt;SQLite&lt;/code&gt; может заставить вас усомниться в своей жизни.&lt;/p&gt;
&lt;p&gt;Что еще более пугающе, когда вы захотите &lt;strong&gt;изменить структуру таблицы&lt;/strong&gt;, база данных скажет вам:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;«Таблицу нельзя изменить напрямую. Пожалуйста, постройте новый дом, перевезите туда мебель, а затем взорвите старый дом».&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;под-капотом-у-sqlite-всего-5-классов-хранения&#34;&gt;Под капотом у SQLite всего 5 классов хранения
&lt;/h2&gt;&lt;p&gt;Независимо от того, какие изысканные названия типов вы объявляете в &lt;code&gt;CREATE TABLE&lt;/code&gt; (&lt;code&gt;VARCHAR(255)&lt;/code&gt;, &lt;code&gt;BIGINT&lt;/code&gt;, &lt;code&gt;DECIMAL&lt;/code&gt;), &lt;code&gt;SQLite&lt;/code&gt; под капотом распознает только эти &lt;strong&gt;5 классов хранения&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Класс хранения&lt;/th&gt;
          &lt;th&gt;Описание&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;NULL&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Пустое значение&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;INTEGER&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Целое число (автоматически занимает от 1 до 8 байт в зависимости от величины значения)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;REAL&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Число с плавающей запятой (фиксированные 8 байт)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;TEXT&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Текстовая строка (по умолчанию кодировка UTF-8)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;BLOB&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Большой двоичный объект (хранится точно в том виде, в каком был введен)&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Типы, которые вы устанавливаете для столбцов, &lt;strong&gt;являются лишь «рекомендациями» для &lt;code&gt;SQLite&lt;/code&gt;, а не «обязательными правилами»&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Это называется &lt;strong&gt;«Type Affinity» (Родство типов)&lt;/strong&gt;. &lt;code&gt;SQLite&lt;/code&gt; попытается преобразовать ваши данные в рекомендуемый тип, но если не сможет, то просто вставит исходные данные в любом случае без вызова ошибки.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Вы можете объявить столбец &lt;code&gt;age INTEGER&lt;/code&gt; в &lt;code&gt;SQLite&lt;/code&gt; и затем вставить строку &lt;code&gt;&#39;вечно восемнадцать&#39;&lt;/code&gt;; база данных с радостью примет ее.&lt;/p&gt;
&lt;!--adsense--&gt;
&lt;h2 id=&#34;три-ловушки-типов-в-которые-легче-всего-угодить&#34;&gt;Три ловушки типов, в которые легче всего угодить
&lt;/h2&gt;&lt;h3 id=&#34;ловушка-1-отсутствие-встроенного-boolean&#34;&gt;Ловушка 1: Отсутствие встроенного Boolean
&lt;/h3&gt;&lt;p&gt;В &lt;code&gt;SQLite&lt;/code&gt; &lt;strong&gt;нет типа данных boolean&lt;/strong&gt;. Значения &lt;code&gt;True&lt;/code&gt; и &lt;code&gt;False&lt;/code&gt; могут быть представлены только целыми числами &lt;code&gt;1&lt;/code&gt; и &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Когда вы извлекаете данные из &lt;code&gt;SQLite&lt;/code&gt; с помощью &lt;code&gt;Node.js&lt;/code&gt;, вы получаете число &lt;code&gt;1&lt;/code&gt; или &lt;code&gt;0&lt;/code&gt;, а не &lt;code&gt;true&lt;/code&gt; или &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Если вы напрямую выполните проверку вида &lt;code&gt;if (user.is_admin === true)&lt;/code&gt;, она никогда не будет истинной.&lt;/p&gt;
&lt;h3 id=&#34;ловушка-2-отсутствие-типа-datetime&#34;&gt;Ловушка 2: Отсутствие типа Date/Time
&lt;/h3&gt;&lt;p&gt;В &lt;code&gt;SQLite&lt;/code&gt; &lt;strong&gt;нет типа данных даты/времени&lt;/strong&gt;. Вы можете хранить время только следующими способами:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Способ хранения&lt;/th&gt;
          &lt;th&gt;Пример&lt;/th&gt;
          &lt;th&gt;Плюсы и минусы&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;TEXT (строка ISO-8601)&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;&#39;2026-05-19T18:00:00Z&#39;&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Наиболее рекомендуемый&lt;/strong&gt;, высокая читаемость, бесшовное преобразование при переходе на PostgreSQL в будущем&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;INTEGER (Unix Timestamp)&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;1747656000&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Малый размер, но не читается человеком&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Никогда не храните даты в произвольных пользовательских форматах, таких как &lt;code&gt;19.05.2026 18:00&lt;/code&gt;, иначе будущая миграция данных обернется катастрофой.&lt;/p&gt;
&lt;h3 id=&#34;ловушка-3-вставка-строки-в-столбец-integer-не-вызовет-ошибку&#34;&gt;Ловушка 3: Вставка строки в столбец Integer не вызовет ошибку
&lt;/h3&gt;&lt;p&gt;В &lt;code&gt;PostgreSQL&lt;/code&gt; вставка строки в столбец &lt;code&gt;INTEGER&lt;/code&gt; сразу же вызывает ошибку. Но &lt;code&gt;SQLite&lt;/code&gt; лишь попытается тихо преобразовать ее, а в случае неудачи примет как есть.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Это означает, что &lt;strong&gt;грязные данные могут незаметно просочиться в вашу базу данных&lt;/strong&gt;, пока в один прекрасный день ваша программа не упадет из-за получения неожиданного типа. Только тогда вы обнаружите проблему.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;оборонительное-программирование-отношение-к-непринужденной-базе-данных-со-строгой-позиции&#34;&gt;Оборонительное программирование: Отношение к непринужденной базе данных со строгой позиции
&lt;/h2&gt;&lt;p&gt;Столкнувшись с непринужденностью &lt;code&gt;SQLite&lt;/code&gt;, вы должны выстроить &lt;strong&gt;строгие механизмы защиты&lt;/strong&gt; при разработке на &lt;code&gt;Node.js&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Уровень защиты&lt;/th&gt;
          &lt;th&gt;Инструмент&lt;/th&gt;
          &lt;th&gt;Роль&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Страж времени компиляции&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Перехват некорректных типов на этапе написания кода&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Валидация на входе API&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Zod&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Строгая проверка входящих данных (гарантия того, что age всегда является числом)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Неявное преобразование типов&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Prisma / Drizzle ORM&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Автоматическая обработка различий типов между SQLite и PostgreSQL&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Перенос &lt;strong&gt;«вышибалы валидации данных»&lt;/strong&gt; с уровня базы данных на уровень приложения &lt;code&gt;Node.js&lt;/code&gt; — ключевая стратегия для использования преимуществ высокой скорости разработки SQLite при обеспечении будущей масштабируемости.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;При использовании ORM, если вы объявите &lt;code&gt;type: &#39;boolean&#39;&lt;/code&gt; в своем коде, ORM автоматически преобразует его в &lt;code&gt;1/0&lt;/code&gt; при сохранении в &lt;code&gt;SQLite&lt;/code&gt; и обратно в &lt;code&gt;true/false&lt;/code&gt; при чтении, идеально скрывая различия базовых типов.&lt;/p&gt;
&lt;!--adsense--&gt;
&lt;h2 id=&#34;alter-table-неполноценен-что-можно-и-что-нельзя-изменять&#34;&gt;ALTER TABLE неполноценен: Что можно и что нельзя изменять
&lt;/h2&gt;&lt;p&gt;Поддержка изменения структуры таблиц в &lt;code&gt;SQLite&lt;/code&gt; крайне ограничена:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Операция&lt;/th&gt;
          &lt;th&gt;Поддерживается&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Добавление столбца (&lt;code&gt;ADD COLUMN&lt;/code&gt;)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Да&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Переименование столбца (&lt;code&gt;RENAME COLUMN&lt;/code&gt;)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Да&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Удаление столбца (&lt;code&gt;DROP COLUMN&lt;/code&gt;)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Да&lt;/strong&gt; (в более новых версиях)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Переименование таблицы (&lt;code&gt;RENAME TO&lt;/code&gt;)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Да&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Изменение типа столбца&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Нет&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Добавление/удаление ограничений &lt;code&gt;UNIQUE&lt;/code&gt;, &lt;code&gt;NOT NULL&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Нет&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Изменение первичного ключа (Primary Key)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Нет&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Изменение внешнего ключа (Foreign Key)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Нет&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Как только вам понадобится выполнить любое из «неподдерживаемых» изменений, &lt;code&gt;SQLite&lt;/code&gt; потребует от вас выполнения стратегии &lt;strong&gt;«пересоздания и переноса»&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;четыре-шага-пересоздания-и-переноса-метод-обновления-таблиц-sqlite&#34;&gt;Четыре шага пересоздания и переноса: Метод обновления таблиц SQLite
&lt;/h2&gt;&lt;p&gt;Поскольку прямое изменение невозможно, стандартная процедура, рекомендуемая официальной документацией, выглядит так: &lt;strong&gt;построить новый дом, перевезти мебель, взорвать старый дом и повесить новую табличку на дверь&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Шаг&lt;/th&gt;
          &lt;th&gt;Действие&lt;/th&gt;
          &lt;th&gt;Описание&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;1&lt;/td&gt;
          &lt;td&gt;Создание новой таблицы&lt;/td&gt;
          &lt;td&gt;Создать &lt;code&gt;CREATE TABLE users_new (...)&lt;/code&gt; с правильной структурой&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;2&lt;/td&gt;
          &lt;td&gt;Копирование данных&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;INSERT INTO users_new SELECT ... FROM users&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;3&lt;/td&gt;
          &lt;td&gt;Удаление старой таблицы&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;DROP TABLE users&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;4&lt;/td&gt;
          &lt;td&gt;Переименование таблицы&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;ALTER TABLE users_new RENAME TO users&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Эти четыре шага должны быть выполнены &lt;strong&gt;на одном дыхании&lt;/strong&gt;; любое отключение электричества или сбой приложения на полпути приведет к потере данных.&lt;/p&gt;
&lt;!--adsense--&gt;
&lt;h2 id=&#34;гарантия-обновления-без-потери-данных-две-линии-безопасности&#34;&gt;Гарантия обновления без потери данных: Две линии безопасности
&lt;/h2&gt;&lt;h3 id=&#34;линия-безопасности-1-физическая-защита-прямое-копирование-файла&#34;&gt;Линия безопасности 1: Физическая защита, прямое копирование файла
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;SQLite&lt;/code&gt; по сути представляет собой один-единственный файл. Перед выполнением любых изменений схемы просто скопируйте файл &lt;code&gt;.db&lt;/code&gt; в качестве резервной копии.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;fs&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;copyFileSync&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;my_project.db&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;my_project_backup.db&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Если что-то пойдет не так, перезапись файла восстановит всё в мгновение ока. Это преимущество, которое не могут предоставить другие крупные базы данных.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;линия-безопасности-2-обертка-в-transaction-машина-времени-базы-данных&#34;&gt;Линия безопасности 2: Обертка в Transaction, машина времени базы данных
&lt;/h3&gt;&lt;p&gt;Оберните все шаги миграции в одну транзакцию &lt;code&gt;Transaction&lt;/code&gt;; если какой-либо шаг завершится неудачей, весь процесс будет &lt;strong&gt;автоматически отменен (Rollback)&lt;/strong&gt;, как будто ничего и не было.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Database&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;better-sqlite3&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Database&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;my_project.db&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;migrateData&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;transaction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;    CREATE TABLE users_new (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;      id INTEGER PRIMARY KEY AUTOINCREMENT,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;      name TEXT NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;      age INTEGER NOT NULL DEFAULT 18
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;  `&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;    INSERT INTO users_new (id, name, age)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;    SELECT id, name, COALESCE(age, 18) FROM users
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;  `&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;DROP TABLE users&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ALTER TABLE users_new RENAME TO users&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;migrateData&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Обновление таблицы завершено&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Ошибка обновления, данные безопасно восстановлены:&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;«Резервная копия файла + привязка транзакции»&lt;/strong&gt; — это подушка безопасности для миграции вашей базы данных.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;контролируйте-непринужденную-sqlite-со-строгой-позиции&#34;&gt;Контролируйте непринужденную SQLite со строгой позиции
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Укротите непринужденную &lt;code&gt;SQLite&lt;/code&gt; с помощью &lt;strong&gt;строгой архитектуры на уровне приложения&lt;/strong&gt;, чтобы наслаждаться молниеносной скоростью разработки и одновременно избегать технического долга в будущем.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Система типов SQLite очень непринужденная, а &lt;code&gt;ALTER TABLE&lt;/code&gt; имеет множество ограничений.&lt;/p&gt;
&lt;p&gt;Однако, пока вы добросовестно используете &lt;strong&gt;проверку типов TypeScript + валидацию Zod + ORM-абстракцию&lt;/strong&gt; на стороне &lt;code&gt;Node.js&lt;/code&gt; в сочетании со стратегией безопасности &lt;strong&gt;физического резервного копирования + транзакций&lt;/strong&gt;, вы можете спокойно наслаждаться высокой эффективностью разработки, которую предлагает &lt;code&gt;SQLite&lt;/code&gt;, одновременно подготавливая путь к гладкому переходу на &lt;code&gt;PostgreSQL&lt;/code&gt; в будущем.&lt;/p&gt;
&lt;!--adsense--&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://sqlite.org/datatype3.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Datatypes In SQLite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.runoob.com/sqlite/sqlite-data-types.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;SQLite 数据类型 | 菜鸟教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.sqlite.org/lang_transaction.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Transaction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://sqlite.org/lang.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Query Language Understood by SQLite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/SQLite&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;SQLite - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        
    </channel>
</rss>
