Данная статья посвящена модернизации Microsoft SQL Server на основе проекта, выполненного Ispirer для крупной компании, занимающейся финансовым консалтингом. Клиент использовал возможности базы данных SQL Server для эффективной обработки, обработки, доступа и контроля финансовой информации своих клиентов. Клиент стремился перенести SQL Server в облако, оптимизируя при этом системную архитектуру и затраты на обслуживание.
Команда Ispirer предложила перенести бизнес-логику на Java, поскольку база данных используется в режиме OLTP. Мы тщательно проанализируем тему и рассмотрим проект клиента, который предполагает конвертацию бизнес-правил SQL Server в Java. Кроме того, мы выясним причины, по которым компании решили перенести код SQL на уровень приложений. Это потребует комплексного изучения всего процесса.
Чтобы оптимизировать затраты на облачную инфраструктуру, клиент решил перенести таблицы и данные в PostgreSQL. Поскольку мы специализируемся на миграции баз данных и приложений, заказчик обратился к нам со следующими задачами:
Ввиду значительного масштаба проекта клиент постарался минимизировать затраты на миграцию за счет внедрения автоматизации. Чтобы оптимизировать эффективность Ispirer Toolkit, мы решили, что его настройку следует провести заранее. Такой подход позволил нам предоставить команде клиента инструмент с коэффициентом конверсии T-SCL в Java примерно 90%.
Теперь давайте углубимся в миграцию таблиц и данных.
Давайте рассмотрим причины, по которым клиент решил перейти с локального SQL Server в облако. Этот переход включает в себя ряд неоспоримых преимуществ:
Экономия затрат. Одним из основных движущих факторов перехода с SQL Server на PostgreSQL в облаке является экономия средств. Раньше клиент считал, что хранить базы данных SQL Server на месте дорого. Это было связано с необходимостью специального оборудования, лицензий на программное обеспечение и квалифицированных администраторов баз данных. PostgreSQL, будучи базой данных с открытым исходным кодом, предлагает экономичную альтернативу. Клиенты могут сэкономить деньги, используя облако. Им придется платить только за то, что они используют, вместо того, чтобы вносить большие авансовые платежи. Кроме того, они могут тратить меньше средств на операции.
Масштабируемость. Облачные вычисления легче масштабировать, чем локальную инфраструктуру, для обслуживания больших рабочих нагрузок и большего числа пользователей. Чтобы локальная система могла масштабироваться в соответствии с потребностями бизнеса, организациям пришлось приобрести и установить физические серверы, лицензии на программное обеспечение, хранилище и сетевое оборудование для масштабирования бизнес-услуг в традиционных ИТ-средах. В облаке большинство этих ресурсов доступны мгновенно, в несколько кликов, и их можно автоматически увеличивать и уменьшать в зависимости от необходимых ресурсов. PostgreSQL в облаке обеспечивает высокий уровень масштабируемости, позволяя нашему клиенту легко настраивать ресурсы в зависимости от спроса.
Безопасность. Использование облачных технологий предлагает заметные преимущества в области безопасности благодаря расширенным средствам контроля идентификации, управлению доступом и системам аутентификации, предоставляемым поставщиками облачных услуг. Часто поставщики облачных услуг имеют более высокие стандарты безопасности, чем собственные ИТ-команды или локальные системы, что делает среду данных более безопасной.
Надежное шифрование в облаке снижает вероятность утечки данных. Он включает в себя многоуровневую безопасность, хорошее управление ключами и безопасный контроль доступа, которые помогают предприятиям эффективно контролировать доступ пользователей. Более того, поставщики облачных услуг строго контролируют физический доступ, внедряя такие меры, как анонимность, репликация и шифрование, для усиления защиты данных. Прогнозируется, что к 2025 году около 80% предприятий перейдут от физических центров обработки данных к облачным сервисам. Этот сдвиг обусловлен улучшенными преимуществами безопасности, предоставляемыми облаком.
Переход с SQL Server на PostgreSQL в облаке требует тщательного планирования и выполнения с учетом конкретных соображений. На основе проекта клиента наша команда выделила следующие этапы модернизации SQL Server:
Схема и преобразование данных. Данные должны быть точно преобразованы, чтобы соответствовать требованиям PostgreSQL. Это может включать обработку таких нюансов, как форматы дат и кодировка символов.
Ограничения и триггеры. Понимание различий в использовании ограничений и триггеров в двух базах данных имеет решающее значение. Соответственно необходимо внести необходимые изменения. Кроме того, функционал триггеров можно перенести в приложение. Однако задача эта далеко не простая, поэтому важно взвесить все «за» и «против».
Оптимизация производительности. Оптимизация процесса миграции позволяет минимизировать простои и время передачи данных. Для эффективной миграции важно использовать распараллеливание, оптимизировать пропускную способность сети и инвестировать в мощное оборудование.
Проверка данных и тестирование. Чтобы гарантировать целостность и функциональность данных, необходима строгая проверка перенесенных данных. Всестороннее тестирование гарантирует бесперебойную работу приложений с новой базой данных PostgreSQL.
Безопасность и разрешения. Параметры безопасности, учетные записи пользователей и разрешения в PostgreSQL должны быть настроены в соответствии с исходной настройкой SQL Server, обеспечивая плавный переход.
Раньше наши клиенты использовали хранимые процедуры для своей бизнес-логики, думая, что это повысит производительность. Но давайте будем честными: язык SQL, возможно, не является оптимальным выбором для размещения бизнес-логики по сравнению с уровнем приложения.
Фактически SQL лишь запрашивает или изменяет данные в базе данных. Здесь многие могут закидать нас тухлыми помидорами, потому что язык SQL хорошо выполняет сложные соединения, фильтрацию и сортировку, чтобы получить из запроса именно те данные, и не более того. Тогда зачем что-то менять и выносить бизнес-логику на уровень приложения?
Вопрос кажется логичным. Давайте ответим на него подробнее. Ниже мы обозначили 4 основные причины, по которым стоит серьезно задуматься о переносе бизнес-логики в приложение. Решение клиента перенести бизнес-логику на уровень приложения было вызвано следующими причинами:
Для масштабируемости лучшим вариантом является хранение бизнес-логики на уровне приложения. Почему? Потому что, как правило, значительно проще масштабировать ресурсы сервера приложений, чем ресурсы сервера базы данных. Это признано почти повсеместно. Для большинства веб-приложений добавление дополнительных серверов обычно не составляет труда, если требуется обрабатывать большой трафик. Однако ценность дополнительных серверов приложений снижается, если ваша база данных не может масштабироваться для удовлетворения возросшего спроса. Масштабирование сервера базы данных значительно сложнее, чем простое добавление серверов приложений.
Хранение бизнес-логики в базе данных может создать проблемы с удобством обслуживания. Изменение хранимых процедур может нарушить работу многих приложений, ограничить расширяемость и затруднить соблюдение принципа «Не повторяйся» (DRY). Код SQL, превышающий 100 строк, часто создает сложности и трудности с устранением неполадок. Разделение бизнес-логики на уровень приложений может облегчить вход новых членов команды и предоставить более интуитивно понятную платформу для рефакторинга.
SQL — плохой выбор для кодирования бизнес-правил вашей системы. Он негибкий, и мы не можем полагаться на него при представлении сложных моделей, поскольку он не может создавать правильные абстракции. Это ограничение является основной причиной, по которой следует избегать его использования в бизнес-логике. Речь идет не об инструментах или поддержке, а о неспособности SQL создать простую и выразительную модель предметной области, в отличие от объектно-ориентированного и функционального проектирования, которое предлагает больше возможностей.
В разработке программного обеспечения повторное использование кода — это эффективный способ сэкономить время и деньги при адаптации существующего кода для новых задач. Объектно-ориентированное программирование (ООП) — это метод, который облегчает переработку кода, что делает его пригодным для различных приложений. Однако SQL, обычно используемый в базах данных, предлагает ограниченную гибкость для повторного использования кода. Варианты включают использование «представлений» и «хранимых процедур», хотя последнее может привести к обилию параметров. Чтобы сделать правильный выбор для вашего проекта, необходимо тщательно изучить каждый метод.
Преобразование Transact-SQL в Java требует ряда важных соображений. Этот процесс включает в себя сопоставление типов данных SQL с их эквивалентами в Java, что обеспечивает точное представление данных. Он также включает в себя перевод SQL-запросов в код Java, где Java использует такие библиотеки, как JDBC или Hibernate, для обработки взаимодействия с базой данных. Более того, некоторые функции ESQL не имеют прямых эквивалентов в Java, что может создать впечатление, что автоматическое преобразование неэффективно.
На этапе настройки нашего проекта мы смогли создать ряд конверсионных решений, которые повысили уровень автоматизации. Эти решения, которые первоначально считались невозможными для автоматизации, в конечном итоге оказались успешными. Давайте углубимся в детали некоторых из них.
Преобразование инструкции INSERT в сочетании с SCOPE_IDENTITY() для получения последнего значения идентификатора, вставленного в столбец идентификаторов.
Источник:
ALTER PROCEDURE example1 AS BEGIN Declare @idBit int Declare @c int Insert Into tab (c) Values (@c) Set @idBit = SCOPE_IDENTITY() End
Цель:
@Service public class Example1 implements IExample1 { @Autowired private JdbcTemplate jdbcTemplate; private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Example1.class); @Override public Integer spExample1() throws SQLException, Exception { Integer mStatus = 0; KeyHolder keyHolder = new GeneratedKeyHolder(); try { Integer idBit = null; Integer c = null; { final Integer tmpC = c; jdbcTemplate.update(connection-> { PreparedStatement ps = connection.prepareStatement("Insert Into tab(c) \r\n" + " Values(?)", new String[] { "" }); ps.setInt( 1, tmpC); return ps; }, keyHolder); } idBit = Tsqlutils.<Integer > strToNum(keyHolder.getKey().toString(), Integer.class); return mStatus; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return mStatus; } } }
Источник:
ALTER PROCEDURE [returnSeveralResultSet] @p1 int, @p2 varchar(50) AS Begin select cob_ft, lower(buzon) from tab1 where cob_id = @p1 and cob_ft = @p2 select dep_ft, lower(fiton) from tab2 END
Цель:
@Service public class Returnseveralresultset implements IReturnseveralresultset { @Autowired private JdbcTemplate jdbcTemplate; private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Returnseveralresultset.class); private Integer errorCode = 0; private String sqlState = ""; @Override public Map<String, Object> spReturnseveralresultset(Integer p1, String p2) throws Exception { Integer mStatus = 0; Map<String, Object> outData = new HashMap<>(); List<SqlRowSet> outRsList = new ArrayList<>(); SqlRowSet rowSet; try { rowSet = jdbcTemplate.queryForRowSet("select cob_ft, lower(buzon) from tab1 \r\n" + " where cob_id = ? and cob_ft = ?", p1, p2); outRsList.add(rowSet); rowSet = jdbcTemplate.queryForRowSet("select dep_ft, lower(fiton) from tab2"); outRsList.add(rowSet); return outData; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return outData; } finally { outData.put("status", mStatus); outData.put("rsList", outRsList); } } }
Источник:
create procedure datediffFn as declare @var1 int set @var1 = DATEDIFF(dd, '1999-01-01', '2000-02-01') set @var1 = DATEDIFF(mm, getdate(), '2000-02-01') set @var1 = DATEDIFF(week, '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000');
Цель:
public Integer spDatedifffn() throws Exception { Integer mStatus = 0; try { Integer var1 = null; var1 = Tsqlutils.datediff("dd", Tsqlutils.toTimestamp("1999-01-01"), Tsqlutils.toTimestamp("2000-02-01")); var1 = Tsqlutils.datediff("mm", new Timestamp(new java.util.Date().getTime()), Tsqlutils.toTimestamp("2000-02-01")); var1 = Tsqlutils.datediff("week", Tsqlutils.toTimestamp("2005-12-31 23:59:59.9999999"), Tsqlutils.toTimestamp("2006-01-01 00:00:00.0000000")); return mStatus; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return mStatus; } }
Источник:
create PROCEDURE spSendDbmail AS BEGIN EXEC msdb.dbo.sp_send_dbmail @profile_name = 'New DB Ispirer Profile', @recipients = '[email protected]', @body = '<h1>This is actual message embedded in HTML tags</h1>', @subject = 'Automated Success Message' , @file_attachments = 'C:\Temp\Attached.txt', @body_format='HTML', @copy_recipients = '[email protected]', @blind_copy_recipients = '[email protected]'; END
Цель:
import java.util.*; import com.ispirer.mssql.mail.MailService; public class Spsenddbmail { private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Spsenddbmail.class); public Integer spSpsenddbmail() throws Exception { Integer mStatus = 0; try { MailService.send("New DB Ispirer Profile", "Automated Success Message", "<h1>This is actual message embedded in HTML tags</h1>", "[email protected]", "[email protected]", "[email protected]", "C:\\Temp\\Attached.txt", "HTML"); return mStatus; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return mStatus; } } }
Источник:
create procedure workWithXml AS begin declare @result bit, @myDoc XML, @myStr varchar(1000), @ProdID INT SET @myDoc = '<Root> <ProductDescription ProductID="1" ProductName="Road Bike"> <Features> <Warranty>1 year parts and labor</Warranty> <Maintenance>3 year parts and labor extended maintenance is available</Maintenance> </Features> </ProductDescription> </Root>' SET @result = @myDoc.exist('(/Root/ProductDescription/@ProductID)[1]') SET @myStr = cast(@myDoc.query('/Root/ProductDescription/Features') as varchar(max)) SET @ProdID = @myDoc.value('(/Root/ProductDescription/@ProductID)[1]', 'int' ) end;
Цель:
import java.util.*; import com.ispirer.mssql.xml.XMLUtils; public class Workwithxml { private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Workwithxml.class); public Integer spWorkwithxml() throws Exception { Integer mStatus = 0; try { Boolean result = null; String myDoc = null; String myStr = null; Integer prodID = null; myDoc = "<Root> " + "<ProductDescription ProductID=\"1\" ProductName=\"Road Bike\"> " + "<Features> " + "<Warranty>1 year parts and labor</Warranty> " + "<Maintenance>3 year parts and labor extended maintenance is available</Maintenance> " + "</Features> " + "</ProductDescription> " + " </Root>"; result = XMLUtils.exist(myDoc, "(/Root/ProductDescription/@ProductID)[1]"); myStr = XMLUtils.query(myDoc, "/Root/ProductDescription/Features"); prodID = XMLUtils.<Integer > value(myDoc, "(/Root/ProductDescription/@ProductID)[1]", Integer.class); return mStatus; } catch (Exception e) { LOGGER.error(String.valueOf(e)); mStatus = -1; return mStatus; } } }
Благодаря нашим усилиям по настройке наша команда успешно разработала ряд методов для автоматизации перехода с T-SQL на Java. Это значительно сократило общее время миграции для всего проекта, что позволило нам ускорить миграцию в 4 раза по сравнению с потенциальной миграцией вручную. Настройка нашего набора инструментов не только ускорила переход, но и повысила общую эффективность проекта, продемонстрировав ценное влияние наших инициатив по настройке. Указанные в примерах методы предоставляются клиенту вместе с результатами преобразования.
В заключение отметим, что переход бизнес-логики с Transact-SQL на Java — это многогранный процесс, требующий всестороннего понимания обоих языков и их особенностей.
В этой статье мы подробно изучили миграцию бизнес-логики на уровень приложения и предоставили ценную информацию для тех, кто планирует такой переход. Случай нашего клиента доказывает, что подобные проекты модернизации можно автоматизировать, что существенно экономит время и силы при миграции. Проект нашего клиента служит убедительным свидетельством замечательного потенциала автоматизации. Это демонстрирует, что существуют аспекты модернизации, в которых автоматизация может успешно оптимизировать процессы, которые изначально могут оказаться за пределами ее возможностей.
В конечном счете, переход с Transact-SQL на Java — это стратегический шаг для организаций, стремящихся к большей гибкости, кросс-платформенной совместимости и масштабируемости. Несмотря на то, что он представляет собой ряд проблем, преимущества с точки зрения переносимости, производительности и адаптации к современным программным архитектурам делают этот переход стоящим усилием для тех, кто хочет модернизировать свои системы баз данных и приложения.