Hibernate 反向生成 产生BigInteger的解决方法:java
你应该用的Oracle吧,不要用里面的number做为主键,数据库中使用long或者int.这样反响工程的到的主键就是Long或者Intger类型的了。sql
问题解决了,只要给主键加个精度就行了使用Number(20)数据库
<set name="children" lazy="true" cascade="all">session
在保存主表的时候,若是没有保存从表信息,会抛出异常,若是设置了级联关系,能够自动先保存从表,在保存主表app
all: 全部状况下均进行关联操做,即save-update和delete。
none: 全部状况下均不进行关联操做。这是默认值。
save-update: 在执行save/update/saveOrUpdate时进行关联操做。dom
<set name="children" lazy="true" inverse="true">ide
<class name=”mypack.Customer” table=”CUSTOMER” lazy=”false”>测试
laz Lazy属性为false:当即检索,一次性访问有关联关系的全部表。fetch
llaz Lazy属性为true:(默认)延迟检索,只访问主表数据,从表数据不会当即访问,只有当用到从表的时候会自动访问。this
Lazy的有效期:只有在session打开的时候才有效;session关闭后lazy就没效了。
<class name=”mypack.Customer” table=”CUSTOMER” fetch =”join”>
fetch="join”:相似于lazy=false,一次性查完
fetch="select”:相似于lazy=true
Hibernate 的延迟加载(lazy load)本质上就是代理模式的应用
实体是Employee和Department,它们之间是多对一的关系。
Department类:
public class Department { private int id; private String name; public Department() { } public Department(String name) { this.name = name; } // getters and setters are omitted }
Employee类:
public class Employee { private int id; private String name; private Department department; public Employee() { } public Employee(String name) { this.name = name; } // getters and setters are omitted
Department.hbm.xml:
<hibernate-mapping package="com.john.myhibernate.domain"> <class name="Department"> <id name="id"> <generator class="native"/> </id> <property name="name" length="20" not-null="true"/> </class> </hibernate-mapping>
Employee.hbm.xml:
<hibernate-mapping package="com.john.myhibernate.domain"> <class name="Employee"> <id name="id"> <generator class="native"/> </id> <property name="name" length="20" not-null="true"/> <many-to-one name="department" column="department_id" class="Department" fetch="select"/> </class> </hibernate-mapping>
many-to-one没有inverse属性,由于关系的维护是many的一方,不可能放弃对关系的维护。
many-to-one的lazy属性有三个取值:false, proxy, no-proxy。
1. 测试cascade属性:
public void testSaveCascade() { Session s = null; Transaction tx = null; Department depart = new Department(); depart.setName("FCI"); Employee em1 = new Employee("John"); em1.setDepartment(depart); Employee em2 = new Employee("Lucy"); em2.setDepartment(depart); try { s = HibernateUtil.getSession(); tx = s.beginTransaction(); s.save(em1); s.save(em2); tx.commit(); } catch (HibernateException e) { tx.rollback(); e.printStackTrace(); } finally { if (s != null) s.close(); } }
结果是报org.hibernate.TransientObjectException异常,由于没有保存Department实例。
能够加cascade属性,解决问题:
<many-to-one name="department" column="department_id" class="Department" fetch="select" cascade="save-update"/>
2. 测试fetch
Session s = null; s = HibernateUtil.getSession(); Employee em = (Employee) s.get(Employee.class, 2); System.out.println(em.getName()); System.out.println(em.getDepartment());
查询语句以下:
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.department as department1_0_, employee0_.skill as skill1_0_, employee0_.sell as sell1_0_, employee0_.type as type1_0_ from Employee employee0_ where employee0_.id=?
Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?
由于fetch设置为select,因此对每一个实体,都分别用一个SELECT语句
若是把fetch设置为join,也就是连表查询,只使用一个SELECT语句。以下:
Hibernate: select employee0_.id as id1_1_, employee0_.name as name1_1_, employee0_.department as department1_1_, employee0_.skill as skill1_1_, employee0_.sell as sell1_1_, employee0_.type as type1_1_, department1_.id as id0_0_, department1_.name as name0_0_ from Employee employee0_ left outer join Department department1_ on employee0_.department=department1_.id where employee0_.id=?
3. 测试lazy
当fetch为select时,设置lazy为proxy或者no-proxy。
<many-to-one name="department" column="department_id" class="Department" fetch="select" cascade="save-update" lazy="no-proxy"/>
Session s = null; s = HibernateUtil.getSession(); Employee em = (Employee) s.get(Employee.class, 2); s.close(); System.out.println(em.getName()); System.out.println(em.getDepartment());
结果是报org.hibernate.LazyInitializationException异常。
由于fetch为select,并且lazy为proxy或者no-proxy,因此开始仅仅查询Employee,当须要用SELECT语句查询Department时,Session已经关闭。
解决办法:
1. 设置lazy为false,hibernate会第一时间把Employee和Department查询出来。
若是fetch为select,使用两个SELECT查询语句。
若是fetch为join,使用一个SELECT连表查询语句。
2. 设置fetch为join,这时无论lazy的取值,hibernate会进行连表查询,把两个实体都查询出来。
English Title:The Fetch in Hibernate, lazy, inverse and Cascade
1.fetch 和 lazy 主要用于级联查询(select) 而 inverse和cascade主要用于级联增、加删、除修
改(sava-update,delete)
2.想要删除父表中的记录,但但愿子表中记录的外键引用值设为null的状况:
父表的映射文件应该以下配置:
<set name="emps" inverse="false" cascade="all">
<key>
<column name="DEPTNO" precision="2" scale="0" />
</key>
<one-to-many class="com.sino.hibernate.Emp" />
</set>
inverse="false"是必须的,cascade无关紧要,而且子表的映射文件中inverse不必设置,cascade也能够不
设置,若是设置就设置成为cascade="none"或者cascade="sava-update"
<many-to-one name="dept" class="com.sino.hibernate.Dept" fetch="select" cascade="save-update">
<column name="DEPTNO" precision="2" scale="0" />
</many-to-one>
3.关于级联查找对子表的持久化类进行查找的时候,会一块儿把子表持久化类中的父表持久化类的对象一块儿查询
出来,在页面中能够直接取值的状况:要把父表的映射文件中设置 lazy 属性以下:
<class name="com.sino.hibernate.Emp" table="EMP" schema="SCOTT" lazy="false">
这样就能够直接在页面中取值 (相似于这样的取值 client.cmanager.id)若是没有设置 lazy="false" 则会抛
出异常javax.servlet.ServletException: Exception thrown by getter for property cmanager.realName
of bean cl在Action中取值的话就会抛出 could not initialize proxy - the owning Session was closed
的异常
--------------------------------------------------------------------------------------------------
一、outer-join关键字(many-to-one的状况)
outer-join关键字有3个值,分别是true,false,auto,默认是auto。
true: 表示使用外链接抓取关联的内容,这里的意思是当使用load(OrderLineItem.class,"id")时,Hibernate只生成一条SQL语句将OrderLineItem与他的父亲Order所有初始化。
select * from OrderLineItem o left join Order p on o.OrderId=p.OrderId where o.OrderLineItem_Id=?
false:表示不使用外链接抓取关联的内容,当load(OrderLineItem.class,"id")时,Hibernate生成两条SQL语句,一条查询OrderLineItem表,另外一条查询Order表。这样的好处是能够设置延迟加载,此处要将Order类设置为lazy=true。
select * from OrderLineItem o where o.OrderLineItem_Id=?
select * from Order p where p.OrderId=?
auto:具体是ture仍是false看hibernate.cfg.xml中的配置
注意:若是使用HQL查询OrderLineItem,如 from OrderLineItem o where o.id='id',老是不使用外部抓取,及outer-join失效。
二、outer-join(集合)
因为集合能够设置lazy="true",因此lazy与outer-join不能同时为true,当lazy="true"时,outer-join将一直是false,若是lazy="false",则outer-join用法与1同
三、HQL语句会将POJO配置文件中的关联一并查询,即便在HQL语句中没有明确join。
四、In HQL, the "fetch join" clause can be used for per-query specific outer join fetching. One important thing many people miss there, is that HQL queries will ignore the outer-join attribute you specified in your mapping. This makes it possible to configure the default loading behaviour of session.load() and session.get() and of objects loaded by navigating relationship. So if you specify
and then do
MyObject obj = session.createQuery("from MyObject").uniqueResult(); obj.getMySet().iterator().next();
you will still have an additional query and no outer-join. So you must explicily request the outer-join fetching:
MyObject obj = session.createQuery( "from MyObject mo left join fetch mo.mySet").uniqueResult();
Another important thing to know is that you can only fetch one collection reference in a query. That means you can just use one fetch join. You can however fetch "one" references in addition, as this sample from the Hibernate Docs demonstrates:
from eg.Cat as cat inner join fetch cat.mate left join fetch cat.kittens
We have once considered lifting this limitation, but then decided against it, because using more than one fetch-join would be a bad idea generally: The generated ResultSet becomes huge and is a major performance loss.
So alltogether the "fetch join" clause is an important instrument Hibernate users should learn how to leverage, as it allows tuning the fetch behaviour of a certain use case.
五、join fetch 与 join 的区别
若是HQL使用了链接,可是没有使用fetch关键字,则生成的SQL语句虽然有链接,可是并无取链接表的数据,仍是须要单独的sql取数据,也就是 select a,b,d...中没有链接表的字段
六、若是集合被声明为lazy=true,在HQL中若是显式的使用 join fetch 则延迟加载失效。
七、在one-to-many的one端显式设置fecth="join",则不管如何都采起预先抓取(生成一个SQl),延迟加载失效(生成两个SQL)
八、many-to-one的延迟加载是在配置文件的class标签设置lazy="true",one-to-many和many-to-many的延迟加载是在set标签中设置lazy="true"。而one-to-one不仅要在calss标签设置lazy="true",并且要在one-to-one标签中设置constrained="true".