Como automatizamos a migração do SQL Server para Java e aceleramos 4 vezes
Este artigo é dedicado à modernização do Microsoft SQL Server a partir de um projeto realizado pela Ispirer para uma grande empresa que atua na área de consultoria financeira. O cliente aproveitou o poder de um banco de dados SQL Server para manipular, processar, acessar e supervisionar com eficiência as informações financeiras de seus clientes. O objetivo do cliente era migrar o SQL Server para uma nuvem e, ao mesmo tempo, otimizar a arquitetura do sistema e os custos de manutenção.
A equipe do Ispirer se ofereceu para transferir a lógica de negócios para Java porque o banco de dados é usado no modo OLTP. Analisaremos cuidadosamente o assunto e revisaremos o projeto do cliente, que envolve a conversão das regras de negócio do SQL Server para Java. Além disso, investigaremos os motivos pelos quais as empresas optam por migrar o código SQL para uma camada de aplicação. Isso envolverá um exame abrangente de todo o processo.
Para otimizar os custos da infraestrutura em nuvem, o cliente decidiu migrar tabelas e dados para PostgreSQL. Por sermos especializados em migração de banco de dados e aplicações, o cliente nos procurou com as seguintes tarefas:
- Movendo 815.000 LOC de lógica de negócios para a camada de aplicação em Java.
- Migrando 300 GB de dados e 3.000 tabelas do Microsoft SQL Server para PostgreSQL.
Devido à dimensão substancial do projeto, o cliente esforçou-se por minimizar as despesas de migração através da implementação da automação. Para otimizar a eficiência do Ispirer Toolkit, determinamos que sua customização deveria ser realizada com antecedência. Essa abordagem nos permitiu entregar uma ferramenta para a equipe do cliente, com taxa de conversão de T-SCL para Java de aproximadamente 90%.
Agora vamos nos aprofundar na migração de tabelas e dados.
Do SQL Server para PostgreSQL: migração de dados e tabelas
Vamos considerar os motivos pelos quais o cliente optou por migrar de um SQL Server local para a nuvem. Esta transição inclui uma série de vantagens inegáveis:
- Poupança de custos. Um dos principais fatores que impulsionam a migração do SQL Server para o PostgreSQL na nuvem é a economia de custos. O cliente costumava achar caro manter os bancos de dados do SQL Server no local. Isto se deveu à necessidade de equipamentos especiais, licenças de software e administradores de banco de dados qualificados. O PostgreSQL, sendo um banco de dados de código aberto, oferece uma alternativa econômica. Os clientes podem economizar dinheiro usando a nuvem. Eles só precisam pagar pelo que usam, em vez de fazer grandes pagamentos adiantados. Além disso, eles podem gastar menos em operações.
- Escalabilidade. A computação em nuvem pode ser dimensionada com mais facilidade do que a infraestrutura local para atender maiores cargas de trabalho e mais usuários. Para que um sistema local se adaptasse às necessidades de uma empresa, as organizações tiveram que adquirir e instalar servidores físicos, licenças de software, armazenamento e equipamentos de rede para expandir os serviços empresariais em ambientes de TI convencionais. Na nuvem, a maioria desses recursos está disponível instantaneamente com apenas alguns cliques e pode ser ampliada ou reduzida automaticamente, dependendo dos recursos necessários. O PostgreSQL na nuvem oferece um alto nível de escalabilidade, permitindo que nosso cliente ajuste facilmente os recursos com base na demanda.
- Segurança. A adoção da tecnologia de nuvem oferece vantagens de segurança notáveis graças aos controles avançados de identidade, gerenciamento de acesso e sistemas de autenticação fornecidos pelos provedores de nuvem. Muitas vezes, os provedores de nuvem têm melhores padrões de segurança do que as equipes internas de TI ou os sistemas locais, tornando o ambiente de dados mais seguro. A criptografia forte na nuvem reduz a chance de violações de dados. Inclui segurança em camadas, bom gerenciamento de chaves e controles de acesso seguros, que ajudam as empresas a controlar o acesso dos usuários de maneira eficaz. Além disso, os provedores de nuvem supervisionam rigorosamente o acesso físico, implementando medidas como anonimato, replicação e criptografia para fortalecer a proteção de dados. Até 2025, prevê-se que aproximadamente farão a transição de data centers físicos para serviços em nuvem. Essa mudança é impulsionada pelos benefícios de segurança aprimorados fornecidos pela nuvem.
Migrar do SQL Server para o PostgreSQL na nuvem requer planejamento e execução cuidadosos, com considerações específicas em mente. Com base no projeto do cliente, nossa equipe destacou os seguintes passos para modernização do SQL Server:
- Esquema e transformação de dados. Os dados devem ser transformados com precisão para atender aos requisitos do PostgreSQL. Isso pode envolver o tratamento de nuances como formatos de data e codificação de caracteres.
- Restrições e gatilhos. Compreender as distinções no uso de restrições e gatilhos nos dois bancos de dados é crucial. É necessário fazer as modificações necessárias em conformidade. Além disso, a funcionalidade dos gatilhos pode ser movida para o aplicativo. No entanto, esta tarefa está longe de ser simples, por isso é essencial pesar os prós e os contras.
- Otimização de performance. A otimização do processo de migração permite minimizar o tempo de inatividade e o tempo de transferência de dados. É importante utilizar a paralelização, otimizar a largura de banda da rede e investir em hardware poderoso para uma migração eficiente
- Validação e teste de dados. A validação rigorosa dos dados migrados é necessária para garantir a integridade e funcionalidade dos dados. Testes extensivos garantem que os aplicativos funcionem perfeitamente com o novo banco de dados PostgreSQL.
- Segurança e permissões. As configurações de segurança, contas de usuário e permissões no PostgreSQL devem ser configuradas para corresponder à configuração original do SQL Server, garantindo uma transição perfeita.
Por que mover a lógica de negócios para a camada de aplicação?
No passado, nossos clientes usavam procedimentos armazenados para sua lógica de negócios, pensando que isso melhoraria o desempenho. Mas sejamos honestos: a linguagem SQL pode não ser a escolha ideal para abrigar a lógica de negócios quando comparada à camada de aplicação. Na verdade, o SQL apenas consulta ou modifica os dados em um banco de dados. Aqui, muitos podem jogar tomates podres em nós, porque a linguagem SQL é boa para realizar junções, filtros e classificações complexas para obter exatamente os dados que você precisa de uma consulta e nada mais. Então por que mudar alguma coisa e trazer a lógica de negócios para o nível do aplicativo? A questão parece lógica. Vamos responder com mais detalhes. Abaixo descrevemos quatro razões principais pelas quais você deve pensar seriamente em transferir a lógica de negócios para o aplicativo. A decisão do cliente de mover a lógica de negócios para a camada de aplicação foi motivada pelos seguintes motivos:
Escalabilidade
Para escalabilidade, armazenar a lógica de negócios no nível do aplicativo é a melhor opção. Por que? Porque, em geral, é substancialmente mais fácil dimensionar os recursos do servidor de aplicativos do que dimensionar os recursos do servidor de banco de dados. Isto é quase universalmente reconhecido. Para a maioria dos aplicativos web, adicionar mais servidores geralmente é fácil quando há muito tráfego para gerenciar. No entanto, o valor dos servidores de aplicativos extras diminui, a menos que seu banco de dados também possa ser dimensionado para acomodar a demanda crescente. Dimensionar um servidor de banco de dados é consideravelmente mais desafiador do que simplesmente adicionar servidores de aplicativos.
Capacidade de manutenção
Armazenar lógica de negócios em um banco de dados pode criar desafios de manutenção. A modificação de procedimentos armazenados pode interromper muitos aplicativos, limitar a extensibilidade e tornar difícil seguir o princípio "Não se repita" (DRY). O código SQL que excede 100 linhas geralmente apresenta complexidades e dificuldades de solução de problemas. Separar a lógica de negócios na camada de aplicação pode facilitar a entrada de novos membros da equipe e fornecer uma plataforma mais intuitiva para refatoração.
Facilidade de desenvolvimento
SQL é uma escolha ruim para codificar as regras de negócios do seu sistema. Não é flexível e não podemos depender dele para representar modelos complexos porque não pode criar abstrações adequadas. Essa limitação é o principal motivo para evitar usá-lo na lógica de negócios. Não se trata de ferramentas ou suporte, trata-se da incapacidade do SQL de criar um modelo de domínio simples e expressivo, em contraste com o design funcional e orientado a objetos, que oferece mais oportunidades.
Reutilização
No desenvolvimento de software, a reutilização de código é uma forma eficiente de economizar tempo e custos ao adaptar o código existente para novas tarefas. A Programação Orientada a Objetos (OOP) é um método que facilita a reciclagem de código, tornando-o adequado para diversas aplicações. No entanto, o SQL, comumente usado em bancos de dados, oferece flexibilidade limitada para reutilização de código. As opções incluem o uso de "visualizações" e "procedimentos armazenados", embora estes últimos possam levar a uma abundância de parâmetros. Para garantir a escolha certa para o seu projeto, explorar minuciosamente cada método é essencial.
Convertendo Transact-SQL em Java
A conversão do Transact-SQL em Java envolve várias considerações essenciais. O processo inclui o mapeamento de tipos de dados SQL para seus equivalentes Java, garantindo uma representação precisa dos dados. Também abrange a tradução de consultas SQL em código Java, onde Java depende de bibliotecas como JDBC ou Hibernate para lidar com interações de banco de dados. Além disso, certos recursos ESQL não possuem equivalentes diretos em Java, dando potencialmente a impressão de que a conversão automática é ineficiente. Durante a fase de customização do nosso projeto, conseguimos criar diversas soluções de conversão que potencializaram a taxa de automação. Estas soluções, inicialmente consideradas impossíveis de automatizar, acabaram por se revelar bem-sucedidas. Vamos nos aprofundar nos detalhes de alguns deles.
- Converter uma instrução INSERT em combinação com SCOPE_IDENTITY() para obter o último valor de identidade inserido em uma coluna de identidade. Fonte:
ALTER PROCEDURE example1 AS BEGIN Declare @idBit int Declare @c int Insert Into tab (c) Values (@c) Set @idBit = SCOPE_IDENTITY() End
Alvo:
@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; } } }
- Conversão de procedimento com vários conjuntos de resultados.
Fonte:
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
Alvo:
@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); } } }
- Conversão do método DATEDIFF. Como Java não possui equivalentes diretos, a equipe do Ispirer desenvolveu um equivalente para esse método que converte String em Timestamp sem um formato especificado explicitamente. Isso torna o resultado do código organizado e mais fácil de ler. O exemplo abaixo demonstra como ele é usado.
Fonte:
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');
Alvo:
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; } }
- Conversão do método sp_send_dbmail que envia uma mensagem de email para os destinatários especificados. Para tanto, foi desenvolvida uma classe chamada MailService. Este método permite o envio de e-mails com especificações detalhadas, incluindo destinatários (TO), destinatários de uma cópia (CC), destinatários em cópia carbono oculta (BCC), assunto da carta, texto principal, anexos e muito mais . Para manter o código principal organizado, nossa equipe colocou o método em uma classe separada.
Fonte:
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
Alvo:
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; } } }
- A equipe Ispirer desenvolveu uma classe XMLUtils para converter o tipo de dados xml e seus métodos, que são usados para obter qualquer informação de dados XML armazenados em uma variável XML. Um exemplo de implementação do método:
Fonte:
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;
Alvo:
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; } } }
Graças aos nossos esforços de personalização, nossa equipe desenvolveu com sucesso uma série de técnicas para automatizar a transição de T-SQL para Java. Isso reduziu significativamente o tempo geral de migração de todo o projeto, permitindo-nos acelerar a migração 4 vezes em comparação com uma possível migração manual. A customização do nosso Toolkit não apenas agilizou a transição, mas também melhorou a eficiência geral do projeto, demonstrando o impacto valioso de nossas iniciativas de customização. Os métodos especificados nos exemplos são fornecidos ao cliente junto com os resultados da conversão.
Conclusão
Concluindo, a transição da lógica de negócios do Transact-SQL para Java é um processo multifacetado que requer uma compreensão abrangente de ambas as linguagens e de seus recursos distintos.
Neste artigo, exploramos detalhadamente a migração da lógica de negócios para uma camada de aplicativo e fornecemos insights valiosos para aqueles que estão planejando tal transição. O caso do nosso cliente prova que tais projetos de modernização podem ser automatizados, o que economiza significativamente tempo e esforço durante a migração. O projeto do nosso cliente serve como um testemunho convincente do notável potencial da automação. Demonstra que existem facetas de modernização onde a automação pode agilizar com sucesso processos que podem inicialmente parecer além das suas capacidades.
Em última análise, adotar a migração do Transact-SQL para Java é um movimento estratégico para organizações que buscam maior flexibilidade, compatibilidade entre plataformas e escalabilidade. Embora apresente os seus desafios, os benefícios em termos de portabilidade, desempenho e adaptabilidade às arquitecturas de software modernas fazem desta transição um esforço valioso para aqueles que procuram modernizar os seus sistemas e aplicações de bases de dados.