hibernate主键生成策略

来源:互联网 发布:c语言经典编程案例 编辑:程序博客网 时间:2024/03/29 13:21
 


使用mySql生成联合主键需要注意的地方:
生成联合主键的各个列不可以为空,首先要设置好,也不可以有一个为主键,
因为主键只有一个,如果联合主键其中的一个为主键的话,那么就没有必要再去

生成联合主键了.

使用联合主键的时候要注意:联合主键需要实现serializable接口,实现了这个接口后还最好要重写
equals和toString()方法,这两个方法如果不写的话,刚开始是看不到错误的,但是等你开始真正的运行的时候就会报错了.

应该是任何的数据库的主键生成策略都是一样的.

在改造系统自动生成的联合主键的过程中注意修改好:
比如系统自动生成的是:
<composite-id name="id" class="com.dada.foreign.TwoId">
            <key-property name="id" type="java.lang.Integer">
                <column name="id" />
            </key-property>
            <key-property name="name" type="java.lang.String">
                <column name="name" length="20" />
            </key-property>
</composite-id>

如果想自己改造一下这个实体,让它只是需要一个类就可以,这种情况下
要这样来修改:

<composite-id>
            <key-property name="id" type="java.lang.Integer">
                <column name="id" />
            </key-property>
            <key-property name="name" type="java.lang.String">
                <column name="name" length="20" />
            </key-property>
</composite-id>

就是只是需要把composite标签里面的属性给删除掉就好了,然后再修改
系统自动生成的实体类,这个时候需要把包含在那个生成联合逐渐的实体
类中的属性都放入到生成实体的主体类当中,而且需要提供每个属性的
get和set方法,之后再添加一个只是包含了联合主键的构造方法就可以了.
然后再把没有用的属性都给删除掉,在对实体进行操作的时候,记住要首先
使用构造方法生成主键,然后再执行其他的操作.

联合主键是需要生成这个主键的hashCode和equals方法的

public class TwoId implements java.io.Serializable {

 // Fields

 private Integer id;
 private String name;

 getter and setters

 public boolean equals(Object other) {
  if ((this == other))
   return true;
  if ((other == null))
   return false;
  if (!(other instanceof TwoId))
   return false;
  TwoId castOther = (TwoId) other;

  return ((this.getId() == castOther.getId()) || (this.getId() != null
    && castOther.getId() != null && this.getId().equals(
    castOther.getId())))
    && ((this.getName() == castOther.getName()) || (this.getName() != null
      && castOther.getName() != null && this.getName()
      .equals(castOther.getName())));
 }

 public int hashCode() {
  int result = 17;

  result = 37 * result + (getId() == null ? 0 : this.getId().hashCode());
  result = 37 * result
    + (getName() == null ? 0 : this.getName().hashCode());
  return result;
 }

}

--------------------------------------------------------------------------------------------------
使用annotation生成联合主键

1.把提供主键的类设置为@Embeddable表明这个类可以作为一个嵌入的类,然后在需要此类的地方进行引用时为这个
组件的引用加上@Id注解就可以了.

2.将组件的属性设置为Embeddable,就是说这个组件类本身是不带有注解的,但是对它进行引用的实体就需要在使用
它的时候对他加上Embedded这个注解

3.将实体类设置为IdClass,然后把实体中所有属于主键的属性给标注为@Id就行了.

三种方式的使用情况,第一种的使用情况是非常少的,因为第二种就可以直接的比它少了一步,第二种方式是最常用的,
第三种也有用的,但是用的少,为什么呢?
这个是因为如果使用了联合主键之后,自己总还是需要从数据库中去读取东西的,这个时候呢就有必要把它给读出来,
怎么读呢?使用面向对象的方法就需要提供主键的对象,这个时候就需要使用到它了.

--------------------------------------------------------------------------------------------------
一对一单相外键关联

这种情况就会导致的是在此表中会多生成一个字段那就是wife_id是作为这个表的一个外键.
如果要指定生成的外键字段就需要这样设置:

  @OneToOne
 @JoinColumn(name="wifeId")
 private Wife1 wife;

 

@Entity
public class Husband1 {
 @Id
 @GeneratedValue
 private Integer id;
 private String name;
 @OneToOne
 private Wife1 wife;

 public Wife1 getWife() {
  return wife;
 }


}

当然双向关联就容易了,只需要在wife实体中也持有一个对Husband的引用就可以了.
但是又这样的一个需求,就是,需要设置双向的关联,但是实际上只需要在自己或者对方
设置一个引用就可以了,就是说,两个表虽然是双向的关联,但是并不需要设置两个外键
这样设置是多余的,这种情况下应该怎么弄呢?
这个时候应该在不需要设置外键的一方中设置好mappedBy就好了,如下

@OneToOne(mappedBy="wife")
 private Husband1 husband1;

其中mappedBy的意思是这个外键关系是由对方来主导的,使用的是对方的wife属性来主导的.
这样设置之后就可以达到使用一个外键而得到双向关联的目的了.

在xml中这种双向关联,只生成一个外键的设置方式是:
<one-to-one name="wife" property-ref="student">
同样的,这里的student也是对方实体里面的一个引用.

只要有双向关联必然需要设置mapped

如果是设置为一对一的主键关联的话,就把
 @JoinColumn(name="wifeId")
 修改为
 @PrimaryKeyJoinColumn
--------------------------------------------------------------------------------------------------
多对多单向关联
单向关联只需要在一方设置好关联关系就好了,另外的一方不要设置的.

@Entity
public class Student {
 @Id
 private int id;
 private String name;
 @ManyToMany
 private Set<Teacher> teachers = new HashSet<Teacher>();

}
注意在这个地方设置@ManyToMany的mappedBy属性是没有用的,因为
它根本不需要生成外键,而是生成一个中间表,这个时候如果想要指定
生成的中间表的名称和中间表中的字段的名字的话,就需要设置:

@JoinTable(
   name="t_s",//指明中间表的名字
   joinColumns={@JoinColumn(name="stu_id")},//指明本实体
   //的主键在中间表中的外键的名字
   inverseJoinColumns={@JoinColumn(name="tea_id")}
   //指明另外一方实体在中间表中的外键的名字.
 )
 
 
在xml配置中中间表的名称是在类的hbm的<set>标签中配置的.
 
 

 ---------------------------------------------------------------------------------------------------------------------------------------------------

 Hibernate更新指定的字段

1需求,有一个表里面记录的是学生的姓名,学号和他的爱好论文这个时候如果这个表需要更新,
那么在hibernate中默认的更新是把所有的字段全部都更新一遍,因此就会出现在更新一个人的
爱好的时候却需要把论文也更新的情况,这种情况很显然很耗资源也没有必要,这个时候可以这样
配置
在对应的论文字段上加上注解@Colum(updatable=false);
或者在对应的xml的配置文件中配置一下<property>标签的update属性也是可以的.

但是上面的这两种方式都太不灵活了,因此需要使用第三种方式就是在xml中配置
<hibernate-mapping>
 <class catalog="shopping" name="com.dada.entities.Notebook" table="notebook" dynamic-update="true">
 这个时候呢就是dynamic-update="true"这句话起作用了,它可以动态的去修改.
 
  不过这种动态的改变有个限制就是只能够在xml文件中去配置,而不可以在annotation中去配置,所以
  如果需要使用动态的改变的话,就使用xml去配置这个文件就好了.
  当然如果不想使用这种动态的配置的话,也可以使用类似于sql的hql语句来实现对特定的一个字段进行修改.
 
 
 但是即便是动态的修改它还是有条件的,条件就是动态修改的条件,如何才能知道哪些属性改变了呢?
 肯定是拿现在的属性跟数据库的属性进行了比较了,那怎么跟数据库里面的数据进行比较呢?
 那肯定是把数据库里面的东西给load进入内存里面了,这样才能对修改后的内容跟修改之前的内容进行比较
 
 所以就是执行动态代理的条件就是,被执行动态代理的对象是持久化的也就是被load或者get进入内存的.
 
 但是有的时候会出现这种需求就是跨session去修改数据库,这个时候应该使用的是merge()它的意思是合并
 这个在hibernate中实现的细节是:先从数据库中去load这个对象,之后再把要合并的东西跟数据库里面的进行
 对比,然后再去修改到数据库里面.
 
 clear()清空缓存内容;
 flush:强制缓存内容与数据库同步;
 
 比如
 p.setName("a");
 p.setName("aa");
 session.save(p);
 这个时候hibernate中会生成一条语句这个时候只是执行最后一次的更新.
 如果使用的是
 p.setName("a");
 session.flush();
 p.setName("aa");
 session.save(p);
 
  session.flush();
 这句话会产生这样的效果:
 1.hibernate会向数据库发送两条语句,一条是执行第一个更改
 2.执行第二次更改
 
 如果把session.flush();换成为session.clear();
 那么结果就是内存被清空,然后呢持久化的对象都没有了这个时候,当然就谈不上是更改了.
 
 当然在执行commit();方法的时候,系统就会默认的实现flush();这个方法的.
 

 


 

原创粉丝点击