首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > 其他数据库 >

见习技术笔记-Hibernate应用 (一个Entity对应多个相同结构的数据库表)

2012-10-06 
实习技术笔记---Hibernate应用 (一个Entity对应多个相同结构的数据库表)大家有没有遇到过这样的情况,一个E

实习技术笔记---Hibernate应用 (一个Entity对应多个相同结构的数据库表)

大家有没有遇到过这样的情况,一个Entity对应多个相同结构的数据库表。

打个比方,

我们需要根据时间划分到同一个数据库结构相同的多个表中(情况1)

我们需要把数据分散在不同的数据库结构相同的多个表中(情况2)

而情况二又分为以下两种情况:

以一个与该Entity的业务逻辑无关的项作为分拆条件(情况2.1)

以一个与该Entity的业务逻辑有关的项作为分拆条件(情况2.2)

而2.2就是我要实现的情况。我们来单独一个一个讲解实现方法:

?

  • 1的实现方法:

    这个是老大先让我看的技术Hibernate Shards,上帝啊,这个manual也是纯英文的,差点没把我看死。

    最终发现她的实现方法就是通过不同的数据源配置以及strategy的自己实现来完成对于数据的分布式存储过程。

    http://www.hibernate.org/subprojects/shards.html

    有兴趣的同学可以自己阅读以下他的手册~可惜不能满足我的需求,于是就没有实现。

    简单的介绍如下:

    1 <!-- Contents of shard0.hibernate.cfg.xml -->
    2 <hibernate-configuration>
    3 <session-factory name="HibernateSessionFactory0"> <!-- note the different name -->
    4 <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
    5 <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    6 <property name="connection.url">jdbc:mysql://dbhost0:3306/mydb</property>
    7 <property name="connection.username">my_user</property>
    8 <property name="connection.password">my_password</property>
    9?<property name="hibernate.connection.shard_id">0</property> <!-- new -->?
    10?<property name="hibernate.shard.enable_cross_shard_relationship_checks">true</property> <!-- 11 </session-factory>?
    12 </hibernate-configuration>

    在配置sessionfactory的时候对于不同的数据库配置不同的shard_id方便之后的分配过程。

    public interface ShardStrategy {
    ????? ShardSelectionStrategy getShardSelectionStrategy();
    ????? ShardResolutionStrategy getShardResolutionStrategy();
    ????? ShardAccessStrategy getShardAccessStrategy();
    }

    以上为shard提供的一个接口,需要我们自己的需求进行实现,比如我需要根据不同的大陆保存在不同的数据库的同名表中,那么在ShardSelectionStrategy的实现当中就可以这样实现:

    public class WeatherReportShardSelectionStrategy implements ShardSelectionStrategy {
    public ShardId selectShardIdForNewObject(Object obj) {
    if(obj instanceof WeatherReport) {
    return ((WeatherReport)obj).getContinent().getShardId();
    }
    throw new IllegalArgumentException();
    }
    }

    只需要自己再continent类当中指定不同的Continent应该放在哪个数据库里就好(Shard_id来指定)。

    别忘了要把所有的接口都用自己的分配逻辑实现哦。

    public class WeatherReportShardResolutionStrategy extends AllShardsShardResolutionStrategy {
    public WeatherReportShardResolutionStrategy(List<ShardId> shardIds) {
    super(shardIds);
    }
    public List<ShardId> selectShardIdsFromShardResolutionStrategyData(
    ShardResolutionStrategyData srsd) {
    if(srsd.getEntityName().equals(WeatherReport.class.getName())) {
    return?Continent.getContinentByReportId(srsd.getId()).getShardId();?
    }
    return super.selectShardIdsFromShardResolutionStrategyData(srsd);
    }
    }

    但是由于这个分布式存储和读取的方法现在还是初级阶段,还不能支持排序和distinct这样的算法。

    因为比如select distinct(name) from Student 这样的方法,Shards会先后查询所有的数据库中的STUDENT表,在查询过程中他只能支持每个表的Distinct,但是所有的结果集中的distinct当前版本还是没有支持。

    真的希望他能够在之后的版本中尽快支持,因为这个可能这些缺陷可能是用户不使用他的一个最大的理由。

    • 2.1的实现方法

      ?对于这个需求的实现,Hibernate自己就可以通过配置hibernate自身的strategy实现。

      关于namingstrategy,我想我直接贴一个别人的贴子就可以了。

      http://www.iteye.com/topic/8486

      http://jinguo.iteye.com/blog/209642

      里面讲的很详细,我概括一下就是根据一些业务无关的属性来动态修改entity对应的表关系

      比如我们可以根据时间的不同来动态指派数据表:

      我们需要数据库表动态根据年份来划分,希望数据库表名为SSE_STUDENT_xxxx(年份)。就可以用以上的技术来实现。

      ?public class MyNamingStrategy extends DefaultNamingStrategy {??
      ??????? public static final MyNamingStrategy INSTANCE = new MyNamingStrategy();??
      ??????? public String classToTableName(String className) {??
      ??????? return "SSE_" +className.toUpperCase()+"_"+ Calendar.getInstance().get(Calendar.YEAR);??
      ??????? }??
      ??? }

      具体的大家可以看看我引用的帖子。

      • 2.2的实现方法

        不知道其它的大大怎么实现这个需求的,我的实现方法是使用继承来实现,用一个父类让他拥有所有需要的属性,让每个不同的子类单纯的继承他,而没有任何多余的属性。我的实现分为用配置文件完成和用annotation(注解)实现两种方法。

        配置文件方法:

        单纯的生成一个拥有id,name,type和description的实体类BaseClass

        public class BaseClass {
        ??? protected Long id;
        ??? protected String name;
        ??? protected String type;
        ??? protected String description;

        //getters and setters

        }

        然后让子类继承他:

        public class ChildClassA extends BaseClass {}

        public class ChildClassB extends BaseClass {}

        在BaseClass.hbm.xml中使用union-subclass来继承父类,而让父类声明为abstract:

        <class name="com.ibm.cdl.ospf.dynamicshift.dao.bean.BaseClass"
        ??? ????abstract="true">
        ??? ??? <id name="id" type="java.lang.Long">
        ??? ??? ??? <column name="ID" />
        ??? ??? ????<generator />?
        ??? ??? </id>
        ??? ??? <property name="name" type="java.lang.String">
        ??? ??? ??? <column name="NAME" length="64" />
        ??? ??? </property>
        ??? ??? <property name="type" type="java.lang.String">
        ??? ??? ??? <column name="TYPE" length="64" />
        ??? ??? </property>
        ??? ??? <property name="description" type="java.lang.String">
        ??? ??? ??? <column name="DESCRIPTION" />
        ??? ??? </property>
        ??? ????
        ??? ????<union-subclass?name="com.ibm.cdl.ospf.dynamicshift.dao.bean.ChildClassA" table="DYNAMIC_SHIFT_A_TABLE">
        ??? ??? </union-subclass>
        ??? ????<union-subclass?name="com.ibm.cdl.ospf.dynamicshift.dao.bean.ChildClassB" table="DYNAMIC_SHIFT_B_TABLE">
        ??? ??? </union-subclass>
        ??? </class>

        在hibernate.cfg.xml中这样写上mapping就搞定了~~

        <mapping resource="com/ibm/cdl/ospf/dynamicshift/dao/bean/map/BaseClass.hbm.xml" />

        简单吧,重点就在union-subclass来实现,如果需要再写一些工具类来让子类间进行转化或者管理都可以。

        接下来是annotation版的:

        先是实体类:

        @Entity
        @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
        public class AnnotationBaseClass {
        ??? @Id
        ??? protected Long id;
        ??? @Column(name="NAME")
        ??? protected String name;
        ??? @Column(name="TYPE")
        ??? protected String type;
        ??? @Column(name="DESCRIPTION")
        ??? protected String description;

        //getters and setters

        }

        注意这一句:@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS),即申明一个类一个数据库表。

        然后只要在子类中单纯的继承,然后使用@Entity然后声明具体的数据库表就可以了。

        @Entity
        @Table(name = "DYNAMIC_SHIFT_A_TABLE")
        public class AnnotationChildClassA extends AnnotationBaseClass {}

        在hibernate.cfg.xml中则是声明上具体的class mapping就可以了:

        <mapping class="com.ibm.cdl.ospf.dynamicshift.dao.bean.AnnotationChildClassA"/>
        <mapping class="com.ibm.cdl.ospf.dynamicshift.dao.bean.AnnotationBaseClass"/>

        ?

        希望以上的对大家有帮助~谢谢支持。

热点排行