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

gaobudong 2010-11-24

大家有没有遇到过这样的情况,一个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-factoryname="HibernateSessionFactory0"><!--notethedifferentname-->

4<propertyname="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>

5<propertyname="connection.driver_class">com.mysql.jdbc.Driver</property>

6<propertyname="connection.url">jdbc:mysql://dbhost0:3306/mydb</property>

7<propertyname="connection.username">my_user</property>

8<propertyname="connection.password">my_password</property>

9<propertyname="hibernate.connection.shard_id">0</property><!--new-->

10<propertyname="hibernate.shard.enable_cross_shard_relationship_checks">true</property><!--11</session-factory>

12 </hibernate-configuration>

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

public interface ShardStrategy {

ShardSelectionStrategygetShardSelectionStrategy();

ShardResolutionStrategygetShardResolutionStrategy();

ShardAccessStrategygetShardAccessStrategy();

}

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

public class WeatherReportShardSelectionStrategy implements ShardSelectionStrategy {

publicShardIdselectShardIdForNewObject(Objectobj){

if(objinstanceofWeatherReport){

return((WeatherReport)obj).getContinent().getShardId();

}

thrownewIllegalArgumentException();

}

}

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

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

public class WeatherReportShardResolutionStrategy extends AllShardsShardResolutionStrategy {

publicWeatherReportShardResolutionStrategy(List<ShardId>shardIds){

super(shardIds);

}

publicList<ShardId>selectShardIdsFromShardResolutionStrategyData(

ShardResolutionStrategyDatasrsd){

if(srsd.getEntityName().equals(WeatherReport.class.getName())){

returnContinent.getContinentByReportId(srsd.getId()).getShardId();

}

returnsuper.selectShardIdsFromShardResolutionStrategyData(srsd);

}

}

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

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

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

  • 2.1的实现方法

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

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

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

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

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

 public class MyNamingStrategy extends DefaultNamingStrategy {  

publicstaticfinalMyNamingStrategyINSTANCE=newMyNamingStrategy();

publicStringclassToTableName(StringclassName){

return"SSE_"+className.toUpperCase()+"_"+Calendar.getInstance().get(Calendar.YEAR);

}

    }

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

  • 2.2的实现方法

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

配置文件方法:

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

public class BaseClass {

protectedLongid;

protectedStringname;

protectedStringtype;

    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">

<idname="id"type="java.lang.Long">

<columnname="ID"/>

<generatorclass="increment"/>

</id>

<propertyname="name"type="java.lang.String">

<columnname="NAME"length="64"/>

</property>

<propertyname="type"type="java.lang.String">

<columnname="TYPE"length="64"/>

</property>

<propertyname="description"type="java.lang.String">

<columnname="DESCRIPTION"/>

</property>

<union-subclassname="com.ibm.cdl.ospf.dynamicshift.dao.bean.ChildClassA"table="DYNAMIC_SHIFT_A_TABLE">

</union-subclass>

<union-subclassname="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)

publicclassAnnotationBaseClass{

@Id

protectedLongid;

@Column(name="NAME")

protectedStringname;

@Column(name="TYPE")

protectedStringtype;

@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"/>

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

相关推荐

LetonLIU / 0评论 2020-05-29
东方咖啡屋 / 0评论 2020-01-06