关于Hibernate主键包含null值的改动方案

前言
最近公司跟另外一个公司在合作一个项目,不幸被卷入其中。这几天做了一个变态的工作,就是客户死活就要复合主键能够支持null值,甚至扬言不惜修改hibernate,于是他如愿了。
命题
数据表中设置为 主键的两个字段其中一个可以为空。
分析
经过分析,Hibernate3.0的beta1~3支持可以为空的 主键,但是之后就不再支持。同时,oracle也不支持可以为null的 主键,在建表的过程中,只能建立unique索引。
由此,建立可以为null的数据表 主键的方法是一种非标准化的做法。就像参考文献中 Hibernate作者所说的:
Comment by Gavin King [04/Mar/05 02:04 PM]
Hibernate 3 treats any key with a null value as null. This is reasonable because nulls in primary keys are completely evil and not allowed on most dbs.
为了满足命题要求,我们需要修改 Hibernate的代码。
参考文献
 
步骤
建立库表结构
以下是用于实验的表结构代码:
drop table CLASS1
create table class1
    (field1 varchar2(10 char) not null,
    field2 varchar2(30 char) ,
    f3 number(10,0) not null,
    f4 varchar2(10 char) not null)
create unique index uniq1 on CLASS1 (FIELD1 , FIELD2 );
 
代码
类定义的时候使用标准的 Hibernate的复合 主键结构。并且在映射配置文件中使用自定义的CRUD语句代替 Hibernate的自动生成语句。
文件Class1.java
package com.chinainsurance.platform.service.impl.test;
 
import java.io.Serializable;
 
public class Class1 implements Serializable {
    Class1ID id;
    Integer field3;
    String field4;
   
    public Integer getField3() {
       return field3;
    }
    public void setField3(Integer field3) {
       this.field3 = field3;
    }
    public String getField4() {
       return field4;
    }
    public void setField4(String field4) {
       this.field4 = field4;
    }
    public Class1ID getId() {
       return id;
    }
    public void setId(Class1ID id) {
       this.id = id;
    }
}
 
文件Class1ID.java
package com.chinainsurance.platform.service.impl.test;
 
import java.io.Serializable;
 
public class Class1ID implements Serializable {
    String field1;
    String field2;    // nullable
 
   
   
    public String getField1() {
       return field1;
    }
    public void setField1(String field1) {
       this.field1 = field1;
    }
    public String getField2() {
       return field2;
    }
    public void setField2(String field2) {
       this.field2 = field2;
    }
    public boolean equals(Object arg0) {
       return super.equals(arg0);
    }
    public int hashCode() {
       return field1.hashCode();
    }
   
   
}
定义的hbm文件内容如下:
<?xmlversion="1.0"?>
<!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <classname="com.chinainsurance.platform.service.impl.test.Class1"table="class1"lazy="false">
       <composite-idname="id"class="com.chinainsurance.platform.service.impl.test.Class1ID">
           <key-propertyname="field1"column="field1"type="java.lang.String"length="10"/>
           <key-propertyname="field2"column="field2"type="java.lang.String"length="30" />
       </composite-id>
       <propertyname="field3"column="f3"type="java.lang.Integer"length="20"not-null="true"/>
       <propertyname="field4"column="f4"type="java.lang.String"length="10"not-null="true"/>
      
       <loaderquery-ref="selectClass1"/>
 
       <sql-insert>INSERT INTO class1 (f3, f4, field1, field2) VALUES ( ?, ?, ?, ? )</sql-insert>
       <sql-update>UPDATE class1 SET f3=?, f4=? WHERE field1=? anD nvl(fielD2,'*')=nvl(?, '*')</sql-update>
       <sql-delete>DELETE FROM class1 where field1=? and nvl(fielD2,'*')=nvl(?, '*')</sql-delete>
 
    </class>
   
    <sql-queryname="selectClass1">
       <returnclass="com.chinainsurance.platform.service.impl.test.Class1">
           <return-propertyname="id">
              <return-columnname="field1"/>
              <return-columnname="field2"/>
           </return-property>
           <return-propertyname="field3"column="f3"/>
           <return-propertyname="field4"column="f4"/>
       </return>
      
       select * from class1 where field1=? and nvl(field2,'*')=nvl(?, '*')
    </sql-query>            
</hibernate-mapping>
 
修改的Hibernate源代码
经过调试跟踪,发现不支持null 主键的代码在org. hibernate.type.ComponentType的hydrate函数中,代码如下:
if ( val == null ) {
    if (isKey) return null; //different nullability rules for pk/fk
}
else {
    notNull = true;
}
为此,我们需要把这一段代码修改为如下:
if( val != null )
    notNull = true;
编译Hiberante
Hibernate的根目录下有build.bat,运行就可以编译生成hibernate3.jar,该文件也会在根目录下。
测试
使用如下的测试用例来测试以下结果:
 
package com.chinainsurance.platform.service.impl.test;
 
import java.util.List;
 
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
 
import com.chinainsurance.platform.service.helper.TaskServiceHelper;
 
import junit.framework.TestCase;
 
/*
drop table CIUSER.CLASS1
create table class1 (field1 varchar2(10 char) not null, field2 varchar2(30 char) , f3 number(10,0) not null, f4 varchar2(10 char) not null)
create unique index uniq1 on CIUSER.CLASS1 (FIELD1 , FIELD2 );
*/
public class TestClasses extends TestCase {
 
    HibernateTemplate dao;
   
    public TestClasses()
    {
       TaskServiceHelper.context = TestUtil.getContext();
       HibernateDaoSupport t = (HibernateDaoSupport) TaskServiceHelper.getDao("reportJobDao");
       dao = t.getHibernateTemplate();
    }
    protected void setUp() throws Exception {
       super.setUp();
    }
 
    protected void tearDown() throws Exception {
       super.tearDown();
       try{   clearClass1();    }catch(Exception e){}
    }
 
    private void clearClass1()
    {
       List list = dao.loadAll(Class1.class);
       for(int i = 0; i < list.size(); ++i)
       {
           dao.delete(list.get(i));
       }
    }
   
    private Class1 insertClass1()
    {
       Class1 obj1 = createClass1();
       try{
       dao.save(obj1);
       }
       catch(Exception e)
       {
           // System.out.println(e.toString());
       }
      
       return obj1;
    }
   
    private Class1 createClass1()
    {
       Class1 obj1 = new Class1();
       Class1ID id = new Class1ID();
       id.setField1("c1f1");
       id.setField2(null);
       obj1.setId(id);
      
       obj1.setField3(new Integer(1));
       obj1.setField4("c1f4");
 
       return obj1;
    }
   
    public void testClass1Add()
    {
       System.out.println("testClass1Add");
       dao.save(createClass1());
       clearClass1();
    }
 
    public void testClass1Delete()
    {
       System.out.println("testClass1Delete");
       Class1 obj1 = insertClass1();
      
       dao.delete(obj1);
    }
 
    public void testClass1Load()
    {
       System.out.println("testClass1Load");
       insertClass1();
      
       Class1ID id = new Class1ID();
       id.setField1("c1f1");
       id.setField2(null);
 
       Class1 obj1 = (Class1) dao.load(Class1.class, id);
       assertEquals(obj1.getId().getField1(), "c1f1");
       assertNull(obj1.getId().getField2());
       clearClass1();
    }
 
    public void testClass1Update()
    {
       System.out.println("testClass1Update");
      
       Class1 obj1 = insertClass1();
   
       obj1.setField4("ok");
       dao.update(obj1);
    }
 
    public void testClass1Find()
    {
       System.out.println("testClass1Find");
       insertClass1();
       List list = dao.find("from Class1 as c where c.id.field2 is null");
       assertTrue(list.size() > 0);
       clearClass1();
    }
   
    public void testClass1LoadAll()
    {
       System.out.println("testClass1LoadAll");
       insertClass1();
       List list = dao.loadAll(Class1.class);
       //assertTrue(list.size() > 0);
       //clearClass1();
       System.out.println("size = " + list.size());
       for(int i = 0; i < list.size(); ++i)
       {
           Class1 cls = (Class1)list.get(i);
           System.out.println("" + cls.getId().getField1() + cls.getId().getField2());
       }
      
       clearClass1();
    }     
   
}
 
智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值