hibernate:get和load方法
代码执行到session.load(User.class,Id)并不执行SQL语句,而且通过get方法可以获取到Id的值,不管Id的值在数据库表中是否存在,且不执行SQL语句。
session.get(User.class,Id)则不一样,代码执行到这一行就会执行一条SQL查询语句,而且Id的值在数据库表中一定存在。网上有说get方法返回的一定是实体类,但是也有说是可能为代理对象。我比较赞成后者,通过代码也能看出来。
User user = (User) session.load(User.class, 11);
user.setUser_name("heihei");
Useru=(User)session.get(User.class, 11);
System.out.println(u.getUser_name());
数据库表中Id为11的用户名为haha,通过get方法获取的却是heihei,且后台数据库表中数据并没有改变。没执行update操作。
load、get查找数据是有一定的顺序的,各级缓存什么的。暂时没看到缓存这一块,不做记录,以后回头再做修改。
many2one单向:
add:
1、 先添加多one
例:ClassRoom cr=new ClassRoom();
cr.setName(“C”);
session.save(cr);
Stu stu=new Stu();
stu.setName(“clover”);
stu.setCla(cr);
session.save(stu);
这种情况,会执行两条插入SQL语句。
2、 先添加多
例: Stu stu=new Stu();
stu.setName(“clover”);
session.save(stu);
ClassRoomcr=new ClassRoom();
cr.setName(“C++”);
session.save(cr);
stu.setCla(cr);//stu为persistent状态
这种情况,执行的SQL比较多,两条插入语句一条更新语句。
3、 错误的情况
例: ClassRoom cr = new ClassRoom();
cr.setName(“Java”);
Stu stu = newStu();
stu.setName(“haha”);
session.save(stu);
stu.set(cr);
cr对象当前为transient,而stu已经转化为persistent状态。是不能这样做的。
异常信息:org.hibernate.TransientObjectException
load:
1、 one
先加载one,最后查询到的结果只能看到one。不能看到many的数据信息。
2、 many
先加载many,则可以通过关联字段查询到one的数据。而且many一方的数据具有懒加载的特性。
update:
更新什么的应该不会更新外键,所以不再说明。
delete:
肯定可以删除多的一方,不能删除one的一方。
many2one配置文件:
<hibernate-mappingpackage="been">
<classname="Student" table="tb_stu">
<idname="id">
<generatorclass="native"></generator>
</id>
<propertyname="name" />
<many-to-one name="cla" column="cid"cascade="all/delete/update"/>
</class>
</hibernate-mapping>
cascade:级联操作
删除操作室,级联操作不建议在many一方使用,因为many可能不是一条数据。在删除stu的时候,会级联删除Cla,而此时stu中还有别的数据关联cla此时就是报错。
many2one单向:
和one2many相反,不同的地方在于配置文件和代码:
配置文件:
<set name="comments"lazy="extra">
<keycolumn="cid" />
<one-to-manyclass="Comment" />
</set>
代码不同的地方,在于处理many的变量需要使用集合。所以对应的配置文件也发生变化。
需要说明的地方在于lazy:
lazy=”true”:懒加载,需要加载第二条SQL的时候才会加载;
lazy=”false”:不会懒加载;
lazy=”extra”:根据需要使用不同的SQL语句。比如查询留言下有多少评论,使用extra属性则会通过count查找。
one2many双向,就是one2many单向与many2one单向合在一起,就像齿轮相互咬合的感觉。
one2many单向和many2one单向使用的时候,维护关系只在一方。one2many双向则是通过任何一方都可以知道另外一方。
one2one单向和many2one单向很像,不同的地方在不one2one的关系是一对一的,不能多对一或者一对多。
配置文件:(维护关系的一方)
<hibernate-mappingpackage="been">
<classname="IDCard" table="tb_card">
<idname="id">
<generatorclass="native"></generator>
</id>
<propertyname="no" />
<many-to-onename="person" column="pid"unique="true"/>
</class>
</hibernate-mapping>
one2one双向:和many2one很像,个人感觉。
配置文件,在one2one的基础之上:
<hibernate-mappingpackage="been">
<classname="Person" table="tb_person">
<idname="id">
<generatorclass="native"></generator>
</id>
<propertyname="name" />
<!--name指定属性的名称,property-ref指定维护关系的一方为对端 -->
<one-to-onename="card" property-ref="person"/>
</class>
</hibernate-mapping>
insert、update and delete 不再说。
load:很奇怪的地方,如果首先load关系被维护的一方,hibernate会自动关联两张表查询,通过person查询idcard也只有一条SQL。
Personperson = (Person) session.load(Person.class, 1);
System.out.println(person.getName());
System.out.println(person.getCard().getId());
查询的SQL及结果:
Hibernate: select person0_.id asid6_1_, person0_.name as name6_1_, idcard1_.id as id5_0_, idcard1_.no asno5_0_, idcard1_.pid as pid5_0_ from tb_person person0_ left outer join tb_cardidcard1_ on person0_.id=idcard1_.pid where person0_.id=?
clover
1
如果load维护关系的一方,则是另外的一种情况:
IDCardid=(IDCard)session.load(IDCard.class, 1);
System.out.println(id.getNo());
System.out.println(id.getPerson().getName());
查询的SQL及结果:
Hibernate: select idcard0_.id asid5_0_, idcard0_.no as no5_0_, idcard0_.pid as pid5_0_ from tb_card idcard0_where idcard0_.id=?
123456
Hibernate: select person0_.id asid6_1_, person0_.name as name6_1_, idcard1_.id as id5_0_, idcard1_.no asno5_0_, idcard1_.pid as pid5_0_ from tb_person person0_ left outer join tb_cardidcard1_ on person0_.id=idcard1_.pid where person0_.id=?
Hibernate: select idcard0_.id asid5_0_, idcard0_.no as no5_0_, idcard0_.pid as pid5_0_ from tb_card idcard0_where idcard0_.pid=?
clover
many2many双向
直接上配置文件:
<hibernate-mappingpackage="been">
<classname="Role" table="tb_role">
<idname="id">
<generatorclass="native"></generator>
</id>
<propertyname="name" />
<setname="admins"table="tb_admin_role" lazy="extra">
<keycolumn="rid" />
<many-to-manyclass="Admin"column="aid" />
</set>
</class>
</hibernate-mapping>
<hibernate-mappingpackage="been">
<classname="Admin"table="tb_adm">
<idname="id">
<generatorclass="native"></generator>
</id>
<propertyname="name" />
<setname="roles" table="tb_admin_role"lazy="extra">
<keycolumn="aid" />
<many-to-manyclass="Role" column="rid" />
</set>
</class>
</hibernate-mapping>
至于单向,从任意一方删除的对应的属性就是了。
1、 增删改查
配置文件和原来使用xml不一样,不需要再配置xxx.hbm.xml文件,不过hibernate.cfg.xml文件需要之间指定实体类的路径:
<!-- 如果数据库表没有建立,会自动创建 -->
<propertyname="hibernate.hbm2ddl.auto">update</property>
<mapping class="been.User"/>
<mapping class="been.Cla"/>
<mappingclass="been.Student"/>
需要在类名前添加:
@Entity
@Table(name=”tb_user”)//指定表名
在对应的Id前添加:
@Id
@GeneratedValue
代码:
@Entity
@Table(name="tb_user")
public class User {
private intaccount;
private String user_name;
@Id
@GeneratedValue
public int getAccount() {
returnaccount;
}
·······
}
2、 many2one
one的一方,在many方维护两者的关系:
@Entity
@Table(name = "tb_cla")
public class Cla {
private intid;
private String name;
private Set<Student> stus;
public Cla() {
setStus(new HashSet<Student>());
}
@Id
@GeneratedValue
public intgetId() {
return id;
}
//在many维护关系的字段
@OneToMany(mappedBy="cla")
//查询数量的时候,可以智能使用count
@LazyCollection(LazyCollectionOption.EXTRA)
public Set<Student> getStus() {
return stus;
}
```````
}
many的一方:
@Entity
@Table(name = "tb_stu")
public class Student {
private int id;
private String name;
private Cla cla;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//启用懒加载的功能,懒加载添加在维护关系的一方
@ManyToOne(fetch = FetchType.LAZY)
//维护的关系的字段,外键
//使用这个,many2one只会创建两个表,否则会自动创建一个中间表
@JoinColumn(name = "cid")
public Cla getCla() {
return cla;
}
public void setCla(Cla cla) {
this.cla = cla;
}
····
}
3、 one2one
one2one和many2one很像,many2one或者one2many是一对多或者多对一的关系,而one2one可以使是这两者的特例,关系的两方都是一对一的关系。
代码:
维护关系方:
package been;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "tb_idCard")
public class IDCard {
private int id;
private String no;
private Person person;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "pid")
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
}
被维护关系:
package been;
import javax.persistence.*;
@Entity
@Table(name = "tb_person")
public class Person {
private int id;
private String name;
private IDCard card;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@OneToOne(mappedBy = "person")
public IDCard getCard() {
return card;
}
public void setCard(IDCard card) {
this.card = card;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4、 many2many
many2many和使用配置文件一样,一般使用两个many2one来实现。
PS:关于Id的想法,从学生的心理来说,在学校学习数据库的时候对已Id的想法是能不用就不用了,所以在hibernate刚接触的时候,感觉为啥非要用Id这个字段。特别是使用配置文件的时候,Id是必不可少的一个标签。在我工作的过程中,我也发现并不是每个表都有Id这个字段,但是主键却是必不可少的。这个Id,我想应该是封装hibernate的开发者,对经验的总结。我想,所有的框架也都是这样吧,对以往经验的高度总结,实现的代码的重构和复用。