zoukankan      html  css  js  c++  java
  • Hibernate 映射文件的配置 核心文件的配置 一对一 一对多 多对多 hibernate检索策略 Hibernate中session的关闭问题总结

    以留言系统为实例

    1 .配置映射文件:首先得引入约束dtd

    <!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

    然后<hibernate-mapping></hibernate-mapping>映射标签

    <class></class>标签  表示你要创建表的javaBean功能类  

    <id></id>配置表的主键id<generator class="native"><generator> native :hibernate自动是哪种数据库 然后根据数据库类型进行主键的增长   来保证数据的唯一性

    <proterty></proterty>来配置表的字段

    <set></set> 一对多是有的标签  来表示那个多的集合

    <one-to-one>  一对一

    <one-to-many>一对多

    <many-to-many>多对多

    2.核心配置文件

    同样的也要引入约束dtd

    <!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

    然后<hibernate-configuration></hibernate-configuration>加载核心文件标签

    <session-factory></session-factory>session工厂标签

    然后3个模块

    1  连接数据库  进行配置

    peroperty标签

      具体的

    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/liuyanban</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password"></property>

    2.hibernate信息模块

      输出日志

    输出sql语句:<property name="hibernate.show_sql">true</property>

    格式化sql语句 <property name="hibernate.format_sql">true</property>

    配置建表信息<property name="hibernate.hbm2ddl.auto">update</property>配置了这个有表就更新没有就创建

    配置session线程绑定<property name="hibernate.current_session_context_class">thread</property>

    配置数据库方言 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

    3。隐射文件配置

    <mapping resource属性/>

    2.一对一配置

    一对一关联分为主键关联和外键关联

        主键关联:不需要添加额外的字段,两个表的主键值一样

        外键关联:附表有一个额外的字段和主表相关联  或两个表都有额外字段和其对应的表相关联

    <one-to-one
            name="propertyName"                                (1)
            class="ClassName"                                        (2)
            cascade="cascade_style"                                 (3)
            constrained="true|false"                               (4)
            fetch="join|select"                               (5)
            property-ref="propertyNameFromAssociatedClass"          (6)
            access="field|property|ClassName"                        (7)
            formula="any SQL expression"                            (8)
            lazy="proxy|no-proxy|false"                         (9)
            entity-name="EntityName"                         (10)
            node="element-name|@attribute-name|element/@attribute|."
     
            embed-xml="true|false"
            foreign-key="foreign_key_name"
    />

    cascade:用于级联操作 crud操作   官方解释:表明操作是否从父对象级联到被关联的对象

    constrained(约束):表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。 这个选项影响save()和delete()在级联执行时的先后顺序以及 决定该关联能否被委托(也在schema export tool中被使用).

    fetch (可选 - 默认设置为select): 在外连接抓取或者序列选择抓取选择其一.

    property-ref:指定关联类的属性名  这个将会和本类的主键相对应,如果没有指定会使用对方关联类的主键

    lazy:对延迟查询的高效进行指定  如果为extra为及其懒惰 你要什么就给什么不给多也不给少 ,指定这个查询很高效

     access (可选 - 默认是 property): Hibernate用来访问属性的策略。

     formula (可选):绝大多数一对一的关联都指向其实体的主键。在一些少见的情况中, 你可能会指向其他的一个或多个字段,或者是一个表达式,这些情况下,你可以用一个SQL公式来表示。 (可以在org.hibernate.test.onetooneformula找到例子)

      lazy (可选 - 默认为 proxy): 默认情况下,单点关联是经过代理的。lazy="no-proxy"指定此属性应该在实例变量第一次被访问时应该延迟抓取(fetche lazily)(需要运行时字节码的增强)。 lazy="false"指定此关联总是被预先抓取。注意,如果constrained="false", 不可能使用代理,Hibernate会采取预先抓取!

    entity-name (可选): 被关联的类的实体名

     1.主键关联的:

        例: User和Account,一个用户对应一个账户。

      在附表的one-to-one中要写constrained="true" 表示受到约束通过一个外键引用对主键进行约束

     User类与配置文件

        private Integer id;

       private String username;

       private String password;

       private Account account;

        one-to-one中的class属性可以不写,默认Hibernate会使用反正自己去寻找。

    <one-to-one name="account" class="piaohan.domain.Account"cascade="all" />

     Account类与配置

       private Integer id;

       private String accountNum;

       private Integer money;

       private User user;

    <id name="id" column="id"><generator class="foreign"><!--本类中想要关联的属性--><param name="property">user</param></generator></id>

    <one-to-one name="user" class="" constrained="true"></one-to-one>

    表示不添加额外的字段 使两个表的主键值一样    这时两个表的主键的值一样

    2.单方外键关联 :

    例:一个留言对应一个回复

    在留言当中显示其对应的回复

    Message

     

    public class Message {

    private Integer mid;
    private String title;
    private String mtext;
    private String mtime;
    private User user;
    private Revert revert;

    <many-to-one name="revert" class="" unique="true"></many-to-one>

    这里就要问了  为什么是many-to-one呢    这种关联Message 实际上这里是用many-to-one然后用unique来进行限制  限制成一对一的关系

    所以一对一的单方外键关联是一个特殊的many-to-one的例子

    public class Revert {

    private Integer rid;
    private String rtext;
    private String rtime;
    private Message message;

    <one-to-one name="message" class="" property-ref="rever"></one-to-one>

    配置property-ref值为关联类的属性  其对应本类中的主键值  如果没有配置呢?会使用对方关联类的主键

    2.双方外键关联

    都是用<many-to-one></many-to-one>所以一对一的双方外键关联是一个特殊的many-to-one的例子

    关联类的属性是一样的     都要进行unique的配置 

      <many-to-one name="account" cascade="all" unique="true"

             column="accountid" />

        Account配置(类不变)

    <many-to-one name="user" unique="true" column="userid"

             cascade="all" />

     

    一对多的配置

     

    public User() {
    super();
    // TODO Auto-generated constructor stub
    }
    private Integer uid;
    private String username;
    private String password;
    private String email;
    private Set<Message> messageset=new HashSet<Message>();

    一个用户对应多个留言

    <set  name="messageset(对应本类中的set集合名)">

         //使用户有多个留言的关系  外键

        <key column="uid"></key>

       <one-to-many name="message" class=""></one-to-many>

    </set>

     

    public class Message {

    private Integer mid;
    private String title;
    private String mtext;
    private String mtime;
    private User user;
    private Revert revert;

    <many-to-one name="user" class="" column="uid(要与主表当中配置的外键保持一致)"></many-to-one>

    5.多对多的配置

    通过第三张表来表示两个表之间的关系

    private Integer rid;
    private String name;
    //通过建立set集合来表示一个角色可有对应多个用户
    private Set<User> userset=new HashSet<User>();

    <set name="userset(类中set集合)" table="userrole(第三张表的名称)" cascade="all">

       //user和role创建联系

       //外键的名称

       <key column="rid"></key>

       <many-to-many name="user" class="" column="uid"></many-to-many>

    </set>

    public class User {

    private Integer uid;
    private String username;
    private String password;
    //通过建立set集合来实现 一个用户有多个角色对应
    private Set<Role> roleset=new HashSet<Role>();

    <set name="roleset" table="(要保持一致)">

    //反映本类中的主键在第三张表中的外键

      <key column="uid"></key>

    <many-to-many name="role" class="" column="rid(与另一张中的配置保持一致)"> </many-to-many>

    </set>

    Hibernate检索策略

    分为立即查询和延迟查询

    特点:立即查询执行到这一句时立即发送查询数据库语句进行查询数据库  通过session.get()方法

          延迟查询:不会立即查询当到对像中取值才会发送语句  ,查询数据库 通过session.load()方法

       延迟又分为类级别延迟和关联级别延迟

       类级别:通过sesion.load()来实现

        关联级别实现:通过配置映射文件lazy(默认为true)  fetch(默认为select)

         lazy:true (延迟),false(不延迟),extra(极其懒惰(延迟上升一个等级效率高))

      批量抓取问题

       查询的数据量比较大产生的问题是  会重复查询相同的语句

       通过batch-size值越大性能越高

    一级缓存和二级缓存的问题

    他们的特点:一级缓存:1.默认是打开的

                                    2.存储的数据必须是持久态

                                   3.适用范围是session的开启到关闭

                     二级缓存:1.需要手动打开

                                    2.范围是sessionfactory范围

      User user=session.get(User.class,1(id值))执行过程

      user.setName("ji");

       首先会看一级缓存中是否有use内容,如果找不到会查询数据库,得到user对象存入一级缓存和快照区中

     执行到第二句时  只改变一级缓存中的值而不该快照区中

      执行commit时会做一件事情  比较

      如果快照区中的值与一级缓存值不相同那么就更新

      如果相同那么就不更新。   

    Hibernate中的session关闭问题

    session相当于jdbc中的connection 所以需要进行关闭

    但是由于session要与本地线程进行捆绑来实现其单线程对象的特性

    创建工具类

    package com.jdztc.util;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    /**
     * 
     * @author 付鹏鹏
     *产生SessionFactory核心工具类
     */
    public class HibernateUtil {
    
        //采用静态代码块的方式   因为静态代码块是类加载的时候运行,且只运行一次
        private static Configuration configuration=null;
        private static SessionFactory sessionFactory=null;
        private static Session session=null;
        static{
            //加载核心配置文件, 创建对象将文件放入对象当中
           configuration=new Configuration();
           configuration.configure();
           
           //通过有文件的对象的引用来创建SessionFactory ,根据核心配置文件中的数据库信息  和映射文件来进行表格的创建
          sessionFactory= configuration.buildSessionFactory();
          //通过getCurrentSession()的方法来得到保证是单线程对象的Session
          session=sessionFactory.getCurrentSession();
        }
        public static Session gerThreadSession(){
            return session;
        }
        public static SessionFactory getSessionFactory(){
            return sessionFactory;
        }
        public static void main(String[] args){
            
        }
    }

    在查询数据库中 HibernateUtil.getSession()时不能关闭因为执行到commit()会自动关闭  如果你还关闭将会报session已经关闭

    还有一点:commit也不能随便要到最后关闭   举个例子:

     public static void addRevert(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String mid=req.getParameter("uid");
            System.out.println("uid +"+mid);
            String content=req.getParameter("content");
            System.out.println("content:"+content);
            if(content.indexOf("
    ")!=-1){
                content.replace("
    ", "<br>");
            }
            Message message=MessageDao.getMessage(mid);
            if(message!=null){
                //将message与revert相关联     设置revert中的message与message中的revert
                Revert revert=message.getRevert();
                System.out.println("revert:"+revert);
                if(revert==null){
                    revert=new Revert();
                }
                Date date=new Date();
                DateFormat time1=new SimpleDateFormat("yyyy.MM.dd HH:mm:ss ");
                String time=time1.format(date);
                //  设置message中的revert
                System.out.println("revert2:"+revert);
                message.setRevert(revert);
                RevertDao.add(revert, content, time, message);
                //更新留言
                MessageDao.updateMessage(message);
                //req.getRequestDispatcher("index.jsp").forward(req, resp);
            }else{
                System.out.println("message == null");
            }
            
        }
     Message message=MessageDao.getMessage(mid);通过内容来查询message 
    getMessage(mid)方法中commit和rollback()都不能有全部删除 因为session已经和本地线程绑定 如果关闭
    Message message=MessageDao.getMessage(mid);下面的代码将不能得到session  所以必须到
    在 MessageDao.updateMessage(message);方法中commit()和rollback()
    在addRevert方法的最后进行关闭  注意之前不能有commit()和rollback()
  • 相关阅读:
    C++细节决定成败---菜鸡程序员被前辈蹂躏历程(持续更新)
    VIM杂记——基本使用
    UE4——用Android Studio打开UE4工程
    UE4——打包时遇到Could not determine java version from 'xx.x.x'的问题
    HTML笔记——常用标签总结
    LeetCode——142. Linked List Cycle II
    Leetcode——344. Reverse String
    UE4 隐藏虚拟摇杆
    UE4——实现走近物件其上方出现互动按钮并弹出UMG的功能
    UE4——调用API实现布娃娃死亡效果
  • 原文地址:https://www.cnblogs.com/fupengpeng/p/6791673.html
Copyright © 2011-2022 走看看