cascade(与其相关的对象也发生相应变化):
CascadeType.PERSIST: 如果一个实体是受管状态, 或者当persist()函数被调用时, 触发级联创建(create)操作
CascadeType.MERGE: 如果一个实体是受管状态, 或者当merge()函数被调用时, 触发级联合并(merge)操作
CascadeType.REMOVE: 当delete()函数被调用时, 触发级联删除(remove)操作
CascadeType.REFRESH: 当refresh()函数被调用时, 触发级联更新(refresh)操作
CascadeType.ALL: 以上全部
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
private Set<User> users=new HashSet<User>();//------------
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(mappedBy="group",cascade={CascadeType.ALL}) // -----注释1
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
@Entity
public class User {
private int id;
private String name;
private Group group;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne(cascade={CascadeType.ALL}) //---------------------------
@JoinColumn(name="g_id")//-------注释2---------
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
@Test
public void testOne() {
Group group=new Group();
group.setName("g");
User user1=new User();
User user2=new User();
user1.setGroup(group);//存储Group时要用
user2.setGroup(group);
group.getUsers().add(user1);
group.getUsers().add(user2);
session.beginTransaction();
/*存储user
session.save(user);
*/
session.save(group);
//session.save(user2);
session.getTransaction().commit();
}
两个铁 律:双向关系在程序中要设定双向关联
双向关系中要设置mappedBy(在少的那方)
获取数据库内容时
i. User user=(User) session.get(User.class, 1) 产生的sql请求:
select
user0_.id as id0_1_,
user0_.g_id as g3_0_1_,
user0_.name as name0_1_,
group1_.id as id1_0_,
group1_.name as name1_0_
from
User user0_
left outer join
t_group group1_
on user0_.g_id=group1_.id
where
user0_.id=?
Group g=(Group) session.get(Group.class, 1);
ii. Group g=(Group) session.get(Group.class, 1);产生的sql请求:
select
group0_.id as id1_0_,
group0_.name as name1_0_
from
t_group group0_
where
group0_.id=?
只把自己查出来
以上看出查询多的那方hibernate默认会把一的那方也给查出,而查询一的那方并不会也查出多的那方
cascade(cud)不影响读取(r),读取用fetch设置,fetch两个值:FetchType.LAZY,FetchType.EAGER
例如可以设置上面@ManyToOne(cascade={CascadeType.ALL},fetch=FetchType.LAZY) 查询user时就不会再查询group内容,在session关闭之前(这里很容易出错如果是eager则没事),当用到group时如user.getGroup.getName()才会发送sql请求,用load也差不多
/**
* delete
* manytoone不设置cascade时,执行删除user时,只删除相应user
* 设置为all时也会 删除group以及所有与user相同g_id的其他user,解决方法:
* i.取消级联关系:user.setGroup(null);
* ii.session.createQuery("delete……");
*
*
* Group 也是同上
*
*/
1+n问题:
在多对一关系中,当我们需要查询多的一方对应的表的记录时,可以用一条sql语句就能完成操作。然而,在多的一方的实体类中的@ManyToOne标注的fetch的默认值是eager,这时,hibernate除了发出查询多的一方对应的表的记录的sql语句外,还会发出n(多方记录数)条sql语句,这就是1+n问题。如:bbs的板块(Category),主题(topic),回复(msg)。一个板块有多个主题,而一个主题属于一个板块,则Category和topic属于一对多的关系,在topic里设置@ManyToOne。当需要取出所有的主题时,只需要发出select * from topic一条语句就能做到。然而,hibernate会查询出每个topic所对应的Category,所以会发出1+n条sql语句。
解决的方法是:①设置@ManyToOne的fetch属性值为lasy,这种方式解决后,后面的n条sql语句按需而发。
②设置@BatchSize(size=5),这样发出的sql语句减少。这个设置在一定程度上提高了效率。
③用left join fetch,事实上Criteria用的就是这种方法(left join fetch w.category)。
//N+1
@Test
public void testQuery1() {
Session session = sf.openSession();
session.beginTransaction();
List<Topic> topics = (List<Topic>)session.createQuery("from Topic").list();//不设置lazy的话,发出n+1条sql语句
for(Topic t : topics) {
System.out.println(t.getId() + "-" + t.getTitle());
}
session.getTransaction().commit();
session.close();
}
//@BatchSize
@Test
public void testQuery3() {
Session session = sf.openSession();
session.beginTransaction();
//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
List<Topic> topics = (List<Topic>)session.createQuery("from Topic").list();
for(Topic t : topics) {
System.out.println(t.getId() + "-" + t.getTitle());
System.out.println(t.getCategory().getName());
}
session.getTransaction().commit();
session.close();
}
//join fetch
@Test
public void testQuery4() {
Session session = sf.openSession();
session.beginTransaction();
//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
List<Topic> topics = (List<Topic>)session.createQuery("from Topic t left join fetch t.category c").list();
for(Topic t : topics) {
System.out.println(t.getId() + "-" + t.getTitle());
System.out.println(t.getCategory().getName());
}
session.getTransaction().commit();
session.close();
}
list 和 iterator的区别:
①List:直接取出所有的记录将其封装成对象放到集合中。
Iterator:先取出所有记录的id(主键),当需要用到对应的id的记录时,再根据id发sql语句。
②list不会主动利用session级的缓存,因此list遍历时每次会到数据库中取数据。
Iterator会利用session的缓存,Iterator每次会到缓存中找,如果缓存中没有,再到数据库中取数据。
③Iterator默认使用二级缓存
list默认往二级缓存存数据,但是查询时不使用二级缓存。
@Test
public void testQueryIterate() {
Session session = sf.openSession();
session.beginTransaction();
//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
Iterator<Category> categories = (Iterator<Category>)session.createQuery("from Category").iterate();
while(categories.hasNext()) {
Category c = categories.next();
System.out.println(c.getName());
}
session.getTransaction().commit();
session.close();
}