Hibernate笔记

1. hibernate不能删除全是非空记录表记录。

 org.hibernate.PropertyValueException: not-null property references a null or transient value: cn.itcast.hibernate.domain.Department.name

在hbm.xml里面写了not-null=“true”。

Hibernate.cfg.xml文件编写需要的配置:(hibernate.properties)

## MySQL

#hibernate.dialect org.hibernate.dialect.MySQLDialect

#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect

#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect

#hibernate.connection.driver_class com.mysql.jdbc.Driver

#hibernate.connection.url jdbc:mysql:///test

#hibernate.connection.username gavin

#hibernate.connection.password

#hibernate.show_sql true

#hibernate.format_sql true

#hibernate.hbm2ddl.auto create-drop

#hibernate.hbm2ddl.auto create

#hibernate.hbm2ddl.auto update

#hibernate.hbm2ddl.auto validate

2.Hql语句:form+对象名。后面的名字必须和javabean类类名相同。

uploading.4e448015.gif正在上传…重新上传取消

3配置Myeclipse连接数据库,使之自动生成hibernate.cfg.xml和javabean类。

第一步:

uploading.4e448015.gif正在上传…重新上传取消

成功连接数据库。

第三步:

新建一个Web工程项目。选中该项目然后:MyEclipse-->Project--->add Hibernate Capabilities。操作之后会出现如下界面:

uploading.4e448015.gif正在上传…重新上传取消选中myhibernate这个项目。

然后点击:一:Myeclipse

二:project capabilities

三:add Hibernate Capabilities.

第二步:

uploading.4e448015.gif正在上传…重新上传取消

第三步:

uploading.4e448015.gif正在上传…重新上传取消

第四步:

uploading.4e448015.gif正在上传…重新上传取消

 

对于这步中,我选中去掉自动生成的HibernatesessionFactory工具类,该工具类就是一个回去Session的单例。完成后,打开项目就可以看到:

uploading.4e448015.gif正在上传…重新上传取消

第五步:

重新回到MyEclipse Database Exploere界面。选中刚刚配置的SQLServerDriver,右击选中open connection,完成后就会出现如下界面:

uploading.4e448015.gif正在上传…重新上传取消

第六步:

在dbo-->table中选中相应的表,右击选中Hibernate Reverse Engineering。。如上。然后出现:

如果browse不能选择其他的项目目录,或者没有我们需要选择的目录显示,那么就需要我们手动在工作空间配置:.project文件里面下面的一句话:第一行的的红色内容 <nature>com.genuitec.eclipse.hibernate.hibernatenature</nature>

  1. <natures>  
  2.        <span style="color:#cc0000;"> <nature>com.genuitec.eclipse.hibernate.hibernatenature</nature>  
  3. </span>     <nature>com.genuitec.eclipse.ast.deploy.core.deploymentnature</nature>  
  4.         <nature>com.genuitec.eclipse.j2eedt.core.webnature</nature>  
  5.         <nature>org.eclipse.jdt.core.javanature</nature>  
  6.         <nature>org.eclipse.wst.jsdt.core.jsNature</nature>  
  7.     </natures>  

 

uploading.4e448015.gif正在上传…重新上传取消

如果出现错误:

如下图:

uploading.4e448015.gif正在上传…重新上传取消

解决方案:

解决方法:修改.myhibernatedata文件里面的configFile属性

指定hibernate.cfg.xmll路径。格式是/项目名称/src/hibernate.cfg.xml

 

如果提示hibenate功能2.2冲突,修改version 为当前hibernate使用版本 

uploading.4e448015.gif正在上传…重新上传取消.myhibernatedata

uploading.4e448015.gif正在上传…重新上传取消#
#Thu Dec 15 14:33:09 CST 2011
genBasicCompId=false
sessionFactoryName=
profile=
daoSFId=
version=3.0 
jndiPath=
detectM2M=false
reStrategyClass=
springDaoFile=
useJavaTypes=true
keyGenerator=uuid.string
libInstallFolder=
addLibs2Project=false
genVersionTag=false
sessionFactoryId=
basePersistenceClass=
reSettingsFile=/jxwpgsh/hibernate.reveng.xml
configFile=/elec/src/hibernate.cfg.xml 
createConfigFile=false
addLibs2Classpath=false

 

第七步:

uploading.4e448015.gif正在上传…重新上传取消

第八步:

uploading.4e448015.gif正在上传…重新上传取消

4.查询一列:返回的是:List<Object>,查询多列:返回的是List<object[]>数组集合。
       解析:何时查询出来是List<Object[]>,何时是javabean对象。
       1).select * from person:使用createSQLQuery查询出来时List<Object[]>的形式。

试想:如果每次查询出来都是数组,每次我们都去操作数组,那将会非常麻烦
              所以:这个也是可以转换成映射javabean的形式的,转换方法如下:

       query.addEntity(Person.class).list()
              通过addEntity(Person.class)就可以实现List<Person>转换成功。
              否则将会出现异常。
那么看完成sql语句还需要addEntity来进行转换,那么就想起Hql语句的好处来了,Hql语句完全不需要转换,直接操作javabean类,这样变得简单多了。

       例如:Hql语句:from Person where name=:aa

       Query query = openSession.createQuery(hql).setParameter("aa","张三");

              List<Person> list = query.list();
       查询出来结果就直接封装到javabean中,这样hibernate的核心价值就体现出来了。

       真的不需要操作数据库,操作对象就可以解决一切问题。

       2).上面说的都是查询全部映射到javabean,那么查询部分字段呢?
       查询部分字段在sql中只能是:List<Object[]>或者List<Object>

       那么在Hql语句中:查询部分字段同样可以转换成javabean来进行操作。

       具体方法步骤如下:

       uploading.4e448015.gif正在上传…重新上传取消

在javabean中也必须是2个参数的构造函数:

uploading.4e448015.gif正在上传…重新上传取消

5.条件查询与占位符查询。

@Test

   public void test03()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();   

      String hql = "from Department where name = :abc";

      Query query = session.createQuery(hql).setParameter("abc", "媒体部");

      List<Department> list = query.list();   

      for(Department ff:list)

      {

         System.out.println(ff.getName());

      }    

      transaction.commit();

      session.close();

   }

6.Criteria高级查询。

@Test

   public void test04(){

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Criteria c = session.createCriteria(Department.class);

      c.add(Restrictions.eq("name", "媒体部"));

      //Department uniqueResult = (Department) c.uniqueResult();

      List<Department> list = c.list();

      System.out.println(list);   

      transaction.commit();

      session.close();

   }

7.主键生成策略

  1. (increment)并发问题。

演示并发:

给程序2次debug,第一次让程序停在点上,在运行一个debug,发现第一个成功,第二个失败。

两次debug的目的:为了演示并发的效果,我们需要第一个程序停在某个点上等待程序第二次的运行。

uploading.4e448015.gif正在上传…重新上传取消

  1. Identity标示符。

由于 identity 生成标识符的机制依赖于底层数据库系统, 因此, 要求底层数据库系统必须支持自动增长字段类型. 支持自动增长字段类型的数据库包括: DB2, Mysql, MSSQLServer, Sybase 等

OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常

  1. Sequence序列

uploading.4e448015.gif正在上传…重新上传取消

  1. 复合主键。
  2. 派生属性。

在数据库里面定义一个字段totalPrice,formula里面的sql语句查询出来值付给totalPrice属性。注意:formula里面语句必须加括号().

uploading.4e448015.gif正在上传…重新上传取消

8.MySql数据库乱码处理

Mysql 乱码的解决

show variables like 'char%';  查看数据库字符集设置

client、connection、result 和命令行客户端相关  (windows 下命令行客户端必须要设置gbk )    

database server system 和服务器相关字符集  (system字符集不可修改

* 实际开发中 建议大家 将database 和 server 字符集 设置为utf8

mysql核心配置文件 my.ini 如果linux my.cnf

[mysql] 主要配置命令行客户端参数 default-character-set=gbk  ---- 影响 client、connection、result

[mysqld] 配置服务器参数 character-set-server=utf8  ----- 影响 database server

 

如果服务器server 字符集 已经设置utf8 建立数据库 数据表 默认utf8 ----- 插入数据一定没有乱码

如果服务器 没有设置server字符集, 默认latin1 , 建立数据库指定字符集utf-8 建表指定字符集utf-8  (有乱码 )

       解决方案一: 设置server 字符集, 重新建立数据库和表

       解决方案二: jdbc:mysql:///db?useUnicode=true&characterEncoding=utf-8  (默认传输字符集 utf8/gbk)

9.Hibernate中将PO对象分为三种状态。

  1. 瞬时态 transient  尚未与Hibernate Session关联对象,被认为处于瞬时状态,失去引用将被JVM回收,无持久化标识OID,未与Session关联
  2. 持久态 persistent 数据库中有数据与之对应并与当前session有关联,并且相关联的session没有关闭数据库并且事务未提交   存在持久化标识OID,与Session关联
  3. 脱管态 detached 数据库中有数据与之对应,但当前没有session与之关联,脱管状态改变hibernate不能检测到,存在持久化标识OID,未与Session关联
    • .delete删除 脱管对象时,先将脱管对象转换为持久对象,再进行删除

代码如下:

Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Person person = new Person();

      //托管态对象。

      person.setId(1);

      //删除托管态对象,先将托管对象转换为持久对象,在删除。

      session.delete(person);

      //测试删除方法执行后,缓存中还有持久对象没,结果验证:有

      Person person1 = (Person) session.get(Person.class, 1);

      System.out.println(person.getId()+"持久对象"); 

      transaction.commit();

      session.close();
运行结果:1持久对象

Hibernate:  delete from  person  where  id=?

可以看出:执行delete方法后,get方法没有生成sql语句也查询出持久对象,获取id值,证明:删除托管对象,先把托管对象变成持久对象,然后再执行删除。

.多表删除

.使用传统的配置文件进行删除。

Course配置文件:

  <class name="cn.itcast.hibernate.manytomany.Course" table="course" >

    <id name="id">

    <generator class="native"></generator>

    </id>

    <property name="name"></property>

    <set name="students" table="student_course">

    <key column="course_id"></key>

    <many-to-many class="cn.itcast.hibernate.manytomany.Student" column="student_id"></many-to-many>

    </set>

</class>

   Student配置文件:

<class name="cn.itcast.hibernate.manytomany.Student" table="student" >

    <id name="id">

    <generator class="native"></generator>

    </id>

    <property name="name"></property>

    <set name="courses" table="student_course">

    <key column="student_id"></key>

    <many-to-many class="cn.itcast.hibernate.manytomany.Course" column="course_id"></many-to-many>

    </set>

    </class>

进行删除:

Course c = new Course();

      c.setId(1);    

      session.delete(c);//删除托管对象,同时删除中间表。不是级联删除

   删除成功:发出sql语句

      delete from student_course where course_id=?

delete from sshdemo.course where id=?

    uploading.4e448015.gif正在上传…重新上传取消

    • .托管对象进行update

hbm文件中提供<class>属性 select-before-update:为了防止 离线数据 与 数据表数据 完全一致,无效update, 设置 select-before-update =true 在更新前 先查询一次,不同时才更新

代码解析如下:
Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Person person = new Person();

      //托管对象必须和数据库各属性值保持一致。并且全部加set

      //如果有任何一个属性没有set,那么这个属性值为null

      //为null,那么就造成与数据库不一致,将会进行update。这个值被赋null值。

      person.setId(1);

      person.setAge(23);

      person.setName("王五");

      person.setSex("女");

      session.update(person);

      transaction.commit();

    session.close();

uploading.4e448015.gif正在上传…重新上传取消

运行结果如下:

Hibernate:

    select

        person_.id,

        person_.name as name0_,

        person_.sex as sex0_,

        person_.age as age0_

    from

        person person_

    where

        person_.id=?

从运行结果可以看出:

没有执行update语句,达到预期目的:验证了,class配置属性:select-before-update将会检查要更新数据是否与数据库一致,如果一致,那么就不需要update

 

★.在执行update前,一级缓存中 已经存在 相同OID持久对象 ,发生冲突

Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      //先进行查询,让一级缓存中存在数据。

      Person person1 = (Person) session.get(Person.class, 1);

      System.out.println(person1+":"+person1.getName());

      //设置具有一级缓存相同id的新数据

      Person person = new Person();

      person.setId(1);

      person.setAge(23);

      person.setName("王五");

      person.setSex("女");

      session.update(person);

      transaction.commit();

    session.close();

结果产生异常:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [cn.itcast.hibernate.test.Person#1]

分析:

我们发现,查询出来在session中存在一个person1对象,如果我们对person1对象进行一些修改,然后commit那么这是正常的。

那么如果我们新建一个person对象,再给他相同的id,那么就会产生上面的冲突。

这说明:session只允许一个OID对应一个对象。

    • .执行update时,脱管对象OID数据表中不存在,也会抛出异常
    • .测试关闭session托管对象状态。

public void test008()

      {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Person person = (Person) session.get(Person.class, 1);

      System.out.println(person.getName());

      transaction.commit();

      session.close();

      //测试缓存中数据消失,托管对象还有值吗?                    System.out.println(person.getId()+"||"+person.getName());

   }

结果分析:关闭session时,我们还可以取到值,那么这个托管对象确定解除与session的关联,但为什么还能取到值呢?这就进一步说明了托管对象

与session解除关联,但是在缓存中还保留一份,所以可以取到值。

    • jsp中的session是一个可以理解为会话级的存储变量,是web间信息互访的载体,而Hibernate中的session一个全新的概念,可以理解为数据库层和持久化层的互访载体,也可以认为是一个缓冲器,对数据库的所有CURD操作在这个session(缓存)中都有记录,一旦做个清理缓存操作,则所有对持久化对象的操作都将映射到具体的某个数据库中,完成最后的数据更新,也就是说在没有清理缓存之前的所有操作都是不会对某个具体的数据库数据产生影响的。

自动建表:

<property name="hibernate.hbm2ddl.auto">update</property>

Hbm文件使用type制定类型生成表如下:

<property name="name" column="name" type="string"></property>

<property name="price" column="price" type="double"></property>

CREATE TABLE `book` (                                 

          `id` int(11) NOT NULL AUTO_INCREMENT,               

          `name` varchar(255) DEFAULT NULL,                   

          `price` double DEFAULT NULL,                        

          PRIMARY KEY (`id`)                                  

        ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 

 

未使用type进行类型制定,生成表如下:

<property name="name" column="name" ></property>

<property name="price" column="price" ></property>

生成表和上面一样,说明这个type是与javabean类的属性类型是相关的。与这类型无关。

程序代码

生命周期

状态

tx = session.beginTransaction();

Customer c = new Customer();

开始生命周期

瞬时状态

Session.save(c)

处于生命周期中

转变为持久化状态

Long id=c.getId();

c = null;

Customer c2 = (Customer)session.load(Customer.class,id);

tx.commit();

处于生命周期中

处于持久化状态

session.close();

处于生命周期中

转变为脱管态

c2.getName();

处于生命周期中

处于脱管态

c2 = null;

结束生命周期

结束生命周期

10.证明一级缓存存在。

@Test

   public void test06()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();   

      //证明一级缓存的存在。

      Book book1 = (Book) session.get(Book.class, 1);

      System.out.println(book1);

      //为了证明缓存存在,重新获取一下id为1的实例。发现其地址一样。

      Book book2 = (Book) session.get(Book.class, 1);

      System.out.println(book2);

      transaction.commit();

      session.close();

   }

运行结果:

cn.itcast.hibernate.domain.Book@1397e5c

cn.itcast.hibernate.domain.Book@1397e5c

可以看出,hashcode一致。并且2次查询只有一条select的sql语句。

  1. 将缓存中的数据同步到数据库。

如果在上面代码中间加入session.flush();没有任何效果,输出结果,select语句全部一样。

如果使用book1.setName(“哦哦哦”);改变了其值,那么flush将会使用快照更新数据库。

  1. Clear清空所有缓存。
  2. Evit清楚指定缓存。
  3. 证明不使用flush自动更新。

uploading.4e448015.gif正在上传…重新上传取消

说明:三种情况会更新数据库。

事物提交,Query查询,还有flush都会同步数据库。

uploading.4e448015.gif正在上传…重新上传取消

  1. FlushMode:设置什么时间进行一级缓存刷出。

清理缓存的模式

Session的

查询方法

tx的

commit()

Session的

flush()

FlushMode.AUTO(默认)

刷出

刷出

刷出

FlushMode.COMMIT

不刷出

刷出

刷出

FlushMode.ALWAYS

刷出

刷出

刷出

FLushMode.MANUAL

不刷出

不刷出

刷出

11.数据建表原则。

  1. 多对多:必须创建一张中间表,引用两张实体表主键作为外键,2个外键作为中间表的联合主键。(非常常用 重要 )
    学生Student和课程Course 之间关系
  2. 一个学生 可以选修 多门课程
    一门课程 可以被 多名学生 选修
    多对多和一对多 重要区别: 多对多种没有父子关系
  3. Student.hbm.xml
        <class name="cn.itcast.domain.manytomany.Student" table="student" catalog="hibernate3day2">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="sname"></property>
            <!-- 多对多  必须有中间关系表-->
            <!--
                name : 是Student类中 关联Course 对应属性集合 名称
                table : 生成中间表 表名
             -->
            <set name="courses" table="student_course" >
                <!-- 当前Student对象,在中间表生成 外键列 列名 -->
                <key column="student_id"></key>
                <!-- 
                    class : set集合 数据类型
                    column : set映射目标类 ,生成中间表 外键列 列名
                -->
                <many-to-many class="cn.itcast.domain.manytomany.Course" column="course_id"></many-to-many>
            </set>
        </class>
    Course.hbm.xml
        <class name="cn.itcast.domain.manytomany.Course" table="course" catalog="hibernate3day2">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="cname"></property>
            <!-- 多对多 -->
            <set name="students" table="student_course">
                <key column="course_id"></key>
                <many-to-many class="cn.itcast.domain.manytomany.Student" column="student_id"></many-to-many>
            </set>
        </class>       
  4. 测试用例一 : 建表   
  5. 测试用例二 : 测试保存, 多对多没有父子关系, 在真正的开发中 不建议级联
        * 当两个持久对象,建立关系, 在关系表插入一条数据   (防止重复数据 : 1) inverse=true 使一端放弃外键维护 2) 不要建立双向关系)
  6. 测试用例三: 解决学生和课程关系 ,产生一条delete语句        
  7. 测试用例四: 将1号学生选修1号课程,改为2号学生选修1号课程
  8. 测试用例五: 删除一个选过课的学生
            * 不用级联,删除学生后,选课记录自动删除
        <set name="courses" table="student_course"  cascade="delete">
        <set name="students" table="student_course" cascade="delete">
        多对多 删除离线对象 --- cascade 无效
        多对多 删除持久对象 --- cascade 生效
    一对多:在多方表引入一方表作为外键。
    一对一:在任意一方引入对方主键作为外键。

12.一对多关联映射。

在多方表引入一方表作为外键。

注意配置的相互关联性:

uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消

测试类分析:

   public void test009()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Customer customer = new Customer();     

      customer.setName("张三");

      customer.setPrice(232d);    

      Order order = new Order();

      order.setName("京东商城");

      order.setCustomer(customer);

      customer.getOrders().add(order)[h1] ;  

      session.save(order);

      session.save(customer);

      transaction.commit();

      session.close();

   }

执行结束:console后台生成sql语句:

  insert                               我们发现出现2条insert语句,2条

    into                               update语句,这样的形式?那么

        orders                         为什么会有2条update语句呢?数据

        (name, customer_id)            库中数据插入都正确,但当我们删除

    Values                             order.setCustomer(customer),保

        (?, ?)                         留customer.getOrders().add(),

Hibernate:                             我只需要session.save(customer)

    insert                             那么这时我们就只会有一条sql语句

    into                               或者还是以前添加双向关系,只要在

        customer                       任意一方添加inverse=”true”我们就

        (name, price)                  收获一条update的sql语句实现同样

    Values                             的效果。

        (?, ?)                         2条update语句分析:

Hibernate:                             我关联了2句

    update                             order.setCustomer(customer)

        orders                         customer.getOrders().add(order

    set                                保存了2次:

        name=?,                        session.save(order)

        customer_id=?                  session.save(customer)

    where                              分析:

        id=?                           当save:order时候,第一次更新了数

Hibernate:                             库,产生了一条update语句。持久化

    Update                             镜像也发生了改变。

        orders                         当save:customer时,我们又添加了一

    set                                次关系映射。这时保存的缓存中会对比

        customer_id=?                  现在保存的关系。再次产生一条更新语

    where                              句(update).

        id=?

 

测试类:注意:测试类没有添加配置文件级联操作,一旦session.save()少保存一个对象,那么就会出错。

       public void test07()

       {

              Session session = HibernateUtils.openSession();

              Transaction transaction = session.beginTransaction();

              Customer customer = new Customer();

              customer.setAge(19);

              customer.setName("maechl");      

              Order order1 = new Order();

              order1.setAddr("ooo");

              order1.setTotalPrice(23d);           

              Order order2 = new Order();

              order2.setAddr("lplpl");

              order2.setTotalPrice(767d);         

              customer.getOrders().add(order1);

              customer.getOrders().add(order2);       

              order1.setCustomer(customer);

              order2.setCustomer(customer);           

              session.save(customer);

              session.save(order1);

              session.save(order2);     

              transaction.commit();

              session.close();}

13.级联删除。

public void test010()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

//<set name="orders" cascade="save-update,delete">:测试级联删除

   Customer customer = (Customer) session.get(Customer.class, 1);

      session.delete(customer);   

      transaction.commit();       session.close();}uploading.4e448015.gif正在上传…重新上传取消

执行语句:

Hibernate: delete from sshdemo.order where id=?

Hibernate: delete from sshdemo.order where id=?

Hibernate: delete from sshdemo.customer where id=?

可以看出:三条删除语句,删除所有关联关系的数据。

而且:我们是从Customer端进行删除的,那么我们就可以在Customer端进行配置。

如果需要从Order进行删除,进行如下配置:

uploading.4e448015.gif正在上传…重新上传取消

Hibernate不能使用id的sql语句来进行删除:

Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      //<set name="orders" cascade="save-update,delete">:测试级联删除

      Customer customer = (Customer) session.get(Customer.class, 8);    

      Customer cus = new Customer();

      cus.setId(8);     

      @SuppressWarnings("unused")

      int executeUpdate = session.createQuery("delete Customer where id = ?").setInteger(0, customer.getId()).executeUpdate();

      transaction.commit();

      session.close();

   这样会出错,表示没有解除外键约束。

14.孤儿删除

  • 在没有配置孤儿删除的时候:

Customer customer = (Customer)session.get(Customer.class,2);

Order order = (Order)session.get(Order.class,3);

Customer.getOrders().remove(order);

使用customer移除3号订单,但是没有配置的情况下,那么将会把外键置为null空。

  • 可以发现配置:delete-orphan后:客户的订单孤儿删除成功。

uploading.4e448015.gif正在上传…重新上传取消

15.多余的SQL

修改订单:

把4号客户订单改为6号。

会产生2个update,这样不行,怎样才能一个update语句呢?原则上,只需要一句update语句。

Inverse=true表示:放弃维护外键值的权利,无法设置外键的值。在父方设置cascade级联,

在父方设置inverse=true,表示Customer已无外键维护权利,把外键维护的权利交给Order.

uploading.4e448015.gif正在上传…重新上传取消

Inverse和cascade是Hibernate映射中最难掌握的两个属性。两者都在对象的关联操作中发挥作用。

1.明确inverse和cascade的作用 
inverse 决定是否把对对象中集合的改动反映到数据库中,所以inverse只对集合起作用,也就是只对one-to-many或many-to-many有效(因为只有这两种关联关系包含集合,而one-to-one和many-to-one只含有关系对方的一个引用)。
cascade决定是否把对对象的改动反映到数据库中,所以cascade对所有的关联关系都起作用(因为关联关系就是指对象之间的关联关系)。

2.inverse属性 :inverse所描述的是对象之间关联关系的维护方式。 
inverse只存在于集合标记的元素中 。Hibernate提供的集合元素包括<set/> <map/> <list/> <array /> <bag /> 
Inverse属性的作用是:是否将对集合对象的修改反映到数据库中。 
inverse属性的默认值为false,表示对集合对象的修改会被反映到数据库中;inverse=false 的为主动方,由主动方负责维护关联关系。 
inverse=”true” 表示对集合对象的修改不会被反映到数据库中。

 为了维持两个实体类(表)的关系,而添加的一些属性,该属性可能在两个实体类(表)或者在一个独立的表里面,这个要看这双方直接的对应关系了: 这里的维护指的是当主控放进行增删改查操作时,会同时对关联关系进行对应的更新。

   一对多: 该属性在多的一方。应该在一方的设置 inverse=true ,多的一方设置 inverse=false(多的一方也可以不设置inverse属性,因为默认值是false),这说明关联关系由多的一方来维护。如果要一方维护关系,就会使在插入或是删除"一"方时去update"多"方的每一个与这个"一"的对象有关系的对象。而如果让"多"方面维护关系时就不会有update 操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。显然这样做的话,会减少很多操作,提高了效率。
注: 
      单向one-to-many关联关系中,不可以设置inverse="true",因为被控方的映射文件中没有主控方的信息。

   多对多: 属性在独立表中。inverse属性的默认值为false。在多对多关联关系中,关系的两端 inverse不能都设为false,即默认的情况是不对的,如果都设为false,在做插入操作时会导致在关系表中插入两次关系。也不能都设为 true,如果都设为true,任何操作都不会触发对关系表的操作。因此在任意一方设置inverse=true,另一方inverse=false。

   一对一: 其实是一对多的一个特例,inverse 的设置也是一样的,主要还是看关联关系的属性在哪一方,这一方的inverse=false。

   多对一: 也就是一对多的反过来,没什么区别。

2.cascade属性 
cascade属性的作用是描述关联对象进行操作时的级联特性。因此,只有涉及到关系的元素才有cascade属性。 
具有cascade属性的标记包括<many-to-one /> <one-to-one /> <any /> <set /><bag /> <idbag /> <list /> <array /> 
注意:<ont-to-many />和 <many-to-many />是用在集合标记内部的,所以是不需要cascade属性的。 
级联操作:指当主控方执行某项操作时,是否要对被关联方也执行相同的操作。

3.inverse和cascade的区别 
作用的范围不同: 
     Inverse是设置在集合元素中的。 
   Cascade对于所有涉及到关联的元素都有效。 
   <many-to-one/><ont-to-many/>没有inverse属性,但有cascade属性 
执行的策略不同 
   Inverse 会首先判断集合的变化情况,然后针对变化执行相应的处理。 
   Cascade 是直接对集合中每个元素执行相应的处理 
执行的时机不同 
     Inverse是在执行SQL语句之前判断是否要执行该SQL语句 
     Cascade则在主控方发生操作时用来判断是否要进行级联操作 
执行的目标不同 
     Inverse对于<ont-to-many>和<many-to-many>处理方式不相同。 
   对于<ont-to-many>,inverse所处理的是对被关联表进行修改操作。 
   对于<many-to-many>,inverse所处理的则是中间关联表 
     Cascade不会区分这两种关系的差别,所做的操作都是针对被关联的对象。

总结: 
<one-to-many>中,建议inverse=”true”,由“many”方来进行关联关系的维护 
<many-to-many>中,只设置其中一方inverse=”false”,或双方都不设置 
Cascade,通常情况下都不会使用。特别是删除,一定要慎重。
操作建议 
  一般对many-to-one和many-to-many不设置级联,这要看业务逻辑的需要;对one-to-one和one-to-many设置级联。
  many-to-many关联关系中,一端设置inverse=”false”,另一端设置为inverse=”true”。在one-to-many关联关系中,设置inverse=”true”,由多端来维护关系表

进行多对多casecade与inverse测试:

  • 测试保存一方表,修改关系表,但是不修改另一张表,只是关联另一种表数据

①.配置情况

<set name="students" table="student_course"  inverse="true">

Course c = new Course();

      c.setId(1);

      c.setName("数学");

      Student s = new Student();

      s.setId(3);

   c.getStudents().add(s);

执行sql语句:

insert into sshdemo.course (name) values (?)

分析:可以看见只生成了一条sql语句,这与我们预想的完全不相符合,我们需要的是关联学生表,让他们产生关联。现在却是保存没有关联。

注意思考:这里在主方配置了inverse=true,那么就放弃了外键的维护权利,就是对集合的修改反映到数据库中。那么现在我们修改为false,那么会产生什么情况呢?

观察生成sql语句:

insert into sshdemo.course (name) values (?)

insert into student_course (course_id, student_id) values (?, ?)

    分析:根据生成的sql语句发现,现在就正确了,那么在项目中真实的业务反映就是页面进行保存,页面有另几张关联的表的下拉框,传递到后台的是主键id,那么就会保存关联。可以直接在页面进行对象化传参:

javabeanModel.javaBean关联属性.id

也可以直接传递基本类型的id,然后在后台进行查询,完了以后在进行关联。

       思考No.2:

我们加上级联(cascade)的话会有什么情况发生呢?

执行生成sql语句:

insert into sshdemo.course (name) values (?)

update sshdemo.student set name=? where id=?

delete from student_course where student_id=?

insert into student_course (course_id, student_id) values (?, ?)

分析:使用级联save,跟新Student表,并把除id以外的其他段设为空。这不是我们需要的业务需求,我们需要的是Student表不能有任何改变。

这句级联执行流程如下:保存course,跟新Student,删除student_id、然后在进行保存关系表,从而推算:级联保存将会删除关系表,然后再进行保存。

  • 多对多进行更新操作

①.配置文件inverse=false,cascade有或者无:

<set name="students" table="student_course" >à:cascade配置和不配置是一样的结果。

执行结果:

update sshdemo.course set name=? where id=?

delete from student_course where course_id=?

分析:由于设计之初的初衷是:修改一方表,不改变关系表,但是明显关系表被改变了,把关系表给删除了,那么我们配置inverse=true,会是什么情况?

<set name="students" table="student_course" inverse="true">

执行结果:

update sshdemo.course set name=? where id=?

果然达到我们的目标:只更新我们需要跟新的表,关系表没有被改掉。

16:一对一映射

一对一完全可以使用一张表的,可能由于字段太多,使用2张表。

一对一映射有两种情况:

外键关联、主键关联。

  • 外键关联【回忆:在一对多时,在多方表引入一方表作为外键,那么一对一其实就一对多的简化。故而在引入外键的一方可以使用:<many-to-one>】

Company:

uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消

Address:

uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消其实就是Company中address属性。

uploading.4e448015.gif正在上传…重新上传取消

@Test

   public void test10()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Company company = new Company();

      company.setName("opopop");     

      Address addr = new Address();

      addr.setInfo("kokoko");     

      company.setAddress(addr);

      addr.setCompany(company);   

      session.save(company);

      session.save(addr);  

      transaction.commit();

      session.close();

   }

 

  • 主键关联

uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消

17.Hibernate组成映射关系。

  • 一张表对应一个持久类,当表数据过于复杂,将实体类进行分解,分解出若干组件 Component , 构成组成关系映射

uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消

  =                     Restrictions.eq()                  等于

      <>                   Restrictions.not(Exprission.eq())  不等于

      >                     Restrictions.gt()                  大于

      >=                   Restrictions.ge()                  大于等于

      <                     Restrictions.lt()                  小于

      <=                   Restrictions.le()                  小于等于

      is null             Restrictions.isnull()              等于空值

      is not null      Restrictions.isNotNull()           非空值

      like                 Restrictions.like()                字符串模式匹配

      and                Restrictions.and()                 逻辑与

      and                Restrictions.conjunction()         逻辑与

      or                   Restrictions.or()                  逻辑或

      or                   Restrictions.disjunction()         逻辑或

      not                  Restrictions.not()                 逻辑非

      in(列表)          Restrictions.in()                  等于列表中的某一个值

      ont in(列表)         Restrictions.not(Restrictions.in())不等于列表中任意一个值

      between x and y      Restrictions.between()             闭区间xy中的任意值

      not between x and y  Restrictions.not(Restrictions..between()) 小于值X或者大于值y

 

 

18.配置使用C3P0连接池。

  • 导入c3p0的jar包。目录:hibernate-distribution-3.6.10.Final下面lib里面optional里面c3p0.

在hibernate.cfg.xml中启用c3p0连接池。
在目录: hibernate-distribution-3.6.10.Final\project\etc下面:
uploading.4e448015.gif正在上传…重新上传取消
打开hibernate.properties文件:找到如下配置:

下面就去hibernate.cfg.xml里面加入如下配置,启用c3p0连接池:
配置如下:
<property name="hibernate.connection.provider_class">

       hibernate.connection.provider_class org.hibernate.connection.C3P0ConnectionProvider

       </property>

解析:表示c3p0已经被开启了。

下面可以在进行一些详细的配置:

###########################

### C3P0 Connection Pool###

###########################

 

#hibernate.c3p0.max_size 2

#hibernate.c3p0.min_size 2

#hibernate.c3p0.timeout 5000

#hibernate.c3p0.max_statements 100

#hibernate.c3p0.idle_test_period 3000

#hibernate.c3p0.acquire_increment 2

#hibernate.c3p0.validate false

示例如下:

<property name="hibernate.c3p0.max_size">30</property>

连接池配置成功。

 

19. 多个事务并发运行时的并发问题
uploading.4e448015.gif正在上传…重新上传取消

理解几种并发问题:

uploading.4e448015.gif正在上传…重新上传取消

第一类:丢失更新

uploading.4e448015.gif正在上传…重新上传取消

第二类:脏读

 

uploading.4e448015.gif正在上传…重新上传取消

第三类:不可重复读

uploading.4e448015.gif正在上传…重新上传取消

第四种:虚读

uploading.4e448015.gif正在上传…重新上传取消

  • 丢失更新问题。
    对于其他三类的问题,使用事务的隔离级别可以解决事务的脏读、不可重复读、虚读。
  • 阐述丢失更新原理。
    假设:A管理员查询id=1、name=”zhangsan”的用户在form表单中回显;
          A修改了name=“李四”并且提交(commit);
          B管理员查询id=1、name=”zhangsan”的用户在form表单中回显。
          B修改了name=“王五”并且提交(commit);
          那么A修改的数据就会被覆盖掉,即A修改的数据将会丢失。
          解决方案:
          B用户必须在A用户修改完之后再去修改。
  • 数据库为了解决数据库并发问题,提供了数据访问事物隔离级别。隔离级别对于不同的数据库是不一样的。
    READ_UNCOMMITED:会发生以上所有并发问题。
    READ_COMMITTED:阻止脏读的发生,会发生不可重复读和虚读。
    REPEATABLE_READ:阻止脏读和不可重复读,会产生虚读。
    SERIALIZABLE:不会发生并发问题,串行初始化(性能非常差,一般不使用)
  • 解决丢失更新:悲观锁、乐观锁。
    悲观锁:假设丢失更新发生概率很大,底层原理:使用数据库内部的锁机制。
    mysql为例,数据库内部提供 读锁(共享锁) 、写锁(排它锁 )

 * 允许一张数据表 添加多个读锁

 * 一张数据表 只能添加 一个写锁(排它锁),与其他锁 互斥 ,添加排它锁 也不能添加 共享锁

*默认情况下,在修改记录时,会自动添加 写锁

在执行查询时,也可以为数据添加 共享锁和排它锁
select * from customer lock in share mode ;  添加共享锁
select * from customer for update; 添加排它锁
悲观锁 使用排它锁  第一个管理员修改时 select * from customer for update  第二个管理员 用同样查询需要等待
Hibernate查询时 Session 提供 Object get(Class clazz, Serializable id, LockMode lockMode)
  mysql : LockMode UPGRADE
   oracle : LockMode UPGRADE_NOWAIT
  Customer customer = (Customer) session.get(Customer.class, 1 ,LockMode.UPGRADE);     
乐观锁:假设丢失更新发生的概率不大,底层原理:添加版本号,用程序来维护版本号。

演示数据库锁的效果:

同时开启2个mysql的dos窗口,表示2个用户同时使用这个数据库:

截图如下:

uploading.4e448015.gif正在上传…重新上传取消

给一张表加多个共享锁:

uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消

如果在共享锁的情况下去update将会死锁。

测试代码:

@Test

   public void test13()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Customer cus = (Customer) session.get(Customer.class, 2, LockMode.UPGRADE);

      System.out.println(cus);

      transaction.commit();

      session.close();

  }

结果:ibernate: select customer0_.id as id2_0_, customer0_.name as name2_0_, customer0_.age as age2_0_ from sshdemo.customer customer0_ where customer0_.id=? for update

cn.itcast.hibernate.onetomany.Customer@d6c07
乐观锁解析:

给数据库加一个版本号的字段version。

具体步骤如下:

第一步:在javabean:Customer中加入属性:

uploading.4e448015.gif正在上传…重新上传取消

第二步:在Customer.hbm.xml中配置属性version。
    uploading.4e448015.gif正在上传…重新上传取消

第三步:测试

@Test

   public void test14()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Customer c = new Customer();

      c.setName("kkk");

      c.setAge(19);

      session.save(c);

      transaction.commit();

      session.close();

   }

查询数据表:发现生成version字段:uploading.4e448015.gif正在上传…重新上传取消

第四步:测试乐观锁对比version方案。
先提交版本变化,后提交的版本与变化的版本对比不一致,就会出错。
测试方法:
开启2个debug进程,让2个debug先获取相同的源数据,然后才能对比。
20.二级缓存
缓存: 常用数据库持久化对象,保存在内存中,减少与数据库交互次数,提高性能

一级缓存: session级别的缓存, 属于事务范围   --- 自带的,无需配置

二级缓存: sessionFactory 级别的缓存, 属于进程范围的缓存   ------ 引入外部缓存插件,配置后才能使用

  1. Hibernate使用二级缓存 提供商

 1) EHCache

 2) OSCache

 3) Swarm Cache

 4) JBOSS Cache

  1. 二级缓存由四个部分组成 : 类级别缓存区、 集合级别的缓存区、 更新时间戳 、 查询缓存

* 有些人称 查询缓存 是Hibernate的第三级 缓存

  1. 二级缓存的并发策略  (每种策略与一种隔离级别 对应)

    非严格读写(Nonstrict-read-write) ----- read uncommitted

    读写型(Read-write) ----- read committed

    事务型(Transactional)  ----- Repeatable Read

    只读型(Read-Only) ----- Serializable

  1. 数据库中 极少被改动的数据,比较适用于放入二级缓存 
  2. 四种缓存提供商 : EHCache、OSCache 主要用于单机数据库软件 , SwarmCache和JBossCache 主要用于集群环境

二级缓存配置步骤:

1) 下载hibernate3.6.10 版本 ,解压后 lib/optional/ehcache 文件夹 ehcache-1.5.0.jar

ehcache 依赖 backport-util-concurrent 和 commons-logging

导入 backport-util-concurrent.jar 、 commons-logging.jar

2)配置hibernate.cfg.xml 开启二级缓存

    <property name="hibernate.cache.use_second_level_cache">true</property>

3) 配置hibernate.cfg.xml 缓存的供应商 

    <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

uploading.4e448015.gif正在上传…重新上传取消

4) 指定对哪些数据应用二级缓存

    有两种配置方式  hbm.xml  和 hibernate.cfg.xml

    在hibernate.cfg.xml 配置 <class-cache> 类级别缓存  <collection-cache> 集合级别的缓存

 

5)在src下 建立ehcache.xml 主要用来配置 缓存插件 EHCache 一些属性

    将hibernate解压目录/project/etc/ehcache.xml 复制到 src

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!--   
  3.     defaultCache节点为缺省的缓存策略  
  4.      maxElementsInMemory 内存中最大允许存在的对象数量  
  5.      eternal 设置缓存中的对象是否永远不过期  
  6.      overflowToDisk 把溢出的对象存放到硬盘上  
  7.      timeToIdleSeconds 指定缓存对象空闲多长时间就过期,过期的对象会被清除掉  
  8.      timeToLiveSeconds 指定缓存对象总的存活时间  
  9.      diskPersistent 当jvm结束是是否持久化对象  
  10.      diskExpiryThreadIntervalSeconds 指定专门用于清除过期对象的监听线程的轮询时间  
  11.  -->  
  12. <ehcache>  
  13.     <diskStore path="D:\cache"/>  
  14.     <defaultCache  maxElementsInMemory="1000" eternal="false" overflowToDisk="true"  
  15.         timeToIdleSeconds="120"  
  16.         timeToLiveSeconds="180"  
  17.         diskPersistent="false"  
  18.         diskExpiryThreadIntervalSeconds="60"/>  
  19.     <cache name="cn.itcast.bean.Person" maxElementsInMemory="100" eternal="false"  
  20.     overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="600" diskPersistent="false"/>  
  21. </ehcache>  

 

6) 编写测试类
测试原理:查询数据、一级缓存会放入数据,然后我们session.close();清空一级缓存。下面我们在获取session来查询,发现只有一条sql语句,故而证明二级缓存存在。
uploading.4e448015.gif正在上传…重新上传取消

uploading.4e448015.gif正在上传…重新上传取消

Hibernate: select customer0_.id as id1_0_, customer0_.version as version1_0_, customer0_.name as name1_0_, customer0_.age as age1_0_ from sshdemo.customer customer0_ where customer0_.id=?

cn.itcast.hibernate.onetomany.Customer@1e536d6

cn.itcast.hibernate.onetomany.Customer@1e536d6

cn.itcast.hibernate.onetomany.Customer@7e5130
 

  1. 二级缓存原理

分析:为什么类级别缓存对象地址和一级缓存地址不一致。
1) 类级别缓存区: 散装数据的存储  ----- 每次使用二级缓存,将获得一个新的对象
一级缓存:session中保存对象的引用。
二级缓存:数据散装,散装数据会封装成一个新的customer对象,即在内存中new一个新的对象。故而地址发生变化。

* query接口可以将数据放置到类级别的二级缓存中,但是不能使用query接口的 list方法从缓存中获取数据 (能存 不能取)

2) 集合级别缓冲区 : 存放集合数据OID,对象数据 保存类级别缓冲区中

* 证明集合缓存区存储原理,将 <class-cache usage="read-write" class="cn.itcast.domain.Order"/> 注释掉

uploading.4e448015.gif正在上传…重新上传取消

当把类级别缓存去掉,那么查询语句将会重新查询数据库,二级缓存失效。

3) 一级缓存,具有同步更新二级缓存的能力
@Test

   public void test16()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      //存入一级缓存和二级缓存。

      Customer cus = (Customer) session.get(Customer.class, 2);

      System.out.println(cus);

      cus.setName("jhon");

      cus.setAge(20);

      transaction.commit();

      session.close();

      //二极缓存同步更新。

      session = HibernateUtils.openSession();

      transaction = session.beginTransaction();

      Customer cus3 = (Customer) session.get(Customer.class, 2);

      System.out.println(cus3.getName()+"  "+cus3.getAge());

      transaction.commit();

      session.close();

  }

解析:运行结果可以看出:
一级缓存,具有同步更新二级缓存的能力

Hibernate: select customer0_.id as id1_0_, customer0_.version as version1_0_, customer0_.name as name1_0_, customer0_.age as age1_0_ from sshdemo.customer customer0_ where customer0_.id=?

cn.itcast.hibernate.onetomany.Customer@932fe

Hibernate: update sshdemo.customer set version=?, name=?, age=? where id=? and version=?

jhon  20
 

  1. 将二级缓存保存到硬盘
    ehcache.xml  <diskStore path="java.io.tmpdir"/>  指定默认缓存到硬盘数据位置
    * 默认目录 C:\DOCUME~1\seawind\LOCALS~1\Temp\
    <diskStore> 指定硬盘缓存数据的位置
    <diskStore path="D:\cache" />
    *<defaultCache> 默认缓存配置
    *<cache> 设定具体的命名缓存的数据过期策略  例如: <cache name='cn.itcast.domain.Customer" > 针对Customer类的缓存策略
    <defaultCache  maxElementsInMemory="10000"  内存中最大元素数量,超过了数量 数据才会被缓存到硬盘上
    eternal="false"  是否永久缓存 false 不永久
    timeToIdleSeconds="120"   设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期
    timeToLiveSeconds="120"   设置对象生存最长时间,超过这个时间,对象过期         overflowToDisk="true" 是否输出到硬盘 true 输出
    maxElementsOnDisk=“10000000”  硬盘允许缓存对象数量 /> 
     
  2. 更新时间戳区域。
    时间戳缓存区域: org.hibernate.cahce.UpdateTimestampCache
    *
    时间戳缓存区域存放了对于查询结果相关的表进行插入, 更新或删除操作的时间戳.  Hibernate 通过时间戳缓存区域来判断被缓存的查询结果是否过期, 其运行过程如下:
    *T1
    时刻执行查询操作, 把查询结果存放在 QueryCache 区域, 记录该区域的时间戳为 T1
    *T2
    时刻对查询结果相关的表进行更新操作, Hibernate T2 时刻存放在 UpdateTimestampCache 区域.
    *T3
    时刻执行查询结果前, 先比较 QueryCache 区域的时间戳和 UpdateTimestampCache 区域的时间戳, T2 >T1, 那么就丢弃原先存放在 QueryCache 区域的查询结果, 重新到数据库中查询数据, 再把结果存放到 QueryCache 区域; T2 < T1, 直接从 QueryCache 中获得查询结果
  3. 查询缓存
    之前类级别缓存 或者 集合级别缓存,都是将数据存入 类级别缓冲区, 通过id 去查询对象  ---- keyid value是缓存对象
    查询缓存 key HQL语句、SQL语句  value是查询结果数据
    ***** 查询缓存,对于返回部分属性、单一结果值 都可以进行缓存
    问题: List list = session.createQuery("select name from Customer").list();  二级缓存无法解决
    uploading.4e448015.gif正在上传…重新上传取消
    启用查询缓存 ,必须要先开启二级缓存 (查询缓存依赖二级缓存
    hibernate.cfg.xml 添加 <property name=hibernate.cache.use_query_cache">true</property>
    对于希望启用查询缓存的查询语句, 调用 Query setCacheable(true) 方法向查询缓存 存入数据时 setCacheable(true)
    希望从查询缓存 获取数据时 setCacheable(true)
    *****
    二级缓存和查询缓存 主要用于 固定不变查询数据 ,如果数据会发生改变, 慎用二级缓存和查询缓存
    代码实例:

@Test

   public void test17()

   {

      Session session = HibernateUtils.openSession();

      Transaction transaction = session.beginTransaction();

      Query query = session.createQuery("select name from Customer");

      query.setCacheable(true);

      List list1 = query.list();

      System.out.println(list1);

      transaction.commit();

      session.close();

      //二极缓存同步更新。

      session = HibernateUtils.openSession();

      transaction = session.beginTransaction();

      Query query1 = session.createQuery("select name from Customer");

      query1.setCacheable(true);

      List list2 = query1.list();

      System.out.println(list2);

      transaction.commit();

      session.close();

   }

注意: query.setCacheable(true);
      query1.setCacheable(
true);
     
这两句必须同时存在,不然查询缓存不起作用。

程序运行结果:
Hibernate: select customer0_.name as col_0_0_ from sshdemo.customer customer0_

[jhon, maechl, maechl, kkk]

[jhon, maechl, maechl, kkk]

错误解析:the user must supply JDBC connections

uploading.4e448015.gif正在上传…重新上传取消

发现:没有configure();加载配置文件。

  • org.hibernate.ObjectNotFoundException: No row with the given identifier exists

在网上找了一下原因,主要原因是,一个表中存在数据,而他的关联表中却不存在数据。

产生此问题的原因抄录如下:

产生此问题的原因: 
         有两张表,table1和table2.产生此问题的原因就是table1里做了关联<one-to-one>或者<many-to-one unique="true">(特殊的多对一映射,实际就是一对一)来关联table2.当hibernate查找的时候,table2里的数据没有与table1相匹配的,这样就会报No row with the given identifier exists这个错.(一句话,就是数据的问题!) 
         假如说,table1里有自身的主键id1,还有table2的主键id2,这两个字段. 
         如果hibenrate设置的单项关联,即使table1中的id2为null值,table2中id2中有值,查询都不会出错.但是如果table1中的id2字段有值,但是这个值在table2中主键值里并没有,就会报上面的错! 
         如果hibernate是双向关联,那么table1中的id2为null值,但是table2中如果有值,就会报这个错.这种情况目前的解决办法就是改成单项关联,或者把不对应的数据改对! 
           这就是报这个错的原因了,知道原因了就相应的改就行了.或许还有些人迷惑hibernate关联都配好了,怎么会出现这样的错?其实这是编程的时候出现的问题,假如说我在添加信息的时候,页面传过来的struts的formbean到dao方法中需要封装成hibernate的po(就是hibenrate的bean),要是一个个po.get(form.set())实在太麻烦了,这样一般都会写个专门的方法来封装,遇到po.get(form.set())这种情况直接把struts的formbean对象传到此方法中封装就行了,假如我有个字段是创建人id,那么这个字段是永远不会改的,我在添加的时候还调用这个方法,这个专门封装的方法是有一些判断的,假如说我判断一下,如果遇到创建人id传过来为空值,我判断如果是空值,我把创建人id设为0,但是用户表中userid是主键从1开始自增的,那么这样数据就对应不上了,一查就会出这个错了.这个错在开发刚开始的时候经常发生,因为每个人的模块都是由相应的人独立开发完成以后再整合在一起的,每个人写单独那一块的时候往往会忽略这些,所以整合的时候这些问题往往就都一下子全冒出来了....整合很辛苦

 


 [h1]这里的关系只需单极映射即可。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值