paint-brush
业务逻辑迁移速度比咖啡冲泡还要快by@ispirersystems
407
407

业务逻辑迁移速度比咖啡冲泡还要快

Ispirer Systems17m2023/11/10
Read on Terminal Reader

本文详细介绍了Ispirer协助一家金融咨询公司从Microsoft SQL Server迁移到Java的项目,优化系统架构并降低维护成本。该客户旨在将业务逻辑移至应用层,将 815,000 行代码 (LOC) 和 300 GB 数据传输到 PostgreSQL。自动化是最大限度地减少迁移费用的关键,提前定制的 Ispirer 工具包可实现 90% 的转换率。迁移过程涉及架构和数据转换、约束和触发器调整、性能优化、数据验证和安全设置对齐。文章还重点介绍了将业务逻辑移至应用程序层背后的原因,强调可扩展性、可维护性、易于开发和可重用性。代码转换的示例,例如 INSERT 语句、多结果集、DATEDIFF 方法、sp_send_dbmail 方法以及与 XML 相关的方法,都证明了自动化的有效性。定制工作显着加快了迁移速度,与手动迁移相比,总体时间减少了四倍。结论强调了从 Transact-SQL 过渡到 Java 的战略优势,为寻求现代化的组织提供了更大的灵活性、跨平台兼容性和可扩展性。
featured image - 业务逻辑迁移速度比咖啡冲泡还要快
Ispirer Systems HackerNoon profile picture

我们如何自动化 SQL Server 到 Java 的迁移并将速度提高 4 倍


本文致力于基于 Ispirer 为一家大型财务咨询公司实施的项目来介绍Microsoft SQL Server 现代化。客户利用 SQL Server 数据库的强大功能来高效处理、处理、访问和监督客户的财务信息。客户端旨在将SQL Server迁移到云端,同时优化系统架构和维护成本。


Ispirer团队提出将业务逻辑转移到Java,因为数据库是在OLTP模式下使用的。我们将仔细分析该主题并审查客户的项目,其中涉及将 SQL Server 业务规则转换为 Java。此外,我们将调查公司选择将 SQL 代码迁移到应用程序层的原因。这将涉及对整个过程的全面检查。


为了优化云基础设施的成本,客户决定将表和数据迁移到 PostgreSQL。由于我们专注于数据库和应用程序迁移,因此客户向我们寻求以下任务:


  • 将 815000 个 LOC 业务逻辑移至 Java 中的应用程序层。
  • 将 300 GB 数据和 3000 个表从 Microsoft SQL Server 迁移到 PostgreSQL。


由于项目规模庞大,客户努力通过实施自动化来最大限度地减少迁移费用。为了优化Ispirer Toolkit的效率,我们决定提前对其进行定制。这种方法使我们能够向客户团队提供一个工具,T-SCL 到 Java 的转换率约为 90%。


现在让我们更深入地了解表和数据的迁移。


从SQL Server到PostgreSQL:数据和表的迁移


让我们考虑一下客户选择从本地 SQL Server 迁移到云的原因。这种转变包括许多不可否认的优势:


  1. 节约成本。从 SQL Server 迁移到云中 PostgreSQL 的主要驱动因素之一是节省成本。客户过去发现在现场保留 SQL Server 数据库的成本很高。这是因为需要特殊设备、软件许可证和熟练的数据库管理员。 PostgreSQL 作为一个开源数据库,提供了一种经济高效的替代方案。客户可以通过使用云来节省资金。他们只需要为他们使用的东西付费,而不需要支付大笔的预付款。此外,他们可以减少运营支出。


  2. 可扩展性。云计算可以比本地基础设施更轻松地扩展,以服务更大的工作负载和更多用户。为了使本地系统能够根据业务需求进行扩展,组织必须购买并安装物理服务器、软件许可证、存储和网络设备,以在传统 IT 设置中扩展业务服务。在云上,大多数资源只需单击几下即可立即可用,并且可以根据所需的资源自动扩展和缩减。云中的 PostgreSQL 提供了高水平的可扩展性,使我们的客户可以根据需求轻松调整资源。


  3. 安全。由于云提供商提供的高级身份控制、访问管理和身份验证系统,采用云技术可提供显着的安全优势。通常,云提供商比内部 IT 团队或本地系统拥有更好的安全标准,从而使数据环境更安全。

    云中的强大加密可降低数据泄露的可能性。它包括分层安全性、良好的密钥管理和安全访问控制,可帮助企业有效控制用户访问。此外,云提供商严格监督物理访问,实施匿名、复制和加密等措施来加强数据保护。到 2025 年,预计大约80% 的企业将从物理数据中心过渡到云服务。这种转变是由云提供的增强的安全优势推动的。


在云中从 SQL Server 迁移到 PostgreSQL 需要仔细规划和执行,并牢记特定的注意事项。根据客户的项目,我们的团队重点介绍了 SQL Server 现代化的以下步骤:


  1. 模式和数据转换。数据应准确转换以满足 PostgreSQL 的要求。这可能涉及处理诸如日期格式和字符编码之类的细微差别。


  2. 约束和触发因素。了解两个数据库中约束和触发器的使用差异至关重要。有必要进行相应的必要修改。此外,触发器的功能可以移至应用程序中。然而,这项任务远非简单,因此有必要权衡利弊。


  3. 性能优化。迁移过程的优化可以最大限度地减少停机时间和数据传输时间。利用并行化、优化网络带宽并投资强大的硬件以实现高效迁移非常重要


  4. 数据验证和测试。需要对迁移的数据进行严格验证,以保证数据的完整性和功能性。广泛的测试可确保应用程序与新的 PostgreSQL 数据库无缝协作。


  5. 安全和权限。 PostgreSQL 中的安全设置、用户帐户和权限应配置为与原始 SQL Server 设置相匹配,以确保无缝过渡。


为什么将业务逻辑移至应用层?

过去,我们的客户将存储过程用于其业务逻辑,认为这可以提高性能。但说实话,与应用程序层相比,SQL 语言可能不是容纳业务逻辑的最佳选择。

事实上,SQL仅查询或修改数据库中的数据。很多人可能会向我们抛出烂番茄,因为 SQL 语言擅长执行复杂的连接、过滤和排序,以便从查询中准确获取所需的数据,仅此而已。那么为什么要改变任何东西并将业务逻辑带到应用程序级别呢?

这个问题似乎合乎逻辑。让我们更详细地回答一下。下面我们概述了您应该认真考虑将业务逻辑转移到应用程序的 4 个主要原因。客户决定将业务逻辑移至应用层的原因如下:

可扩展性

为了可扩展性,在应用程序级别存储业务逻辑是最好的选择。为什么?因为一般来说,扩展应用程序服务器资源比扩展数据库服务器资源要容易得多。这几乎是全世界都承认的。对于大多数网络应用程序来说,当需要处理大量流量时,添加更多服务器通常很容易。然而,除非您的数据库也可以扩展以适应增加的需求,否则额外应用程序服务器的价值就会减少。扩展数据库服务器比简单地添加应用程序服务器更具挑战性。

可维护性

将业务逻辑存储在数据库中可能会带来可维护性挑战。修改存储过程可能会破坏许多应用程序、限制可扩展性,并使遵循“不要重复自己”(DRY) 原则变得困难。超过 100 行的 SQL 代码通常会带来复杂性和故障排除困难。将业务逻辑分离到应用层可以方便新团队成员的进入,并为重构提供更直观的平台。

易于开发

对于对系统的业务规则进行编码,SQL 是一个糟糕的选择。它不灵活,我们不能依赖它来表示复杂的模型,因为它无法创建适当的抽象。这种限制是避免将其用于业务逻辑的关键原因。这与工具或支持无关,而是与 SQL 无法创建简单且富有表现力的域模型有关,这与提供更多机会的面向对象和功能设计形成鲜明对比。

可重复使用性

在软件开发中,在针对新任务调整现有代码时,重用代码是节省时间和成本的有效方法。面向对象编程(OOP)是一种促进代码回收的方法,使其适合各种应用程序。然而,数据库中常用的 SQL 为代码重用提供的灵活性有限。选项包括使用“视图”和“存储过程”,尽管后者可能会导致大量参数。为了确保为您的项目做出正确的选择,彻底探索每种方法至关重要。


将 Transact-SQL 转换为 Java

将 Transact-SQL 转换为 Java 涉及各种基本注意事项。该过程包括将 SQL 数据类型映射到其 Java 等效项,以确保准确的数据表示。它还包括将 SQL 查询转换为 Java 代码,其中 Java 依赖 JDBC 或 Hibernate 等库来处理数据库交互。此外,某些 ESQL 功能在 Java 中缺乏直接等效项,可能会给人一种自动转换效率低下的印象。

在项目的定制阶段,我们能够创建许多提高自动化率的转换解决方案。这些解决方案最初被认为不可能实现自动化,但最终证明是成功的。让我们深入研究其中一些的细节。


  1. 与 SCOPE_IDENTITY() 结合转换 INSERT 语句以获取插入到标识列中的最后一个标识值。

    来源:

 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; } } }
  1. 具有多个结果集的过程转换。

来源:

 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); } } }
  1. DATEDIFF方法的转换。由于 Java 没有直接的等效方法,Ispirer 团队开发了与此方法等效的方法,无需明确指定格式即可将 String 转换为 Timestamp。它使代码结果整洁且更易于阅读。下面的示例演示了如何使用它。

来源:

 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; } }
  1. sp_send_dbmail 方法的转换,该方法将电子邮件发送到指定的收件人。为此,开发了一个名为 MailService 的类。此方法可以发送具有详细规格的电子邮件,包括收件人 (TO)、副本收件人 (CC)、密件抄送收件人 (BCC)、信件主题、正文、附件等。为了保持主代码整洁,我们团队将该方法放置在一个单独的类中。

来源:

 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; } } }


  1. Ispirer 团队开发了一个用于转换 xml 数据类型的 XMLUtils 类及其方法,这些方法用于从存储在 XML 变量中的 XML 数据中获取任何信息。该方法的示例实现:

来源:

 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 是一项战略举措。虽然它带来了挑战,但在可移植性、性能和对现代软件架构的适应性方面的好处使得这种转变对于那些希望实现数据库系统和应用程序现代化的人来说是值得的。