SSH 学习笔记

Hibernater Hql

Hibernater分页查询失败,查询结果为所有,原因:

package com.tenni.test;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.tenni.entity.Account;
import com.tenni.entity.Service;
import com.tenni.util.HibernateUtil;

public class testHql {
    private Session session = HibernateUtil.getSession();
    private Transaction ts = session.getTransaction();
    
    @Test
    //分页查询
    public void testPaging(){
        int page=1, pageSize = 3,totalRows,from;
        String hql = "select count(*) from Service";
        Query qry = session.createQuery(hql);
        totalRows =Integer.valueOf(qry.uniqueResult().toString());
        System.err.println("所有的 数量 totalRows==="+totalRows);
        
        hql = "from Service order by id";
        qry = session.createQuery(hql);//必须在设置起始和容量之前
        from = (page-1)*pageSize;
        qry.setFirstResult(from);//设置起点,从0开始
        qry.setMaxResults(pageSize);// 设置页容量
        List<Service> list = qry.list();
        for(Service a:list){
            System.out.println(a.getId()+" "+a.getOsUserName()+" "+a.getLoginPassword());
        }
    }
}

 Hibernate 二级缓存管理异常情况及原因

再用ThreadLocal线程方式管理session的时候,HibernateUtil中静态获取session的方法以次线程为key,放入ThreadLocal的map中。(自己的理解不知道对否)

  1. 如果想要close掉session必须用HibernateUtil.close();否则提示异常:Session is closed!(如下代码)
  2. HibernateUtil.close()关闭session,必须在HibernateUtil.clearSessionFactory(e1<你从session中get的实体对象>) 清理二级缓存实体类之前。否则执行清理二级缓存之后,Hibernate依然不执行查询语句,从二级缓存中获取共享的查询实例对象结果。

 

附:HibernateUtil.getSessionFactory().getAllClassMetadata() 可以查看sessionFactory中的一些实体类信息

 测试代码如下:

@Test
//    二级缓存是SessionFactory级缓存,由它负责管理,因此需要获取到SessionFactory才能管理二级缓存,
//    我们先在HibernateUtil中增加获取SessionFactory的方法
    public void test2() {
        Session session1 = HibernateUtil.getSession();
        Emp e1 = (Emp) session1.get(Emp.class, 1708);
        System.out.println(e1.getEname());
        System.out.println("-----------session1-----"+session1);
//        session1.close();
       HibernateUtil.close();//前
        HibernateUtil.clearSessionFactory(e1);//后
        System.out.println("-----------session1-----"+session1);
        Session session2 = HibernateUtil.getSession();
        Emp e2 = (Emp) session2.get(Emp.class, 1708);
        System.out.println("-----------session2-----"+session2);
        System.out.println(e2.getEname());

    }

控制台输出:session1已经成功关闭

-----------session1-----SessionImpl(PersistenceContext[entityKeys=[EntityKey[com.tenni.entity.Emp#1708]],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[]])
-----------要close()====连接--SessionImpl(PersistenceContext[entityKeys=[EntityKey[com.tenni.entity.Emp#1708]],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[]])
-----------清理二级缓存中----实体类查询缓存
-----------session1-----SessionImpl(<closed>)

 

 

HibernateUtil.java

 

package com.tenni.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    private static SessionFactory sessionFactory;
    /* 使用ThreadLocal管理Session,可以保证一个线程中只有唯一的一个连接。
     * * 并且我们在获取连接时,它会自动的给我们返回当前线程对应的连接。
    */
    private static ThreadLocal<Session> tl = new  ThreadLocal<Session>();
    static{
//        加载Hibernate配置文件
        Configuration conf = new Configuration();
        conf.configure("/hibernate.cfg.xml");
        sessionFactory = conf.buildSessionFactory();
    }
    /**
     * 创建session
     */
    public static Session getSession(){
//        ThreadLocal会以当前线程名为key获取连接
        Session session = tl.get();
//        如果取到的当前的连接为空
        if(session == null){
//            使用工厂方法创建连接
            System.out.println("-----------getSession===使用工厂方法创建连接");
            session = sessionFactory.openSession();
//            ThreadLocal会以当前线程名为key保存session
            tl.set(session);
        }
        System.out.println("-----------getSession===使用tl.get() 获取连接--"+session);
        return session;
    }
    /**
     * 清理二级缓存中清理掉 实体类查询缓存
     */
    public static void clearSessionFactory(Object o){
        try {
            sessionFactory.evict(o.getClass());
            System.out.println("-----------清理二级缓存中----实体类查询缓存");
        } catch (Exception e) {
            System.out.println("xxxxxxxxxxx清理二级缓存中 实体类查询缓存 !!失败!!----"+e);
        }
    }
    /**
     * @return the sessionFactory
     */
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    /**
     *关闭session
     */
    public static void close(){
//        ThreadLocal会以当前线程名为key获取session
        Session session = tl.get();
        if(session != null){
            System.out.println("-----------要close()====连接--"+session);
            session.close();
//            将当前线程对应的连接从ThreadLocal移除
            tl.remove();
        }
    }
    public static void main(String[] args) {
        System.out.println("-----------"+getSession());
        System.out.println("-----------"+tl);
        close();
        }
    
}
HibernateUtil
 
Session is closed!
org.hibernate.SessionException: Session is closed!
    at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49)
    at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:874)
    at org.hibernate.impl.SessionImpl.get(SessionImpl.java:815)
    at org.hibernate.impl.SessionImpl.get(SessionImpl.java:808)
    at com.tenni.test.TestSecondCache.test2(TestSecondCache.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
    at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
    at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Session is closed!

 Hibernate 的动态update语句,实现部分字段更新

使用Hibernate修改时,它会根据映射关系文件,自动拼出一个update语句,然后执行修改,其中映射关系文件中往往配置表中全部的 字段,而很多时候,页面上不需要修改表中全部的字段,只需要修改其中的一部分,因此页面上的字段少于表中字段,在提交保存时,缺少的字段就成了空值,那么 再按照完整的update语句来执行更新,就会把这些不需要更新的字段更新为空。

这个问题如果使用JDBC或者MyBatis是不会存在的,因为SQL是自己写的。而Hibernate自动生成SQL,就出现了这个问题。

本案例中,我们采用动态更新的方式来解决这个问题,即在映射关系文件中通过dynamic-update=”true”来声明更新方式为动态 更新,届时Hibernate在自动生成update语句时会判断属性值是否发生改变,若改变则将属性拼入SQL,否则忽略掉这个属性。

这种方式要求传给Hibernate的对象必须是持久态的,而通过页面传入的对象是Struts2自动初始化的,是临时态的。我们可以通过 ID查询出持久态对象,然后通过Spring中的BeanUtils工具类,将临时态对象的属性值复制给持久态对象,然后用这个持久态对象进行更新即可。

<class name="com.tarena.entity.Cost" table="cost" dynamic update="true">
    <id name="id" type="integer" column="id">
    <!-- 用来指明主键的生成方式 -->
    <generator class="sequence">
    <param name="sequence">cost_seq</param>
    </generator>
    </id>
    .........

 

Struts2 重定向同一个namespace的action可以简写

如:重定向至、/cost/findByPage

<action name="saveCost" class="costAction“ method="saveCost">
    <result name="success" type="redirectAction">
        <param name="namespace">/cost</param>
        <param name="actionName">findByPage</param>
    </result>
</action>
改为:
<action name="saveCost" class="costAction" method="saveCost">
    <result name="success" type="redirectAction">
        findByPage
    </result>
</action>       

 

posted @ 2017-03-18 15:38  gcjava  阅读(505)  评论(0编辑  收藏  举报