请教 :hibernate 3张表 如何建关联 及增删改查 谢了  

解决方案 »

  1.   

    O/R映射框架  反射技术  优点:   1.提高生产力,不用再写sql语句,不用遍历结果集,代码量减少,
               2.使开发更对象化了,只要操纵session对象save方法就保存数据了
               3.移植性好,也就是方言的配置,适配器的配置,
               4.支持透明持久化,实体没有侵入性,可以复用,
       试用hibernate先建立对象模型,也就是领域模型,再建立映射关系,都是一对象为中心
       
    注意:这里是斜杠啊<mapping resource="com/landy/hibernate/User.hbm.xml"/>
       
     hibernate的映射工具:
               1.Configuration(根启动) cfg=new Configuration.configure();------>读取hibernate的配置文件hibernate.cfg.xml,加入内存
               2.SessionFactory factory=cfg.bulidSessionFactory();存储sql语句和映射源数据(连接池) ,SessionFactory适合数据库绑定的,一个数据库对应一个Sessionfactory,他是重量级的对象,就是创建比较耗时,消耗资源,最好只创建一次,他是线程安全的,可以对个线程用它,SessionFactory和二级缓存相关,
               3.Session  存放当前工作单元所加载的对象,他不同于Connection,是有SessionFactory创建出来的,他对Connection进行了封装,Session他管理了缓存,对实体对象生命周期管理,一般是一个业务对应一个Session, Session用完后必须关闭,是非线程安全的,Session和一级缓存相关
               
       
     hibernate核心接口:
               1.JNDI Java名称和目录接口,统一管理,不依赖具体实现,解决了耦合
               2.JDBC Java数据库连接,它处理本地事务,单一数据库,能保证原子性,但是跨数据库,跨资源,JDBC就不能保证了,
               3.JTA  Java事务API,保证跨数据库,跨资源的事务处理,他是两阶段数据处理,先是日志再更新,JTA是个容器,
               4.Query 查询接口,支持hql和sql
               5.Interceptor 拦截器,没有浸入性,他能将我们对实体类进行保存,删除前后的事件能侦听到,
               6.UserType 转换器的概念,用户可自定义类,
     持久化对象的生命周期:Transient(瞬时的),Persistent(持久的),Detached(离线的)
               
               1.Transient  *在数据库中没有与之匹配的数据
                            *没有纳入Session的管理
                            
               2.Persistent *在数据库中有与之匹配的数据
                            *纳入了Session的管理
                            *在清理缓存(脏数据检查)的时候,会和数据库同步
                            
               3.Detached   *在数据库中有与之匹配的数据---------->只有数据库中有了才能update处理 
                            *没有纳入Session管理
       
     Session的load()方法 实现了lazy,懒加载或延迟加载,按OID检索,只有正真使用这个对象时才加载(发出sql语句),hibernate延迟加载实现原理是代理方式,
                  正真使用时对象就是persistent状态了,hibernate会自动和数据库同步,采用load在加载数据时,如果数据库中没有相应的数据,那么抛ObectNotFoundException异常, Session的get()方法 在加载时马上发出sql语句,加载对象,不会有延迟,当查询数据不存在的数据时,返回null,并不抛出异常
      
     一般是先加载在修改,删除,也就是不要手动构造detached状态,  有许多的批量的处理就不太试用hibernate
    域对象之间的关系
               1.关联:类之间的引用关系,以属性申明体现 ------>一对一,一对多,多对一,多对多
               2.依赖:类之间访问关系,类中的方法
               3.聚集:生命周期(逻辑上的约束)
               4.一般化(泛化)继承
               主键生成策略:             
       assigned  自然主键:手动赋值
       native 动态的选择合适的标示符生成器,OREACL用到的序列hibernate_sequence
       sequence  
       identity SQLServer,MYSQL
       hilo 加一取走
       increment:拿来加一
     
     
       access=“property|filed”(访问级别,默认property)
       
       
     
     inverse  让缓存忽略set集合的变化,只关心one方,在双向关联时通常都会更新两次,inverse=true
              在映射一对多的双向关联关系时,应该在one方把inverse属性设为true,one方有集合,这可以提高性能。在建立两个对象的关联时,
              应该同时修改关联两端的相应属性:
                      Customer.getOrders().add(order);
                      Order.setCustomer(customer);这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码不受Hibernate实现类的影响。
              同理,当删除双向关联的关系时,也应该修改关联两端的对象的相应属性:
                      Customer.getOrders().remove(order);
                      Order.setCustomer(null);
           
       
     级联关系  cascade="save-update" 关联关系的级联程度,主体改变后客体按照级联程度也进行保存更新,
              双向关联时两方同时进行,防止数据的不一致,关联关系的维护hibernate自动做了,所以在进行保存更新时只保存一方就行了,而和她关联的hibernate
              机动保存更新了,这就是级联,级联操作在开发中慎用,
              级联删除,利用jdbc删除有外键约束,利用程序删除就会被级联一起删除(更新),hibernate执行update语句将外键置为null来解除关联,
              如想删除不再关联的对象,就将cascade="all-delete-orphan"
            
     父子关系:cascade="all-delete-orphan" 子代不能删除父代,只能删除和父代关联的子代;更强的约束,将非法数据删除,关联关系的级别就不是更新了,就直接删除操作
    就是没有对应的客户的订单也删除,对应的是删除操作,但原来是null的,他不会删除
             
            
     
     多对一关联关系:
               1.cascade属性为save-update的话,可实现自动持久化所关联的对象。
               2.<many-to-one>
               
               
     一对多关联关系:
               1.<set name=“orders”  cascade=“save-update”>
                      <key column=“CUSTOMER_ID” />
                      <one-to-many class=“..Order” />
                 </set>
                 name:设定待映射持久化类的属性名。
                 cascade:设定级联操作的程度。
                 key子属性:设定与所关联的持久化类对应的标的外键。one-to-many子属性:设定所关联的持久化类。
    hibernate数据操作,面向对象:
              1.插入 save()
                       对象加入缓存,成为持久化对象
              2.更新 update() 将游离对象转变为持久化对象。不论对象属性是否发生变化,该方法都会执行update操作。如果希望仅当属性变化时才执行update语句的话可进行如下配置:(还要看具体业务了,不一定打开就好)
                         <class name=“…” 
                                 table=“…” 
                                   select-before-update=“true”> ----------------------更新之前先查询,只更新改变了的,
                    Session的update操作方法盲目的激活触发器, 如果游离状态的对象的属性和数据库一致,则更新操作是多余的。为避免这种情况:
    <class name=“” table=“” select-before-update=“true”>
                                  ……
    </class>          3.查询 load(Class,id)
                     根据OID在缓存中查询,类型,OID          4.删除 delete()
                      如果参数是持久化对象,就执行一个delete语句,若为游离对象,先使游离对象被session关联,使他变为持久化对象,然后计划执行一个delete语句。          5.批量删除 **hibernate 3.0支持批量删除
                    //只是创建除了删除条件,还没有执行
                Query c=s.createQuery("delete from Customer c where c.id < 4");-------->用到Hql
                //执行
                c.executeUpdate();
              
               6. Transaction.commit(); //提交 先清理缓存,然后向数据库提交事务, 在提交前Session有个清理缓存的模式setFluseMode(FlushMode.AUTO/COMMIT/NEVER),
                              模式设置为NEVER时,只有再调用flush()方法时才会提交到数据库中,           7. Session.flush();      //清理 缓存,让数据库和缓存同步,将缓存的变化反应到数据库中,但不提交,不提交就可以回滚,           8. Session.refresh();    //刷新 缓存,让缓存和数据库同步,取数据库中变化来更新缓存,执行查询操作,           9. Session.clear()       //清空 缓存,将缓存中的引用全销毁,但引用的对象不一定被销毁,要看对象是否还有其他的引用, 
    10. Session.delete(d):将对象从Session中和记录中删除,将对象变为临时态,
    11. Session.evict(c):将持久态对象转变成游离的状态,将对象单纯的从缓存中删除,并不对应删除记录的操作,
    12. Session.saveOrUpdate():调用此方法时oid为null时肯定是save操作,如果oid类型定义为基本数据类型,那默认值为0,就不能是save操作,那怎么让oid是基本数据类的数据有插入操作,在配置文件中将id有个属性unsaved-value=“0”,这样就将oid为基本数据类型的记录调用saveOrUpdate方法时可以是save操作。
                     Session的save,update,saveOrUpdate方法都是将非持久化对象与Session关联让他们变成持久化对象, 缓存里的对象根据快照来查看数据是否有变化,只有来自数据库时才做快照(load),触发器:在服务器执行,(数据库中执行)
    Session.save(c);
    Session.flush();   //执行后,进行更新数据库操作,触发了触发器,在application端并不知道,
    Session.refresh(c);  //缓存与数据库同步
    触发器的行为导致缓存与数据库中的数据不一致。解决办法是执行完操作后,立即调用session的flush方法和refresh方法,迫使缓存与数据库同步。Session的update操作方法盲目的激活触发器,如果游离状态的对象的属性和数据库一致,则更新操作是多余的。为避免这种情况:
    <class name=“” table=“” select-before-update=“true”>
                          ……
    </class>select-before-update的作用   1.更新没有修改的数据
    2.盲目更新激活触发器映射组成关系:<compont name=“homeaddress” class=“mypack.Address”> 他是值类型, component可以嵌套, 
     
                  持久化类的属性分为两种:值(value)类型和实体类型(entity)类型。值类型没有OID,不能被单独持久化,他的生命周期依赖于所属的持久化类的对象的生命周期,组件类型就是一种值类型;实体类型有OID,可单独持久化。 在组合类型中save时没有赋值,在数据库中将会存入null,当查询时就会报空指针异常,因此要判断如果null就new一个然后添加上 
    类级别的检索:当查询对象的时候hibernate什么时候查询对象所对应的表,load受影响
          立即检索:查询表,也就是在缓存里没有,他马上就查询库      延迟检索:只有正真访问对象,在内存里创建代理对象, 他先检查缓存里,缓存里没有,他并不立即查询库
                     <class name="cn.itcast.hibernate.domain.Customer" table="hib_customers" lazy="true">      代理类是用反射技术动态生成的一个新类,他继承了客户类,代理对象他能够监控Session是否关闭,在Session关闭之前你访问代理对象的有效属性时,就会触发代理对象去访问数据库的事件,进行查询操作,将结果赋给代理对象的属性,这个过程就是初始化代理对象,只有延迟检索才会有代理对象的概念,
    代理对象在Session持久化时并没有赋初值,Session关闭后再去初始化,去查库,然而连接已关闭了,报 延迟初始化异常,可以通过下面方法进行初始化:
     关联级别的检索:当查询主体表的时候观察和他关联的表的相应,  有了主体才有客体
    set: one-to-many
                    立即检索:get                                lazy=false,
                    延迟检索:load 延迟到正真访问关联元素的时候  fetch=select&lazy=true ||    size()/count(*)----->extra(特别懒)
                    迫切左外连:以外连接  fetch=join
          
                         
    Many-to-one:
              
    两边都是外连接,理论是打印出一条里面有两次外连接的语句,这在2.0是符合的,但这样会降低性能,但在3.0打印出两条语句,目的优化,忽略了第二次迫切左外连接检索,采用和lazy保持一致的检索,lazy=flase就立即,lazy=true就延迟。
    Hql语句忽略了迫切左外检索,他与lazy保持一致
    set批量立即检索  批量的检索用batch-size,和lazy来设置,Hql语句忽略了迫切左外检索,他与lazy保持一致,降低和数据库的交互次数:<set   batch-size=“ 条数”>设置一次检索的条数,一般在3-10之间批量延迟检索: 用Hql语句查询,只要将lazy=true,就是延迟检索了
    Many-to-one的批量检索,orders集合对应几个客户,一次查一个客户,要查询多次,设置一次可以查询多个客户,应该在orders对端(客户)的类级别进行设置:
      

  2.   

    挺麻烦的拼sql语句放tmp里面执行吧
      

  3.   

    如果3张表有外键关系 那么你要根据具体情况配置N对N的映射关系 并且需要考虑延迟加载问题
    如果没有外键关系 那么在service层对3个表操作的DAO进行事物封装 将3个表的操作放到一个事务中
      

  4.   


    都用了Hibernate了谁还写SQL啊。楼主说要三张表建立关联,把主外键做好了不就行了,只要能让三个Bean之间有联系就行了,再设一个自动加载,就什么都搞定了。当然是否设置自动加载得视情况而定。虽然那个很方便,但有时候还是会影响效率
      

  5.   


    在一楼的基础上,为了减少xml的配置,也可以用annotation,这样可以在实体类里面指明主键,关联关系等
      

  6.   

      配置hbm文件,写一条Hql语句 搞定! 
      

  7.   

    用一对多和多对一来关联。在这提一个问题啊。写的存储过程在Hibernate里配置的时候不绑定实体类,怎么把查询出来的数据遍历出来?(注:A表与B表有主外键关系,B表和C表有主外键关系,A表和C表没关系,现在要在A表中显示出C表的字段。存储过程是这三个张联查的)