最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring hibernate實現(xiàn)動態(tài)替換表名(分表)的方法

 更新時間:2017年08月09日 09:05:38   投稿:jingxian  
下面小編就為大家?guī)硪黄猻pring hibernate實現(xiàn)動態(tài)替換表名(分表)的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

1.概述

其實最簡單的辦法就是使用原生sql,如 session.createSQLQuery("sql"),或者使用jdbcTemplate。但是項目中已經(jīng)使用了hql的方式查詢,修改起來又累,風(fēng)險又大!所以,必須找到一種比較好的解決方案,實在不行再改寫吧!經(jīng)過3天的時間的研究,終于找到一種不錯的方法,下面講述之。

2.步驟

2.1 新建hibernate interceptor類

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

  private String srcName = StringUtils.EMPTY; //源表名
  private String destName = StringUtils.EMPTY; // 目標(biāo)表名

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

這個interceptor會攔截所有數(shù)據(jù)庫操作,在發(fā)送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>
        <!-- 強(qiáng)制Hibernate以更人性化的格式將數(shù)據(jù)存入二級緩存 --> 
         <prop key="hibernate.cache.use_structured_entries">true</prop> 
         <!-- Hibernate將收集有助于性能調(diào)節(jié)的統(tǒng)計數(shù)據(jù) --> 
         <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對象的一個屬性,這點可以在LocalSessionFactoryBean類中可以看到,至于bean的注入為何是class的屬性而非class本身,那是因為它實現(xiàn)了 FactoryBean<SessionFactory> 接口。sessionFacotry是由LocalSessionFactoryBean對象配置后生成的。生成后將sessionFactory對象注入到了spring容器,且僅此一個而已,默認(rèn)單例嘛。

我們對數(shù)據(jù)庫的操作都是用session對象,它是由sessionFactory對象生成的。下面是sessionFactory對象的兩個方法:

/**
   * 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()獲取session對象的。

hibernate interceptor怎么配置呢?

LocalSessionFactoryBean對象的entityInterceptor屬性可以配置,你可以在xml中配置它,加到sessionFactory這個bean的xml配置中去。

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

那,它只能配置一個。因為sessionFactory是單例,他也只能是單例,引用sessionFactory的Dao對像也是單例,service,controller通通都是單例。那么有個問題就是,動態(tài)替換表名,如何動態(tài)?動態(tài)多例這條路已經(jīng)封死了。那只剩下,動態(tài)修改interceptor對象的值。聽起來像是不錯的建議。我嘗試后只能以失敗告終,無法解決線程安全問題!待會兒描述原因。

所以配置到xml中無法實現(xiàn)我的需求。那么就只能在代碼中設(shè)置了,還好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;
    }
}
/**
* 線程域變量,高效實現(xiàn)線程安全(一個請求對應(yīng)一個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) {
    。。。。

    //定制表名攔截器,設(shè)置到線程域
    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; 
}

紅色標(biāo)識的代碼就是核心代碼,核心說明。意思是,在DAO層對象中,注入sessionFactory對象創(chuàng)建session就可以操作數(shù)據(jù)庫了,我們改變了session的獲取方式。當(dāng)需要改變表名的時候,我們定義線程域變量,在需要interceptor的時候?qū)nterceptor對象保存到線程域中去,然后你操作的時候再拿到這個配置有攔截器的session去操作數(shù)據(jù)庫,這個時候interceptor就生效了。

不用線程域變量保存,直接定義對象成員變量肯定是不行的,因為會有并發(fā)問題(多個請求(線程)同時調(diào)用dao方法,dao方法執(zhí)行的時候又調(diào)用getSession()方法,可能當(dāng)你getSession的時候,別的請求,已經(jīng)把interceptor給換掉了。),當(dāng)然用synchronized也可以解決。線程域的使用,比synchronized同步鎖高效得多。線程域的使用,保證了interceptor對象和請求(線程)是綁在一起的,dao方法的執(zhí)行,只要執(zhí)行語句在同一個線程內(nèi),線程所共享的對象信息肯定一致的,所以不存在并發(fā)問題。

上面曾說過,單例interceptor不行,原因是:無法解決線程安全問題。 AutoTableNameInterceptor是一個單例,你在dao層可以修改他的值,比如新增set操作,沒問題??墒悄鉺et的同時,別的請求也在set,就會導(dǎo)致destName,srcName的值一直在變動,除非你的請求是串行的(排隊的,一個一個來的)。而且可能n個dao實例都會調(diào)用interceptor, 你怎么實現(xiàn)線程同步?除非你在dao操作的時候鎖住整個interceptor對象,這個多影響性能! 使用線程域,沒法實現(xiàn),經(jīng)過測試,發(fā)現(xiàn)hibernate底層會有多個線程調(diào)用interceptor方法,而不是我們的請求線程!所以,從dao到interceptor已經(jīng)不是一個線程。interceptor的onPrepareStatement回調(diào)方法又是如此的單調(diào),功能有限,哎。再說了,使用單例,是sessionFactory的全局配置,影響效率,通過代碼添加是臨時性的。

以上這篇spring hibernate實現(xiàn)動態(tài)替換表名(分表)的方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

您可能感興趣的文章:

相關(guān)文章

  • Java中自定義泛型方法及其應(yīng)用示例代碼

    Java中自定義泛型方法及其應(yīng)用示例代碼

    泛型方法是Java中一個強(qiáng)大的特性,它允許我們在方法級別使用類型參數(shù),提高代碼的復(fù)用性和類型安全性,通過本文,讀者可以學(xué)習(xí)如何定義和使用泛型方法,并了解其在處理集合、比較對象、創(chuàng)建實例等任務(wù)中的應(yīng)用,感興趣的朋友一起看看吧
    2025-02-02
  • springboot 多環(huán)境配置教程

    springboot 多環(huán)境配置教程

    這篇文章主要介紹了springboot 常用配置之多環(huán)境配置,需要的朋友可以參考下
    2018-04-04
  • Java獲取一維數(shù)組的最小值實現(xiàn)方法

    Java獲取一維數(shù)組的最小值實現(xiàn)方法

    這篇文章主要介紹了Java獲取一維數(shù)組的最小值實現(xiàn)方法,需要的朋友可以參考下
    2014-02-02
  • Java使用JDBC向MySQL數(shù)據(jù)庫批次插入10W條數(shù)據(jù)(測試效率)

    Java使用JDBC向MySQL數(shù)據(jù)庫批次插入10W條數(shù)據(jù)(測試效率)

    使用JDBC連接MySQL數(shù)據(jù)庫進(jìn)行數(shù)據(jù)插入的時候,特別是大批量數(shù)據(jù)連續(xù)插入(100000),如何提高效率呢?今天小編通過本教程給大家介紹下
    2016-12-12
  • Java中關(guān)于泛型、包裝類及ArrayList的詳細(xì)教程

    Java中關(guān)于泛型、包裝類及ArrayList的詳細(xì)教程

    泛型可以在類或方法中預(yù)支地使用未知的類型。這篇文章主要介紹了Java中關(guān)于泛型、包裝類及ArrayList的詳細(xì)教程,需要的朋友可以參考下
    2021-12-12
  • 詳解SpringBoot?統(tǒng)一后端返回格式的方法

    詳解SpringBoot?統(tǒng)一后端返回格式的方法

    今天我們來聊一聊在基于SpringBoot前后端分離開發(fā)模式下,如何友好的返回統(tǒng)一的標(biāo)準(zhǔn)格式以及如何優(yōu)雅的處理全局異常,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2022-05-05
  • SpringSecurity自定義資源攔截規(guī)則及登錄界面跳轉(zhuǎn)問題

    SpringSecurity自定義資源攔截規(guī)則及登錄界面跳轉(zhuǎn)問題

    這篇文章主要介紹了SpringSecurity自定義資源攔截規(guī)則及登錄界面跳轉(zhuǎn)問題,我們想要自定義認(rèn)證邏輯,就需要創(chuàng)建一些原來不存在的bean,這個時候就可以使@ConditionalOnMissingBean注解,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-12-12
  • Java生成遞增流水號(編號+時間+流水號)簡單示例

    Java生成遞增流水號(編號+時間+流水號)簡單示例

    這篇文章主要給大家介紹了關(guān)于Java生成遞增流水號(編號+時間+流水號)的相關(guān)資料,在開發(fā)項目漫長的過程中常常會遇到流水號需要自動生成的問題存在,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下
    2023-07-07
  • 詳解利用Spring加載Properties配置文件

    詳解利用Spring加載Properties配置文件

    本篇文章主要介紹了詳解利用Spring加載Properties配置文件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • 詳解SpringBean基于XML的裝配

    詳解SpringBean基于XML的裝配

    Bean的裝配可以理解為依賴關(guān)系注入,Bean的裝配方式也就是Bean 的依賴注入方式.Spring容器支持多種形式的Bean的裝配方式,如基于XML的Bean裝配,基于Annotation的Bean裝配和自動裝配等.本文就帶大家了解SpringBean基于XML的裝配,需要的朋友可以參考下
    2021-05-05

最新評論

宝山区| 泰州市| 宝坻区| 承德市| 从化市| 延庆县| 城固县| 博白县| 阜康市| 清苑县| 桃园县| 抚远县| 东平县| 邓州市| 自治县| 岳阳市| 广西| 万盛区| 新兴县| 自治县| 惠来县| 和田县| 新蔡县| 麻城市| 开原市| 西宁市| 塔城市| 镶黄旗| 鄄城县| 唐河县| 满洲里市| 闽清县| 翁源县| 宣武区| 衡东县| 勐海县| 旬邑县| 雅安市| 卓尼县| 连云港市| 辉南县|