旅のメモ、または象のコーヒーの味





あなたはすでに記事が何であるかを推測しましたか?





3年目、PostgreSQL DBMSを使用して大規模なJavaシステムを開発しました。 システムはデスクトップ、クライアントサーバーです。 経験豊富なシニアJava開発者はいないので、自分で考えなければなりません。 考え、構築し、破壊し、再び構築し、再び破壊する...

長年にわたって、データベースとの直接的な作業の整理と、これらのプラットフォームの相互接続の両方で、いくつかの経験が蓄積されてきました。これについては、この記事で説明します。



開発中に発生し決定したいくつかの問題を選択的に説明します。





1. ORMを使用する


Hibernateで使用される原則と、ほぼすべてのJava開発者の仕事がHibernateの知識を必要とするという事実により、このテクノロジーをシステムに統合することに執着しました。



ただし、ベクターグラフィックスを使用しているため、対応するセッターおよびゲッターを使用して、永続化オブジェクトとしてベクターオブジェクトを実行することは非常に不便であることが判明しました。 ベクターオブジェクトは複雑で、多くの論理プロパティ(つまり、グラフィックだけでなくロジック)もあります。 Hibernateでそれらをマップする方法-私は思いつきませんでした。

しかし、彼はXMLでオブジェクトの論理プロパティを記述する独自の構造を考え出しました。各プロパティにはテーブルとDB列が示され、それに基づいて動的SQLクエリを形成するアルゴリズムがあります。

したがって、ORMは使用しません。 JDBCを介して作業し、独自のXMLマッピングを使用します。

そして、DBMSへの依存はまだそこにあります、なぜなら ストアドプロシージャを(!!!)で省くことができません。



2.データベースへの接続の構成


PostgreSQL JDBCドライバー、java.sql.Connectionなど-各クラスで、接続を開閉します。



だから、最初の数ヶ月でした。

現在、1つのクラスがあります-接続マネージャ、非常に簡単です。 オブジェクト自体-接続(プロジェクト全体に1つ!)を格納し、データベースへのこの接続が安全でないため、特に複数のスレッドで同時に使用されないようにします。



3.プロジェクト内のSQLクエリの編成。


開発の開始時に、2番目のクラスごとにSQLクエリに遭遇する可能性がありました。 彼らは素晴らしかった。



しかし、データベースは並行して変更され、ある時点でテーブルを取得して名前を変更する必要がありました。 名前の変更は簡単ですが、プロジェクトはどうですか? リファクタリング? ただし、ソースコード内のテーブルへのすべての呼び出しの名前を変更できるのは、プロジェクトのコンテキスト置換の助けを借りる場合のみです。 しかし、環境はテーブル名がどこにあるのか、同じ名前の変数がどこにあるのかを知りません...

データベース内のテーブルの名前を変更するのに2日かかった後、データベースへのすべての SQLクエリを定数またはメソッドとして含む別のクラスを作成することにしました。 すべての定数は、「<query_type> _ <クラス名> _ <クエリの意味>」という1つの原則に従って名前が付けられます。 たとえば、Graphクラスで呼び出されるグラフィックラインのサンプルの定数はSELECT_GRAPH_LINESと呼ばれます 。 メソッドの場合、 selectGraphLines()と呼ばれます。 これで、SQLテキストの代わりに定数を使用した、簡単に変更可能な美しいコードが作成されました。



4. SQLクエリの実行の最適化。


PostgreSQLの設定方法については説明しません。 そして、よく知られているJDBCメソッド-PreparedStatement-executeBatch();について



挿入要求について話をすると、問題が発生します。大量の行をすぐにテーブルにすばやく挿入する方法ですか。

PostgreSQLはマルチ挿入、つまり あなたは次のようなものを書くことができます

insert into table (a, b, c) values ( (1,2,3), (4,5,6), (...) )
      
      





したがって、複数挿入を動的に形成することは適切ではありません。 一度書くだけで十分です

 PreparedStatement stmt = db.prepareStatement("insert into table (a, b, c) values (?, ?, ?)").
      
      





そして、ループで行います

 stmt.setString(1,a); stmt.setString(2,b); stmt.setString(3,c); stmt.addBatch();
      
      





それから

 stmt.executeBatch()
      
      





すべてのデータが非常に短い時間で挿入されます。

たとえば、単純なINSERTを使用して、約10 kBの1600個のxmlファイルからデータを挿入するには、10分以上かかりました。 executeBatchを使用した挿入は約2秒です。 したがって、同じ挿入要求の多くが使用される場合は常に、このようなスキームを使用することをお勧めします。



5. PostgreSQLでXPathを使用する


問題に直面しました。その答えはグーグルで見つけるのが難しいですが、PostgreSQLのドキュメントからは明らかではありません。

指定:xmlタイプフィールドを持つデータベース内のテーブル。

必須:一部のXML要素にそのような値とそのような値があるテーブルからすべてのレコードを選択するため。



もちろん、最も簡単なことはXPathを介してこれを行うことです。 私たちは書きます:

 SELECT xpath('//child/child/text()', < XML->) from 
      
      





すべてのエントリが空であることがわかります。 検索後、XMLデータはいわゆる デフォルトの名前空間、すなわち すべてのXMLタグは単純に記述されます。
 <xmltag></xmltag>
      
      



じゃない
 <ns:xmltag></ns:xmltag>
      
      





デフォルトのネームスペースを登録する必要があることを認識するのに長い時間がかかり、次のようにします。

 SELECT xpath('//my:root/my:child/text()', < XML->, ARRAY[ARRAY['my', 'http://example.com']]);
      
      





ここで、myは任意の単語です-名前空間名http:/ /example.com-xmlns

 xmlns="http://example.com"/
      
      





さらに、xpath-request内のすべての要素にmyという単語を接頭辞として付ける必要がありますが、属性は必要ありません。



6. PostgreSQLテキストエディターとストアドプロシージャ


これは、Netbeans SQL Editorのコードです

 CREATE FUNCTION AAA (a int, b varchar) RETURNS int AS $body$ BEGIN ... END $body$ LANGUAGE plpgsql;
      
      





エラーが発生します。 SQL WorkbenchとEclipseでも同じことが起こります。 また、JDBCドライバーを使用してSQLクエリを実行する多くのアプリケーションで。



そして問題は$ body $ -いわゆるドルクォートです。これは関数の本体を示すためにpostgresで使用されます。 $ body $は関数の本体を開き、閉じます。

pgAdminに問題はありません。 この場合はSQL Workbenchで特別に処理されますが、松葉杖が使用されます。エディターのストアドプロシージャの本文の末尾に特別な記号(代替区切り記号、デフォルトでは/)を付ける必要があります。



しかし、Netbeansでは機能しません。 また、Eclipseでも。



PS

もちろん、3年間はさらに多くの問題と質問がありました。 これは私が思い出したものであり、私が共有したかったものです。

この記事は、「これを行う」という権威ある声明ではありません。 この記事で説明されているタスクをどのように解決したかについての批判を見るのは興味深いでしょう。



All Articles