【一】 原理模拟
1.session
1.Save() http://1035054540-qq-com.iteye.com/blog/1535689
2.update() 获取主键值,然后进行更新所有的字段数据,现在想来明白了为什么 Hibernate不可以在默认情况下不仅会更新需要更新的数据,而且不需要更新的字段也会得以更新。
它要动态的拼凑update语句。此时它自身还不知道需要更新那些字段,所以它只能所有的字段都加入其中。
Update tableName set a=?,b=?,c=? Where 主键=? 这个和save可以进行参考
要解决只更新我们需要更新的某个字段,其余字段不动的情况。
session.beginTraction();
Test t=new Test(); //假如,Test类有很多的属性; id ,name,age,hight……
t.setName("王树雄");
session.getTraction().comitt();
//上述这种默认情况,我们一旦修改name的值,那么整个属性字段都会发生变化;现在,我们只需修改name字段;
我们有如下两种解决办法
一、 第一中方法就是在cfg配置文件里面加上
<property name="dynamic-update ">rue</property>
这样的话我们只更新name的时候,其余字段是不会发生改变的;
二、使用Hql语句。
Session.create("update Test set name=? Where i主键 =?" );
显然,我们看到第二种情况麻烦一些;
3.delete() 这个方法的模拟实现应该是最简单的了。
Delete from Test where 主键=?
【二】hibernate基础配置
Hibernate.cfg.xml 这个配置文件是最重要的。在其中可以引入xml形式的 类.hbm.xml文件。也可以引入annotation形式的类。
Xml文件: <mapping resource="com/relation/Dream" />
Annotation 形式:<mapping class="com.relation.Dream" />
hibernate.cfg.xml:
hbni2ddl.auto:create(每次都创建表)、update。。。。
show_sql :true|false 显示语句与否
format_sql true}false 格式化显示与否,为了美观
先建表还是先建实体类—先建表
Annotation:要是某个字段类型是时间类型,那么在此字段的get方法上面加上如何注解
@Temproal
@Temporal(TemporalType.DATE) 只显示日期
//@Temporal(TemporalType.TIME) 只显示时间
//@Temporal(TemporalType.TIMESTAMP) 显示日期与时间
总共有四种方法
Native、identity、sequence、uuid
注解方式:@GeneratedValue
直接写上述情况相当于加了native。
(@GeneratedValue(strategy=GenerationType.AUTO)) mysql 是 auo_crement
IDENTITY(@GeneratedValue(strategy=GenerationType.IDENTITY)) sql server
SEQUENCE(@GeneratedValue(strategy=GenerationType.SEQUENCE)) oracle
UUID含义是通用唯一识别码 (Universally Unique Identifier) ,它适用于分布式系统的。也就是不同机器之间起到唯一识别的作用。
【四】关联关系
1.在husband这个类里面。一夫一妻制的情况
@OneToOne
@JoinColumn(name="wifeid") //指定生成的数据库字段名
public Wife getWife() {
return wife;
}
这里的joinColumn 指的是wife在husband这个表里面显示的列名是什么
2.多对一的情况,比如说。多个用户对应一张表。
User与group之间的关系
@ManyToOne //多对一关联 User是多的一方 Group是一的一方
@JoinColumn(name="groupid") //指定User表中生成与Group对应的字段名
public Group getGroup() {
return group;
}
joinColumn显示的也是在user表中,显示到呃group这个类对应的字段名;
3.一对多的情况
在一的这一端Group端users属性上进行注解配置
@OneToMany //一对多关联 Group是一的一方 User是多的一方
@JoinColumn(name="groupid") //指定User表中生成与Group对应的字段名 注意此处与多对一配置方式不同
public Set<User> getUsers(){ ……. }
Hibernate默认将OneToMany理解为ManyToMany的特殊形式,如果不指定生成的外键列@JoinColumn(name="groupId"),则会默认生成多对多的关系,产生一张中间表。
这个配置关系很奇怪,这是在一的一方进行配置的,而前面的例子是在多的一方配置的。加上joincolumn表示对方在当前类对应的表中存在时字段名。而这个一对多的例子确实在一的一方进行设置,在多的一方显示当前类对应表在对方表中的字段名;
双向关系:
配置规则:一般以多的一端为主,先配置多的一端
在多的一端User端配置group
@ManyToOne
@JoinColumn(name="groupid")
在一的一端Group端配置时,在users只需要加个mappedBy="groupid"
@OneToMany(mappedBy="group")
在一的一方设置mappedby(name=''value")value值和多的一方设置的joincolumn里面的name是一样的。否则会出现两个字段
3.双向多对多关系
在Teacher这一端的students上配置
@ManyToMany
@JoinTable(name="t_s",
joinColumns={@JoinColumn(name="teacher_id")},
inverseJoinColumns={@JoinColumn(name="student_id")}
)
在Student一端的teachers只需要配置
@ManyToMany(mappedBy="students")
【级联关系】
三种方法可避免全部删除的情况:
1. 去掉@ManyToOne(cascade={CascadeType.All})设置;
2. 直接写Hql语句执行删除;
3. 将user对象的group属性设为null,相当于打断User与Group间的关联,代码如下
session.beginTransaction();
User user = (User)session.load(User.class,1);
user.setGroup(null);
session.delete(user);
session.getTransaction().commit();
级联可以在任意一边设置,这样当删除当前类对应的表中的记录的时候,那么也将会删除掉与当前表与之相关的表中对应的记录,而如果与之关联表也是级联的,那么也将会删除掉与关联表关联的表中的记录,以此类推……
是在多的一方出现的问题,当多的一方获取记录的时候,关联fetch的值是eage的
1 1+N问题 (典型的面试题) (详见hibernate_2800_Hibernate_1+N项目)
a) @ManyToOne(fetch=FetchType.LAZY)
//fetch=FetchType.LAZY 解决N+1问题 说明如下:
//当多对一(@ManyToOne)已经设定属性" fetch=FetchType.LAZY "时
//只有当需要时(如:t.getCategory().getName()时)才会去获取关联表中数据 可以解决N+1问题
b) @BatchSize
//@BatchSize 解决N+1问题 说明如下:
//在与查询表(此例中为Topic类)关联的表类(此例中为Category类)头处加@BatchSize(size=5)
//表示每次可查出5条记录 从而减少了select语句的个数
c) join fetch
//join fetch 解决N+1问题 说明如下:
//修改hql语句为--" from Topic t left join fetch t.category c "
二级缓存
<property
name= "cache.use_second_level_cache">true</property>
<property
name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
注:使用EhCache二级缓存 需要导入ehcache-1.2.3.jar及commons-logging-1.0.4.jar包
<!--EndFragment-->