0

カスタムの休止状態 ID ジェネレーターを作成しました。休止状態の専門家ではないので、自分のコードに関するフィードバックが欲しいです。生成された ID はselect max(id) from table、+1 です。

public class MaxIdGenerator implements IdentifierGenerator, Configurable {

    private Type identifierType;
    private String tableName;
    private String columnName;

    @Override
    public void configure(Type type, Properties params, Dialect dialect) {
        identifierType = type;
        tableName = (String) params.getProperty("target_table");
        columnName = (String) params.getProperty("target_column");
    }

    @Override
    public synchronized Serializable generate(SessionImplementor session,
            Object object) {
        return generateHolder(session).makeValue();
    }

    protected IntegralDataTypeHolder generateHolder(SessionImplementor session) {
        Connection connection = session.connection();
        try {
            IntegralDataTypeHolder value = IdentifierGeneratorHelper
                .getIntegralDataTypeHolder(identifierType
                        .getReturnedClass());
            String sql = "select max(" + columnName + ") from " + tableName;
            PreparedStatement qps = connection.prepareStatement(sql);
            try {
                ResultSet rs = qps.executeQuery();
                if (rs.next())
                    value.initialize(rs, 1);
                else
                    value.initialize(1);
                rs.close();
            } finally {
                qps.close();
            }
            return value.copy().increment();
        } catch (SQLException e) {
            throw new IdentifierGenerationException(
                    "Can't select max id value", e);
        }
    }
    }

知りたい:

  1. このマルチトランザクションセーフを作成するにはどうすればよいですか? (つまり、2 つの同時トランザクションがデータを挿入する場合、同じ ID が 2 度存在しないと安全に仮定するにはどうすればよいでしょうか?) -- ここでの唯一の解決策は、2 つの同時休止状態トランザクションが同時に実行されるのを防ぐことだと思います。彼らが同じジェネレーターを使用している場合、これは可能ですか?
  2. コードを改善できる場合:ハードコードされた 、などを使用する必要"select"があるとは思えません"target_column"...

ポイント 1) を保証するために、必要に応じて、Java クライアント コードの挿入を同期する際にフォールバックできます。

私がこの種のジェネレーターを使用している理由についてコメントしないでください: レガシー コードは依然として同じデータベースにデータを挿入し、このメカニズムを使用しています...そして変更することはできません。そして、はい、私は知っています、それはひどいです。

4

2 に答える 2

2

トランザクションセーフな動作を実現する最も簡単な方法は、最大IDを取得し、挿入ステートメントを実行するために使用するコードをトランザクションブロックに配置することだと思います。何かのようなもの:

Transaction transaction = session.beginTransaction();
//some code...
transaction.commit();
session.close()

また、可能な場合はネイティブSQLの代わりに、HQL(Hibernate Query Language)を使用してクエリを作成することをお勧めします。さらに、あなたの説明から、クエリから一意の結果、最大IDを期待していることがわかりました。したがって、executeQueryの代わりにクエリに対してuniqueResult()メソッドを使用できます。

于 2012-10-22T21:45:30.400 に答える
0

ID の生成に AtomicInteger を使用できます。これは、多くのスレッドで同時に使用できます。

他の ID プロバイダーを自由に使用できる場合は、UUID クラスを使用してランダム ID を生成することをお勧めします。

UUID.randomUUID();

ID を生成する他の方法を含むリンクを参照できます。

于 2012-10-23T07:34:54.823 に答える