zoukankan      html  css  js  c++  java
  • hibernate复习第(4)天

    1、hibernate的映射类型。
    hbm.xml中property中的type属性。
    这个type属性是表示持久化类中的属性对应数据库中的什么数据类型,用来构建一种映射
    type的可选值:
    hibernate的内建类型:
    integer,long,short,float....
    string
    date,time,timestamp
    ....
    java的类型:必须加上全包名,比如:java.lang.Integer
    type一般都有自己的缺省值,大多数情况下不需要设置。
    设置type的场合:
    比如我设置持久化类类型为Date类型,我希望保存到数据库中只是有日期没有时间,缺省状态下type是timestamp,保存的是日期和时间都有,这时候我们需要将type属性设置成为time即可。

    2、

    Session的内部缓存管理
    flush():将一级缓存与数据库进行同步
    这是什么意思呢?就是hibernate在处理与数据库有关的操作的时候,只有必要的时候才会立刻与数据库进行交互,一般是将处理数据库的语句堆叠在一起,然后在commit()的时候再一起进行与数据库的交互,这样可以提高性能。当然如果在commit()之前查询了前面save的数据,它是会先与数据库交互的,所以说是在不必要的情况下将与数据库的交互堆叠在commit为信号处理。
    flush方法就是将一级缓存与数据库同步,之前未交互的数据是在缓存中的,使用flush方法就直接执行缓存中的所有的sql交互语句,不需要到commit了。

    例子:

    View Code

    大批处理:
    大量操作数据可能会造成内存溢出,解决方法如下:
    1、定时清除session中的数据

    for(int i=0;i<100000;i++){
    session.save(obj);
    if(i%50==0){
    session.flush();//这一步需要进行,否则怕丢失数据
    session.clear();
    }
    }

    2、使用StatelessSession接口,该接口不会与一二级缓存交互,也不会触发任何事件、监听、拦截,通过该接口的操作会立刻发送给数据库,和JDBC功能一样。

    StatelessSession ss=HibernateUtil.getSessionFactory().openStatelessSession();

    该接口的使用与普通session类似
    3、Query.executeUpdate()执行批量更新,会清除相关联的一二级缓存(sessionFactory.evict(class)),可能造成级联和乐观锁定出现问题

     Query query=s.createQuery("update u set Date=:dt from User");
                query.setDate("dt", new Date());
                query.executeUpdate();

    HQL:
    查询多个对象,返回的是对象数组。
    select art,user from Article art,User user where art.author.id=user.id and art.id=:id 返回的是Object[] Object[0]:article,Object[1]:user
    我们一般查询的都是整个对象而不是该对象的某几个属性,因为如果查询的是某几个属性不方便转换,建议查询整个对象,然后从对象中取值。
    在已知id的情况下建议使用get()或者load()查询而不是hql语句或者criteria查询,因为前者会使用缓存而后者不会。所有有一个性能的问题选择
    分页:query.setFirstResult,query.setMaxResults
    查询记录总数:query.iterator("select count(*) from Person").next()
    批量更新query.executeUpdate()可能造成二级缓存数据失效

    Criteria:
    排序:Criteria.addOrder(Order.desc(propertyName));
    关联查询:criteria.setFetchMode("propertyName",FetchMode.SELECT) 和映射文件属性中设置fetch一样
    投影:Projections.rowCount(),max(PropertyName),avg,groupProperty...
    分页:Projections.RowCount(),criteria.setFirstResult(),criteria.setMaxResults()
    离线查询:DetchedCriteria可在session外创建,然后使用getExecuteableCriteria(Session)创建Criteria对象来完成查询
    Example查询,Example.create(obj),criteria.add(example)

    N+1查询:
    iterator方法:
    iterator方法的步骤:首先查询出所有结果集的对应的id的列表,然后根据id查询各个数据列。所以叫做n+1次。iterator中的n次的时候可以使用缓存。
    其他N+1地方:
    懒加载获取关联对象:
    遍历查询一对多中多的信息。应为一对多中使用懒加载,只有使用它属性才会查询,所以查询所有有n次,前面查询父对象需要一次
    如果打开对查询的缓存,即list也可能有n+1次缓存

    hibernate中的监听(event)
    hibernate中也可以使用监听,执行save等前后的操作。
    第一步:
    书写监听器,实现特定接口。书写代码:

    public class SaveListener implements SaveOrUpdateEventListener{
    
    public void onSaveOrUpdate(SaveOrUpdateEvent event)
    throws HibernateException {
    Object obj=event.getObject();
    if(obj.getClass().getSimpleName().equals("User")){
    User u=(User) obj;
    System.out.println(u.getName().getFirstName());
    }
    }
    
    }
    View Code

    第二步:配置监听器

    <event type="save">
    <listener class="cn.itcast.web.listener.SaveListener"/>
    </event>

    其他的就是使用了!
    注意:hibernate中默认的save等方法进行sql操作是通过监听完成的,如果你单纯的配置自己的监听,那么hibernate会以为你拥有更好的实现sql操作的方式,所有会发现你无法插入数据到数据库中。这个时候,你可以再配置一个监听器,也就是默认的监听器。监听器的执行步骤和配置顺序一致

    <event type="save">
    <listener class="cn.itcast.web.listener.SaveListener"/>
    <listener class="org.hibernate.event.def.DefaultSaveOrUpdateEventListener"/>
    </event>

    SQL和命名查询
    在hibernate中使用SQL语句进行查询,使用SQLQuery接口

    static User query(int id){
    Session s=null;
    try{
    s=HibernateUtil.getSession();
    User user=(User) s.load(User.class, id);
    //user.getName(); 在session关闭前简单使用下该对象,就会立刻加载过来了。不建议这样使用,因为调用该对象的语句看起来没有意义可能被误删
    Hibernate.initialize(user); //建议使用这种方式
    return user;
    }finally{
    if(s!=null) s.close();
    }
    }
    View Code

    命名查询:
    在映射文件中配置命名参数,然后在dao中直接使用命名参数生成query对象。

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping 
    package="cn.itcast.domain">
    
    <class name="User" table="user">
    <!-- 
    <cache usage="read-write"/>
    -->
    
    <id name="id">
    <generator class="increment"/>
    </id>
    
    
    <version name="ver" type="timestamp"/> <!-- 缺省状态是int类型 -->
    
    <!-- <timestamp name="ver"/>--><!-- 类型只能是Date类型 -->
    <property name="birth"/>
    <component name="name" class="Name">
    <property name="firstName" column="first_name"/>
    <property name="lastName" column="last_name"/>
    </component>
    
    <query name="findUserById1">
    <![CDATA[from User where id=:id]]>
    </query>
    
    </class>
    
    <query name="findUserById">
    <![CDATA[from User where id=:id]]>
    </query>
    
    <sql-query name="findUser">
    <![CDATA[select * from user]]>
    </sql-query>
    
    </hibernate-mapping>
    View Code

    命名查询的配置地点是在hbm映射文件中,可以在class之内配置也可以在class之外配置。
    配置在class之外,相当于整个项目的成员变量,使用的时候:
    Query query=s.getNamedQuery("findUser");直接使用nameshuxi9ng即可,但是,注意name是唯一的,不允许重复
    如果配置在class之内,使用的时候使用全路径。
    使用:

    s=HibernateUtil.getSession();
    Query query=s.getNamedQuery("findUserById");
    query.setInteger("id", 1);
    User user=(User) query.list().get(0);
    System.out.println(user.getName()+"--"+user.getBirth());
    
    Query query=s.getNamedQuery("cn.itcast.domain.User.findUserById1");

    命名查询不只是可以配置hql查询,也可以配置sql查询:

    <sql-query name="findUser">
    <![CDATA[select * from user]]>
    </sql-query>
    
    Query query=s.getNamedQuery("findUser");
    List<Object[]> user=query.list();
    Object[] u=user.get(0);
    System.out.println(u[0]+"---"+u[1]+"---"+u[2]);


    hibernate的最佳实践:
    1、多使用细粒度的组件,componment
    2、主键最好无意义
    3、最好每一个持久类对应一个映射文件
    4、考虑把查询字符串放到程序外面,也就是使用命名查询
    5、使用绑定变量:=name
    6、不要把异常看成可恢复的,尽量使用RuntimeException而不是Exception
    7、考虑将hibernate代码从业务逻辑代码中抽象出来
    8、多使用双向关联

  • 相关阅读:
    codeforces 616B Dinner with Emma
    codeforces 616A Comparing Two Long Integers
    codeforces 615C Running Track
    codeforces 612C Replace To Make Regular Bracket Sequence
    codeforces 612B HDD is Outdated Technology
    重写父类中的成员属性
    子类继承父类
    访问修饰符
    方法的参数
    实例化类
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/5807484.html
Copyright © 2011-2022 走看看