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、多使用双向关联

  • 相关阅读:
    设计模式之Singleton(单态)(转)
    shell编程与循环
    连接查询、视图、事务、索引、外键
    mariadb主从架构
    Lvs虚拟服务器
    python字符串详解
    firewalld防火墙详解
    自动化运维ansible用法
    元组、列表、字典、集合
    内置函数for、while循环控制
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/5807484.html
Copyright © 2011-2022 走看看