この記事は、財務コンサルティングを行う大企業のために Ispirer が実施したプロジェクトに基づいたMicrosoft SQL Server の最新化に特化しています。この顧客は、SQL Server データベースの機能を利用して、顧客の財務情報を効率的に処理、処理、アクセス、および監視しました。クライアントは、システム アーキテクチャとメンテナンス コストを最適化しながら、SQL Server をクラウドに移行することを目的としていました。
Ispirer チームは、データベースが OLTP モードで使用されているため、ビジネス ロジックを Java に転送することを提案しました。私たちはこの主題を注意深く分析し、SQL Server ビジネス ルールの Java への変換を含むクライアントのプロジェクトをレビューします。さらに、企業が SQL コードをアプリケーション層に移行することを選択する背後にある理由を調査します。これには、プロセス全体の包括的な検査が含まれます。
クラウド インフラストラクチャのコストを最適化するために、クライアントはテーブルとデータを PostgreSQL に移行することにしました。当社はデータベースとアプリケーションの移行を専門としているため、お客様は次のタスクを当社に依頼しました。
プロジェクトの規模が大きいため、クライアントは自動化を導入することで移行費用を最小限に抑えるよう努めました。 Ispirer Toolkit の効率を最適化するには、事前にカスタマイズを行う必要があると判断しました。このアプローチにより、T-SCL から Java への変換率が約 90% となるツールをクライアントのチームに提供することができました。
次に、テーブルとデータの移行について詳しく見てみましょう。
お客様がオンプレミスの SQL Server からクラウドへの移行を選択した理由を考えてみましょう。この移行には、否定できない利点が多数含まれています。
コスト削減。 SQL Server からクラウド上の PostgreSQL への移行を促進する主な要因の 1 つはコスト削減です。クライアントは、SQL Server データベースをオンサイトに維持するのに費用がかかると感じていました。これは、特別な機器、ソフトウェア ライセンス、熟練したデータベース管理者が必要だったためです。 PostgreSQL はオープンソース データベースであり、コスト効率の高い代替手段を提供します。顧客はクラウドを使用することでコストを節約できます。多額の前払いをするのではなく、使用した分だけ支払う必要があります。さらに、運用にかかる費用も削減できます。
スケーラビリティ。クラウド コンピューティングは、オンプレミスのインフラストラクチャよりも簡単に拡張でき、より多くのワークロードとより多くのユーザーに対応できます。ビジネスのニーズに合わせてオンプレミス システムを拡張するには、組織は物理サーバー、ソフトウェア ライセンス、ストレージ、ネットワーク機器を取得して設置し、従来の IT 環境でビジネス サービスを拡張する必要がありました。クラウドでは、これらのリソースのほとんどは数回クリックするだけですぐに利用可能になり、必要なリソースに応じて自動でスケールアップまたはスケールダウンできます。クラウド内の PostgreSQL は高レベルのスケーラビリティを提供し、クライアントが需要に基づいてリソースを簡単に調整できるようにします。
安全。クラウド テクノロジーを採用すると、クラウド プロバイダーが提供する高度な ID 制御、アクセス管理、認証システムのおかげで、セキュリティ上の顕著な利点が得られます。多くの場合、クラウド プロバイダーは社内の IT チームやローカル システムよりも優れたセキュリティ基準を備えており、データ環境をより安全にしています。
クラウド内の強力な暗号化により、データ侵害の可能性が軽減されます。これには、多層セキュリティ、適切なキー管理、安全なアクセス制御が含まれており、企業がユーザー アクセスを効果的に制御するのに役立ちます。さらに、クラウド プロバイダーは物理的アクセスを厳しく監視し、匿名性、レプリケーション、暗号化などの対策を講じてデータ保護を強化します。 2025 年までに、約80% の企業が物理データセンターからクラウド サービスに移行すると予測されています。この変化は、クラウドによって提供されるセキュリティの強化によって促進されます。
SQL Server からクラウド上の PostgreSQL に移行するには、特定の考慮事項を念頭に置いて、慎重な計画と実行が必要です。クライアントのプロジェクトに基づいて、私たちのチームは SQL Server を最新化するための次の手順を強調しました。
スキーマとデータ変換。データは PostgreSQL の要件に合わせて正確に変換される必要があります。これには、日付形式や文字エンコーディングなどのニュアンスの処理が含まれる場合があります。
制約とトリガー。 2 つのデータベースにおける制約とトリガーの使用法の違いを理解することが重要です。それに応じて必要な修正を行う必要があります。さらに、トリガーの機能をアプリケーションに移動できます。ただし、この作業は決して簡単ではないため、メリットとデメリットを比較検討することが重要です。
パフォーマンスの最適化。移行プロセスを最適化することで、ダウンタイムとデータ転送時間を最小限に抑えることができます。効率的な移行のためには、並列化を利用し、ネットワーク帯域幅を最適化し、強力なハードウェアに投資することが重要です
データの検証とテスト。データの整合性と機能を保証するには、移行されたデータを厳密に検証する必要があります。広範なテストにより、アプリケーションが新しい PostgreSQL データベースとシームレスに動作することが保証されます。
セキュリティと権限。 PostgreSQL のセキュリティ設定、ユーザー アカウント、および権限は、元の SQL Server 設定と一致するように構成し、シームレスな移行を確保する必要があります。
以前、当社のお客様は、パフォーマンスが向上すると考えて、ビジネス ロジックにストアド プロシージャを使用していました。しかし、正直に言うと、アプリケーション層と比較した場合、SQL 言語はビジネス ロジックを格納するのに最適な選択ではない可能性があります。
実際、SQL はデータベース内のデータをクエリまたは変更するだけです。 SQL 言語は複雑な結合、フィルタリング、並べ替えを実行して、クエリから必要なデータだけを正確に取得することに優れているため、多くの人が腐ったトマトを私たちに投げつける可能性があります。では、なぜ何かを変更してビジネス ロジックをアプリケーション レベルに持ってくるのでしょうか?
この質問は論理的だと思われます。もっと詳しく答えてみましょう。以下に、ビジネス ロジックをアプリケーションに転送することを真剣に検討すべき 4 つの主な理由を概説します。ビジネス ロジックをアプリケーション層に移動するというクライアントの決定は、次の理由によって決定されました。
スケーラビリティを確保するには、ビジネス ロジックをアプリケーション レベルで保存することが最良の選択肢です。なぜ?一般に、データベース サーバー リソースを拡張するよりも、アプリケーション サーバー リソースを拡張する方が大幅に簡単だからです。これはほぼ広く認められています。ほとんどの Web アプリでは、処理すべきトラフィックが大量にある場合、サーバーを追加するのは通常は簡単です。ただし、増大する需要に対応できるようにデータベースを拡張できない限り、追加のアプリケーション サーバーの価値は減少します。データベース サーバーの拡張は、単にアプリケーション サーバーを追加するよりもはるかに困難です。
ビジネス ロジックをデータベースに保存すると、保守性に課題が生じる可能性があります。ストアド プロシージャを変更すると、多くのアプリケーションが中断され、拡張性が制限され、「Don't Reply Yourself」(DRY) 原則に従うことが困難になる可能性があります。 SQL コードが 100 行を超えると、多くの場合、複雑さが生じ、トラブルシューティングが困難になります。ビジネス ロジックをアプリケーション層に分離すると、新しいチーム メンバーの参入が容易になり、リファクタリングのためのより直感的なプラットフォームが提供されます。
SQL は、システムのビジネス ルールをエンコードする場合には適切な選択ではありません。これは柔軟ではなく、適切な抽象化を作成できないため、複雑なモデルを表すためにこれに依存することはできません。この制限が、ビジネス ロジックでの使用を避ける主な理由です。それはツールやサポートの問題ではなく、より多くの機会を提供するオブジェクト指向や機能的な設計とは対照的に、SQL ではシンプルで表現力豊かなドメイン モデルを作成できないという問題です。
ソフトウェア開発では、コードを再利用することは、既存のコードを新しいタスクに適応させるときに時間とコストを節約する効率的な方法です。オブジェクト指向プログラミング (OOP) は、コードのリサイクルを容易にする方法であり、さまざまなアプリケーションに適しています。ただし、データベースで一般的に使用される SQL では、コードを再利用する際の柔軟性が限られています。オプションには「ビュー」と「ストアド プロシージャ」の使用が含まれますが、後者ではパラメータが大量になる可能性があります。プロジェクトに適切な選択を確実に行うには、各方法を徹底的に検討することが不可欠です。
Transact-SQL を Java に変換するには、さまざまな重要な考慮事項が必要になります。このプロセスには、SQL データ型を Java の対応するデータ型にマッピングし、正確なデータ表現を保証することが含まれます。また、SQL クエリを Java コードに変換することも含まれており、Java は JDBC や Hibernate などのライブラリに依存してデータベースとの対話を処理します。さらに、特定の ESQL 機能には Java に直接相当する機能が欠けており、自動変換が非効率であるという印象を与える可能性があります。
プロジェクトのカスタマイズ段階で、自動化率を高める多くの変換ソリューションを作成することができました。これらのソリューションは、当初は自動化が不可能だと考えられていましたが、最終的には成功することが判明しました。それらのいくつかについて詳しく見てみましょう。
INSERT ステートメントを SCOPE_IDENTITY() と組み合わせて変換し、ID 列に挿入された最後の ID 値を取得します。
ソース:
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 への移行を受け入れることは、柔軟性、クロスプラットフォームの互換性、およびスケーラビリティの向上を求める組織にとって戦略的な動きとなります。課題はありますが、移植性、パフォーマンス、最新のソフトウェア アーキテクチャへの適応性の点で利点があるため、データベース システムとアプリケーションの最新化を検討しているユーザーにとって、この移行は価値のある取り組みとなります。