实习技术笔记---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>
<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 class="increment" /> 
        </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"/>

 

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值