検索
ホームページJava&#&チュートリアルJavaのSpring Hibernateでテーブル名を動的に置き換える方法

1. 概要

実際、最も簡単な方法は、session.createSQLQuery("sql") などのネイティブ SQL を使用するか、jdbcTemplate を使用することです。ただし、プロジェクトでは HQL クエリが使用されており、変更するのは面倒で危険です。したがって、うまくいかない場合は、より良い解決策を見つける必要があります。 3 日間の研究の結果、最終的に良い方法を見つけました。それを以下に説明します。

2. ステップ

2.1 新しい Hibernate インターセプター クラスを作成します

/**
 * Created by hdwang on 2017/8/7.
 *
 * hibernate拦截器:表名替换
 */
public class AutoTableNameInterceptor extends EmptyInterceptor {

    private String srcName = StringUtils.EMPTY; //源表名
    private String destName = StringUtils.EMPTY; // 目标表名

    public AutoTableNameInterceptor() {}

    public AutoTableNameInterceptor(String srcName,String destName){
        this.srcName = srcName;
        this.destName = destName;
    }


    @Override
    public String onPrepareStatement(String sql) {
        if(srcName.equals(StringUtils.EMPTY) || destName.equals(StringUtils.EMPTY)){
            return  sql;
        }
        sql = sql.replaceAll(srcName, destName);
        return sql;
    }
}

このインターセプターは、すべてのデータベース操作をインターセプトし、SQL ステートメント内のテーブル名を送信前に置き換えます。

2.2 sessionFactory への設定

まず sessionFactory とは何かを見てみましょう。


<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
        <property name="dataSource" ref="defaultDataSource"></property>
        <property name="packagesToScan">
            <list>
                <value>com.my.pay.task.entity</value>
                <value>com.my.pay.paycms.entity</value>
                <value>com.my.pay.data.entity.payincome</value>
            </list>
        </property>
        <property name="mappingLocations">
             <list>
                 <value>classpath*:/hibernate/hibernate-sql.xml</value>
             </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">false</prop>
                <prop key="hibernate.hbm2ddl.auto">none</prop>
                <!-- 开启查询缓存 -->
                <prop key="hibernate.cache.use_query_cache">false</prop>
                <!-- 配置二级缓存 --> 
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <!-- 强制Hibernate以更人性化的格式将数据存入二级缓存 -->  
                  <prop key="hibernate.cache.use_structured_entries">true</prop> 
                  <!-- Hibernate将收集有助于性能调节的统计数据 -->  
                  <prop key="hibernate.generate_statistics">false</prop>
                  <!-- 指定缓存配置文件位置 -->
                  <prop key="hibernate.cache.provider_configuration_file_resource_path">/spring/ehcache.xml</prop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
                <prop key="hibernate.current_session_context_class">jta</prop>
                <prop key="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory</prop>
                <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
            </props>
        </property>
    </bean>
public class LocalSessionFactoryBean extends HibernateExceptionTranslator
        implements FactoryBean<SessionFactory>, ResourceLoaderAware, InitializingBean, DisposableBean {

    private DataSource dataSource;

    private Resource[] configLocations;

    private String[] mappingResources;

    private Resource[] mappingLocations;

    private Resource[] cacheableMappingLocations;

    private Resource[] mappingJarLocations;

    private Resource[] mappingDirectoryLocations;

    private Interceptor entityInterceptor;

    private NamingStrategy namingStrategy;

    private Object jtaTransactionManager;

    private Object multiTenantConnectionProvider;

    private Object currentTenantIdentifierResolver;

    private RegionFactory cacheRegionFactory;

    private Properties hibernateProperties;

    private Class<?>[] annotatedClasses;

    private String[] annotatedPackages;

    private String[] packagesToScan;

    private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    private Configuration configuration;

    private SessionFactory sessionFactory;

実際、sessionFactory は LocalSessionFactoryBean オブジェクトの属性です。これは、Bean インジェクションがクラス自体ではなくクラスの属性である理由です。 FactoryBean インターフェイスを実装します。 sessionFacotry は、LocalSessionFactoryBean オブジェクトを構成することによって生成されます。生成後、sessionFactory オブジェクトが Spring コンテナーに挿入されます。デフォルトでは、これが唯一のシングルトンです。
私たちは皆、sessionFactory オブジェクトによって生成されるセッション オブジェクトを使用してデータベースを操作します。以下は、sessionFactory オブジェクトの 2 つのメソッドです:

    /**
     * Open a {@link Session}.
     * <p/>
     * JDBC {@link Connection connection(s} will be obtained from the
     * configured {@link org.hibernate.service.jdbc.connections.spi.ConnectionProvider} as needed
     * to perform requested work.
     *
     * @return The created session.
     *
     * @throws HibernateException Indicates a problem opening the session; pretty rare here.     */
    public Session openSession() throws HibernateException;    /**
     * Obtains the current session.  The definition of what exactly "current"
     * means controlled by the {@link org.hibernate.context.spi.CurrentSessionContext} impl configured
     * for use.
     * <p/>
     * Note that for backwards compatibility, if a {@link org.hibernate.context.spi.CurrentSessionContext}
     * is not configured but JTA is configured this will default to the {@link org.hibernate.context.internal.JTASessionContext}
     * impl.
     *
     * @return The current session.
     *
     * @throws HibernateException Indicates an issue locating a suitable current session.     */
    public Session getCurrentSession() throws HibernateException;

次に、プロジェクトは getCurrentSession() を使用してセッション オブジェクトを取得します。

休止状態インターセプターを構成するにはどうすればよいですか?

LocalSessionFactoryBean对象的entityInterceptor属性可以配置,你可以在xml中配置它,加到sessionFactory这个bean的xml配置中去。


<property name="entityInterceptor">
      <bean class="com.my.pay.common.AutoTableNameInterceptor"/>
      </property>

まあ、設定できるのは 1 つだけです。 sessionFactory はシングルトンであるため、sessionFactory を参照する Dao オブジェクトもシングルトンにすることができ、サービスとコントローラーはすべてシングルトンになります。そこで質問があります。テーブル名を動的に置き換えるにはどうすればよいでしょうか?動的な複数のケースへの道はブロックされています。残っているのは、インターセプター オブジェクトの値を動的に変更することだけです。良いアドバイスのように聞こえます。私の試みは失敗に終わり、スレッドの安全性の問題を解決できませんでした。その理由については後述する。

そのため、XML で構成しても私のニーズを実現できません。幸いなことに、sessionFactory オブジェクトはそれを変更するためのエントリ ポイントを提供します。


@Resource(name = "sessionFactory")private SessionFactory sessionFactory;protected Session getSession(){        
if(autoTableNameInterceptorThreadLocal.get() == null){            
return this.sessionFactory.getCurrentSession();
        }else{
            SessionBuilder builder = this.sessionFactory.withOptions().interceptor(autoTableNameInterceptorThreadLocal.get());
            Session session = builder.openSession();            
            return session;
        }
}
/**
* 线程域变量,高效实现线程安全(一个请求对应一个thread)
*/
private ThreadLocal<AutoTableNameInterceptor> autoTableNameInterceptorThreadLocal = new ThreadLocal<>();

public List<WfPayLog> find(Long merchantId, Long poolId,String sdk, Long appId,String province,
            Integer price,
            String serverOrder, String imsi,Integer iscallback,String state,
            Date start, Date end, Paging paging) {
       。。。。

        //定制表名拦截器,设置到线程域
        autoTableNameInterceptorThreadLocal.set(new AutoTableNameInterceptor("wf_pay_log","wf_pay_log_"+ DateUtil.formatDate(start,DateUtil.YEARMONTH_PATTERN)));
        List<WfPayLog> wfPayLogs;
        if (paging == null) {
            wfPayLogs = (List<WfPayLog>) find(hql.toString(), params); //find方法里面有 this.getSession().createQuery("hql") 等方法
    } else { 
       wfPayLogs = (List<WfPayLog>) findPaging(hql.toString(), "select count(*) " + hql.toString(), params, paging); 
    }
       return wfPayLogs; 
}

赤でマークされたコードはコアコードとコアの説明です。これは、DAO層オブジェクトにおいて、sessionFactoryオブジェクトを注入してセッションを作成することでデータベースを操作できるようにするという意味で、セッションの取得方法を変更しました。テーブル名を変更する必要がある場合は、スレッド ドメイン変数を定義し、インターセプターが必要なときにインターセプター オブジェクトをスレッド ドメインに保存します。これにより、データベースを操作するためにインターセプターで構成されたセッションが取得されます。インターセプターが有効になる時間。

スレッド ドメイン変数を使用せずにオブジェクト メンバー変数を直接定義することは間違いなく不可能です。同時実行性の問題 (複数のリクエスト (スレッド) が dao メソッドを同時に呼び出し、dao メソッドの実行時に getSession() メソッドが呼び出される) が発生するためです。メソッドが実行されると、おそらく getSession のときにインターセプターが他のリクエストに置き換えられます)、もちろん synchronized で解決することもできます。スレッド ドメインの使用は、同期された同期ロックよりもはるかに効率的です。スレッド ドメインを使用すると、実行ステートメントが同じスレッド内にある限り、インターセプタ オブジェクトとリクエスト (スレッド) が確実に結び付けられ、スレッドによって共有されるオブジェクト情報が一貫している必要があります。したがって、同時実行の問題はありません。

上で述べたように、シングルトン インターセプターはスレッド セーフティの問題を解決できないため機能しません。 AutoTableNameInterceptor はシングルトンです。新しい set オペレーションを追加するなど、dao レイヤーでその値を変更することは問題ありません。ただし、設定中に他のリクエストも設定されるため、リクエストがシリアル (1 つずつキューに入れられる) でない限り、destName と srcName の値が変化し続けることになります。そして、おそらく n dao インスタンスがインターセプターを呼び出すでしょう。スレッドの同期はどのように達成するのでしょうか? dao の操作中にインターセプター オブジェクト全体をロックしないと、パフォーマンスに影響します。 これは、スレッド ドメインを使用して実現することはできません。テストの結果、リクエスト スレッドの代わりにインターセプター メソッドを呼び出す複数のスレッドが休止状態の下部に存在することがわかりました。したがって、dao からインターセプターまではスレッドではなくなります。インターセプターの onPrepareStatement コールバック メソッドは非常に単調で、機能が限られています。さらに、シングルトンの使用は sessionFactory のグローバル構成であり、コードを通じて追加するのは一時的なものです。

以上がJavaのSpring Hibernateでテーブル名を動的に置き換える方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
プラットフォームの独立性のためにネイティブコードを介してbytecodeを使用することの利点は何ですか?プラットフォームの独立性のためにネイティブコードを介してbytecodeを使用することの利点は何ですか?Apr 30, 2025 am 12:24 AM

bytecodeachievesplatformedentencedexedectedbyavirtualMachine(VM)、forexApplev.forexample、javabytecodecanrunrunrunnonydevicewithajvm、writeonce、runany "ferfuctionality.whilebytecodeOffersenhの可能性を承認します

Javaは本当に100%プラットフォームに依存していませんか?なぜまたはなぜですか?Javaは本当に100%プラットフォームに依存していませんか?なぜまたはなぜですか?Apr 30, 2025 am 12:18 AM

Javaは100%のプラットフォームの独立性を達成することはできませんが、そのプラットフォームの独立性はJVMとBytecodeを通じて実装され、コードが異なるプラットフォームで実行されるようにします。具体的な実装には、次のものが含まれます。1。bytecodeへのコンパイル。 2。JVMの解釈と実行。 3。標準ライブラリの一貫性。ただし、JVMの実装の違い、オペレーティングシステムとハードウェアの違い、およびサードパーティライブラリの互換性は、プラットフォームの独立性に影響を与える可能性があります。

Javaのプラットフォーム独立性は、コードの保守性をどのようにサポートしますか?Javaのプラットフォーム独立性は、コードの保守性をどのようにサポートしますか?Apr 30, 2025 am 12:15 AM

Javaは、「Write onse、Averywhere」を通じてプラットフォームの独立性を実現し、コードの保守性を向上させます。 2。メンテナンスコストが低いため、1つの変更のみが必要です。 3.チームのコラボレーション効率が高く、知識共有に便利です。

新しいプラットフォームのJVMを作成する際の課題は何ですか?新しいプラットフォームのJVMを作成する際の課題は何ですか?Apr 30, 2025 am 12:15 AM

新しいプラットフォームでJVMを作成することに直面する主な課題には、ハードウェアの互換性、オペレーティングシステムの互換性、パフォーマンスの最適化が含まれます。 1。ハードウェア互換性:JVMがRISC-Vなどの新しいプラットフォームのプロセッサ命令セットを正しく使用できるようにする必要があります。 2。オペレーティングシステムの互換性:JVMは、Linuxなどの新しいプラットフォームのシステムAPIを正しく呼び出す必要があります。 3。パフォーマンスの最適化:パフォーマンステストとチューニングが必要であり、ガベージコレクション戦略が新しいプラットフォームのメモリ特性に適応するように調整されます。

Javafxライブラリは、GUI開発におけるプラットフォームの矛盾にどのように対処しようとしていますか?Javafxライブラリは、GUI開発におけるプラットフォームの矛盾にどのように対処しようとしていますか?Apr 30, 2025 am 12:01 AM

javafxefcectivelyaddressessessistencisingisingidevidementsyusaplatform-agnosticscenegraphandcssstyling.1)itabstractsplatformspificsthroughascenegraph、Assuring-sunsinstentrenderingacrosswindows、macos、andlinux.2)

JVMがJavaコードと基礎となるオペレーティングシステムの間の仲介者としてどのように機能するかを説明します。JVMがJavaコードと基礎となるオペレーティングシステムの間の仲介者としてどのように機能するかを説明します。Apr 29, 2025 am 12:23 AM

JVMは、Javaコードをマシンコードに変換し、リソースを管理することで機能します。 1)クラスの読み込み:.classファイルをメモリにロードします。 2)ランタイムデータ領域:メモリ領域を管理します。 3)実行エンジン:実行バイトコードを解釈またはコンパイルします。 4)ローカルメソッドインターフェイス:JNIを介してオペレーティングシステムと対話します。

Javaのプラットフォーム独立におけるJava Virtual Machine(JVM)の役割を説明します。Javaのプラットフォーム独立におけるJava Virtual Machine(JVM)の役割を説明します。Apr 29, 2025 am 12:21 AM

JVMにより、Javaはプラットフォームを介して実行できます。 1)jvmは、bytecodeをロード、検証、実行します。 2)JVMの作業には、クラスの読み込み、バイトコード検証、解釈の実行、およびメモリ管理が含まれます。 3)JVMは、動的クラスの読み込みや反射などの高度な機能をサポートしています。

さまざまなオペレーティングシステムでJavaアプリケーションが正しく実行されるようにするために、どのような措置を講じますか?さまざまなオペレーティングシステムでJavaアプリケーションが正しく実行されるようにするために、どのような措置を講じますか?Apr 29, 2025 am 12:11 AM

Javaアプリケーションは、次の手順を通じて異なるオペレーティングシステムで実行できます。1)ファイルまたはパスクラスを使用してファイルパスを処理します。 2)System.getEnv()を介して環境変数を設定および取得します。 3)MavenまたはGradleを使用して、依存関係を管理し、テストします。 Javaのクロスプラットフォーム機能は、JVMの抽象化レイヤーに依存していますが、特定のオペレーティングシステム固有の機能の手動処理が必要です。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。