アーカイブ水平表


ここでのアーカイブ水平分割テーブルは、1枚のテーブル内のデータが一定時間または一定のステータスビット変化を経た後、このデータをテーブルから消去してパフォーマンスを向上させ、消去したデータをアーカイブテーブルに格納する必要があることを意味します.この記事では、アーカイブ・テーブルのデータを読み取り、アーカイブ・テーブルのデータを元のテーブルに再移動できるようにコードを変更する方法について説明します.
コードはjava、hibernate、mysqlを例に挙げます.
まずタイマを作成し,タイミングよくデータをアーカイブテーブルにアーカイブし,SysAccountアカウントテーブルをSysAccountArテーブルにアーカイブする例を示す.SysAccountテーブルのプライマリ・キーは自己増加し、SysAccountArテーブルのプライマリ・キーは自己増加を設定せず、プライマリ・テーブルからアーカイブされたデータのプライマリ・キーを使用します.
その後、できるだけ少ない変更コードが採用され、ここではhibernateのentity-name機能が採用されている.すなわち、hbmのみがエンティティクラスを作成する必要はない.xml,得られた単一エンティティデータはMap形式,keyはクラスの属性,valueは値である.
SysAccount.hbm.xmlの内容は以下の通りです.
<hibernate-mapping>
    <class name="com.rbac.entity.SysAccount" table="sys_account" catalog="rbac" dynamic-insert="true" dynamic-update="true">
        <id name="id" type="java.lang.Long">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="username" type="java.lang.String">
            <column name="USERNAME" length="20" not-null="true">
                <comment>     </comment>
            </column>
        </property>
    </class> 
</hibernate-mapping>

SysAccountAr.hbm.xmlの内容は以下の通りです.
<hibernate-mapping>
    <class entity-name="SysAccountAr" table="sys_account_ar" catalog="rbac" dynamic-insert="true" dynamic-update="true">
        <id name="id" type="java.lang.Long">
            <column name="ID" />
            <generator class="assigned" />
        </id>
        <property name="username" type="java.lang.String">
            <column name="USERNAME" length="20" not-null="true">
                <comment>     </comment>
            </column>
        </property>
    </class>
</hibernate-mapping>

違いは、アーカイブ・テーブルのidを自己増加ではなく指定に設定する必要があることです.
entity-nameの値はhql文のテーブル名なので、パッケージ名を付けなくても簡潔です
entity-nameで検索したのはMapなので、Mapとエンティティークラスが互いに変換する方法が必要で、他のサイトで検索することができます.例えば
package com.rbac.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
public class MapConvertUtil {
 
 /**
  *  Map<String,Object>      ,    java        
  * @param clazz        
  * @param map       Map  
  * @return
  */
 public static Object mapToObject(Class clazz, Map<String,Object> map){
  
  if(map == null){
   return null;
  }
  
  Field[] fields = clazz.getDeclaredFields(); 
  Field field;
  Object o = null;
  try {
   o = clazz.newInstance();
  } catch (InstantiationException e1) {
   e1.printStackTrace();
  } catch (IllegalAccessException e1) {
   e1.printStackTrace();
  }
  for(int i=0; i<fields.length; i++){
   field = fields[i];   
   String fieldName = field.getName();
   //    null   
   if(map.get(fieldName)==null){
    continue;
   }
   //              
   String stringLetter=fieldName.substring(0, 1).toUpperCase();    
   //  set   ,  setId
   String setterName="set"+stringLetter+fieldName.substring(1);
   Method setMethod = null;
   Class fieldClass = field.getType();
   try {
    if(isHaveSuchMethod(clazz, setterName)){
     if(fieldClass == String.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, String.valueOf(map.get(fieldName))); 
     }else if(fieldClass == Integer.class || fieldClass == int.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, Integer.parseInt(String.valueOf(map.get(fieldName)))); 
     }else if(fieldClass == Boolean.class || fieldClass == boolean.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, Boolean.getBoolean(String.valueOf(map.get(fieldName)))); 
     }else if(fieldClass == Short.class || fieldClass == short.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, Short.parseShort(String.valueOf(map.get(fieldName)))); 
     }else if(fieldClass == Long.class || fieldClass == long.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, Long.parseLong(String.valueOf(map.get(fieldName)))); 
     }else if(fieldClass == Double.class || fieldClass == double.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, Double.parseDouble(String.valueOf(map.get(fieldName)))); 
     }else if(fieldClass == Float.class || fieldClass == float.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, Float.parseFloat(String.valueOf(map.get(fieldName)))); 
     }else if(fieldClass == BigInteger.class ){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, BigInteger.valueOf(Long.parseLong(String.valueOf(map.get(fieldName))))); 
     }else if(fieldClass == BigDecimal.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      setMethod.invoke(o, BigDecimal.valueOf(Double.parseDouble(String.valueOf(map.get(fieldName))))); 
     }else if(fieldClass == Date.class){
      setMethod = clazz.getMethod(setterName, fieldClass);
      if(map.get(fieldName).getClass() == java.sql.Date.class){
       setMethod.invoke(o, new Date(((java.sql.Date)map.get(fieldName)).getTime())); 
      }else if(map.get(fieldName).getClass() == java.sql.Time.class){
       setMethod.invoke(o, new Date(((java.sql.Time)map.get(fieldName)).getTime())); 
      }else if(map.get(fieldName).getClass() == java.sql.Timestamp.class){
       setMethod.invoke(o, new Date(((java.sql.Timestamp)map.get(fieldName)).getTime())); 
      }
     }
    }
   } catch (SecurityException e) {
    e.printStackTrace();
   } catch (NoSuchMethodException e) {
    e.printStackTrace();
   }   catch (IllegalArgumentException e) {
    e.printStackTrace();
   } catch (IllegalAccessException e) {
    e.printStackTrace();
   } catch (InvocationTargetException e) {
    e.printStackTrace();
   } 
   
  }
  return o;
 }
 
 /**
  *              
  * @param clazz
  * @param methodName
  * @return
  */
 private static boolean isHaveSuchMethod(Class<?> clazz, String methodName){
  Method[] methodArray = clazz.getMethods();
  boolean result = false;
  if(null != methodArray){
   for(int i=0; i<methodArray.length; i++){
    if(methodArray[i].getName().equals(methodName)){
     result = true;
     break;
    }
   }
  }
  return result;
 }
 
 /**
  *    Map,    java        
  * @param entity
  * @return
  */
 public static Map objectToMap(Object entity){
  try {
   return PropertyUtils.describe(entity);
  } catch (IllegalAccessException e) {
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   e.printStackTrace();
  }
  return null;
 }
}

そしてdao層の操作
package com.rbac.dao;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.Hibernate;
import org.springframework.stereotype.Component;
import com.rbac.common.BaseDaoSupport;
import com.rbac.entity.SysAccount;
import com.rbac.util.MapConvertUtil;
@Component("archiveDao")
public class ArchiveDao extends BaseDaoSupport{
 
 public void saveOrUpdateAccountAr(SysAccount account){
  super.getHibernateTemplate().saveOrUpdate("SysAccountAr", account);
 }
 
 public void saveOrUpdateAccountAr(Map map){
  super.getHibernateTemplate().saveOrUpdate("SysAccountAr", map);
 }
 
 
 public SysAccount getAccountById(Long id){
  //   HibernateDaoSupport.getSession  initialize
  //    getHibernateTemplate    collection is not associated with any session
  SysAccount account = (SysAccount)super.getSession().get(SysAccount.class, id);
  return account;
 }
 
 public Map getAccountArById(Long id){
  Map map = (Map)super.getSession().get("SysAccountAr", id);
  return map;
 }
 
 /**
  *            ,           ,         
  * @param username
  * @return HashMap,      key SysAccount,       key SysAccountAr
  */
 public Map<String,SysAccount> loadByNameIncludeAr(String username){
  Map<String,SysAccount> tableEntityMap = new HashMap<String,SysAccount>();
  List accountList = super.getSession().createQuery("from SysAccount where username=:username").setString("username", username).list();
  if(accountList.size()>0){
   tableEntityMap.put("SysAccount", (SysAccount)accountList.get(0));
   return tableEntityMap;
  }
  List accountArList =  super.getSession().createQuery("from SysAccountAr where username=:username").setString("username", username).list();
  if(accountArList.size()>0){
   Map accountArMap = (Map)accountArList.get(0);
   SysAccount account = (SysAccount)MapConvertUtil.mapToObject(SysAccount.class, accountArMap);
   tableEntityMap.put("SysAccountAr", account);
   return tableEntityMap;
  }
  return tableEntityMap;
 }
 
 /**
  *   SysAccount,  tabelname            ,         ,      
  * @param tableName    SysAccount,    SysAccountAr
  * @param account
  */
 public void saveOrUpdateAccount(String tableName, SysAccount account) throws Exception{
  if("SysAccount".equals(tableName)){
   super.getSession().saveOrUpdate(account);
  }
  else if("SysAccountAr".equals(tableName)){
   if(account.getId()==null){
    throw new Exception("       id");
   }
   Map arMap = MapConvertUtil.objectToMap(account);
   super.getSession().saveOrUpdate("SysAccountAr", arMap);
  }
 }
 
 /**
  *             ,id    
  * @param username
  */
 public void moveAccountFromAr(String username) throws Exception{
  Map<String,SysAccount> map = loadByNameIncludeAr(username);
  if(map.containsKey("SysAccountAr")){
   SysAccount account = map.get("SysAccountAr");
   Long arId = account.getId();
   
   //        ,    arId         
   if(super.getSession().get(SysAccount.class, arId)!=null){
    throw new Exception("id "+arId+",username "+username+"          ");
   }
   
   //   id,       ,         ,    save   id   
   // persist    detached entity passed to persist
   // save    , id     , save     
   // saveOrUpdate    ,      account 
   super.getSession().save(account);
   
   //        arId         
   super.getSession().createQuery("update SysAccount set id=:arId where id=:id").setLong("arId", arId).setLong("id", account.getId()).executeUpdate();
   //       
   super.getSession().createQuery("delete from SysAccountAr where id=:id").setLong("id", arId).executeUpdate();
   
  }
  else{
   throw new Exception("       "+username);
  }
 }
}

以上の機能には、エンティティをアーカイブ・テーブルに保存したり、アーカイブ・テーブルからエンティティを読み出したり、アーカイブ・テーブルのレコードをプライマリ・テーブルに移動したりする機能があります.
その後の拡張には、2次アーカイブ・テーブルの作成、プライマリ・テーブルに依存する他のプライマリ・テーブルのアーカイブ・テーブルの作成などが含まれます.