zoukankan      html  css  js  c++  java
  • Hibernate 查询技术

    转载: http://blog.csdn.net/u014078192/article/details/24986475


    一、Hibernate的三种查询方式(掌握)

    Hibernate中提供了三种查询方式:

    1)Session的查询:按主键查询查询,方法为get或load

    2)Query的查询:使用HQL语句或SQL语句完成查询

    3)Criteria的查询:通过方法和类中属性的关系,来设置查询条件,完成查询。

    Session中get和load方法的区别?

    1)  如果没有查询到数据,get会返回null,而load则直接提示错误。

    2)  使用load查询时,可能会出现以下错误,因为load方式使用的是懒汉式加载方法。执行load方法时,不立刻查询数据库。当用到查询出的对象的属性时,才加载数据。

    [java] view plain copy
    1. org.hibernate.LazyInitializationException: could not initialize proxy - no Session  

    解决这个异常的方法:

    1)  不关连接;2)不用load,就使用get就可以了

    1.1、Query查询(重点)

    1.1.1HQL语句不只支持查询功能,还支持修改以及删除功能

    [java] view plain copy
    1. public void doRemove(Integer id) throws Exception {  
    2.         // 注意,使用Hibernate删除时,必须先查询对象,再删除.  
    3.         // HibernateSessionFactory.getSession().delete(findById(id));  
    4.         String hql = "DELETE FROM News AS n WHERE n.id = ?" ;  
    5.         Query query = HibernateSessionFactory.getSession().createQuery(hql);  
    6.         query.setInteger(0, id);  
    7.         query.executeUpdate();  
    8.     }  
    注:使用HQL的删除可以不需要先查询,直接删除,支持一次删除多条数据
    开发中的选择:1)当删除一条数据时,直接使用session.delete()就可以,因为简单,hibernate不在乎那点查询的性能;

    2)批量删除时,使用Hql形式,这是可以提高性能的方法,因为它中间省去了查询的步骤。


    1.1.2HQL语句修改功能

    [java] view plain copy
    1. public void doUpdate(News vo) throws Exception {  
    2.         // HibernateSessionFactory.getSession().update(vo);  
    3.         String hql = "UPDATE News AS n SET n.title = ?,n.content = ? WHERE n.id = ?" ;  
    4.         Query query = HibernateSessionFactory.getSession().createQuery(hql);  
    5.         query.setString(0, vo.getTitle());  
    6.         // ....其他参数一样设置  
    7.         query.executeUpdate();  
    8.     }  
    开发中的选择:1)如果是直接的修改功能,肯定选择session.update()方法;

    2)如果是只修改某一字段,使用HQL方式。
    注:HQL语句不支持添加,但是Query支持添加。


    1.1.3针对HQL的查询功能,也支持写SELECT,可以通过编写SELECT,来只查询对象中某一个或某几个属性。

    但是对于多种字段不同类型的查询返回的,Hibernate中只能是数组。

    例如:

    [java] view plain copy
    1. public List testHQL() throws Exception {  
    2.         String hql = "SELECT n.id,n.title FROM News AS n";  
    3.         Query query = HibernateSessionFactory.getSession().createQuery(hql);  
    4.         return query.list();  
    5.     }  

    经过测试,发现当只查询一个字段时,直接返回该类型的List集合。

    但查询两个以上的字段时,返回的是List<Object[]>,每一条查询出的数据,使用Object[]来表示,这就很不方便。

    [java] view plain copy
    1. public void testHQL() throws Exception {  
    2.         List all = ServiceFactory.getINewsServiceInstance().testHQL();  
    3.         Object[] value1 = (Object[]) all.get(0);  
    4.         System.out.println(value1[1]);  
    5.     }  

    这样使用起来很麻烦,因此在Hibernate3.2以上的版本中,提供了一个自动转换类,可以将查询出的Object[],自动转换为pojo 对象。

    [java] view plain copy
    1. public List testHQL() throws Exception {  
    2.         String hql = "SELECT n.id AS id,n.title AS title FROM News AS n";  
    3.         Query query = HibernateSessionFactory.getSession().createQuery(hql);  
    4.         <span style="color:#cc0000;">query  
    5.                 .setResultTransformer(new AliasToBeanResultTransformer(  
    6.                         News.class));</span>  
    7.         return query.list();  
    8.     }  
    注:一般开发中不会使用这种方法,只有当表中的字段过多,但查询只需要其中的几个字段时,才会用到这种方法。


    1.1.4Hibernate还可以将语句写到配置文件中

    [java] view plain copy
    1. <query name="findAll">  
    2.         FROM News AS n WHERE n.title LIKE ?  
    3.     </query>  

    通过程序读取配置文件,取得这段HQL,并生成Query对象,完成查询。

    [java] view plain copy
    1. Query query = HibernateSessionFactory.getSession().getNamedQuery(  
    2.                 "findAll");  
    3.         query.setString(0"%测试%");  
    4.         return query.list();  
    这种方式在Mybatis中普遍使用,但是在Hibernate中一班很少这样做。

    1.2、Criteria查询(了解)

    Criteria也是Hibernate提供的一个查询对象,支持按对象的方式来完成查询。例如:

    查询全部功能:

    [java] view plain copy
    1. public List<News> testCriteria() throws Exception {  
    2.         // 根据传入的pojo类型,查询该类型对应的全部数据  
    3.         Criteria c = HibernateSessionFactory.getSession().createCriteria(  
    4.                 News.class);          
    5.         return c.list();  
    6.     }  

    如果想加入查询条件,需要使用Restrictions的各种方法来完成条件的拼写。

    [java] view plain copy
    1. public List<News> testCriteria() throws Exception {  
    2.         // 根据传入的pojo类型,查询该类型对应的全部数据  
    3.         Criteria c = HibernateSessionFactory.getSession().createCriteria(  
    4.                 News.class);  
    5.         // 1、WHERE id = 26  
    6.         // c.add(Restrictions.eq("id", 26));  
    7.         // 2、WHERE id > 26  
    8.         // c.add(Restrictions.gt("id", 26));  
    9.         // 3、WHERE id < 26  
    10.         // c.add(Restrictions.lt("id", 26));  
    11.         // 4、WHERE id >= 26  
    12.         // c.add(Restrictions.ge("id", 26));  
    13.         // 5、WHERE id <= 26  
    14.         // c.add(Restrictions.le("id", 26));  
    15.         // 6、WHERE id <> 26  
    16.         // c.add(Restrictions.ne("id", 26));  
    17.         // 7、WHERE title LIKE '%测试%'  
    18.         // c.add(Restrictions.like("title", "%测试%"));  
    19.         // 8、WHERE id between 23 and 27  
    20.         // c.add(Restrictions.between("id", 23, 27));  
    21.         // 9、WHERE id IN (23,25,27)  
    22.         // List<Integer> allIds = new ArrayList<Integer>();  
    23.         // allIds.add(23);  
    24.         // allIds.add(25);  
    25.         // allIds.add(27);  
    26.         // c.add(Restrictions.in("id", allIds));  
    27.         // 10、复杂条件,需要使用and或or来连接各个条件  
    28.         // WHERE id = 23 OR (id <> 26 AND title LIKE '%测试%')  
    29.         c  
    30.                 .add(Restrictions.or(Restrictions.eq("id"23), Restrictions  
    31.                         .and(Restrictions.ne("id"26), Restrictions.like(  
    32.                                 "title""%测试%"))));  
    33.         return c.list();  
    34.     }  

    如果想加入ORDER BY排序条件,需要使用Order对象。

    [java] view plain copy
    1. c.addOrder(Order.desc("id"));  

    如果想加入统计函数和分组函数,则需要用到Projection这个类

    [java] view plain copy
    1. <span style="white-space:pre">  </span>ProjectionList pro = Projections.projectionList();  
    2.         // 加入统计函数  
    3.         pro.add(Projections.rowCount());  
    4.         // 还可以加入分组条件  
    5.         pro.add(Projections.groupProperty("title"));  
    6.         c.setProjection(pro);  

    、Hibernate中Session操作的三种状态

    Session操作过程中的pojo对象存在三种状态:

    1)  瞬时态:该对象在数据库中没有对应的数据。(刚new出来的数据)

    2)  持久态:数据库中存在该对象对应的数据,同时操作该对象的Session也存在。

    3)  游离态:数据库中包含该对象对应的数据,但操作此对象的Session已经不存在或被关闭了。

    三种状态之间的转换

    瞬时 -->持久:save(),saveOrUpdate()

    持久 -->瞬时:delete()

    持久 -->游离:close()

    游离 --> 持久:update(),saveOrUpdate()


    针对持久态对象,Hibernate还存在以下两个特点:

    1)  持久态对象,在同一Session中只存在同一个。

    a)         如果连接不关闭,多次查询同一条数据,只返回同一个对象,也就是只查询一次数据库。

    b)         此功能也被称为一级缓存,但实际开发中实用性很低。

    2)  修改持久态对象的属性,可以自动同步到数据库对应的数据中。

    a)         当修改了一个持久态对象的属性,而且提交了事务,则数据库自动调用更新操作,也一起修改。

    b)        (用处) 当登陆后,要求将当前系统时间,作为最后登陆时间保存到数据库中时,可以使用。

    三、Struts2 + Hibernate实现用户登陆功能

    3.1先建立项目,根据需要加入框架支持

    加入Hibernate:上一博客中详细介绍过,略

    加入Struts2:右击项目名,在MyEclipse中找到Add Struts Capabilities;

    点击next,只需加入它的核心Core Jar包就可以了;

    点击Finish,即加好了struts的核心jar包;

    3.2建立一张用户表

    [sql] view plain copy
    1. CREATE TABLE T_User (  
    2.        userid         varchar2(40)        primary key ,   
    3.        real_name      varchar2(20)        not null,  
    4.        password       varchar2(32)        not null,  
    5.        regist_date    date                default sysdate,  
    6.        last_login_date         date                             
    7. );  
    8.   
    9. INSERT INTO t_USER (userid,real_name,password)   
    10. VALUES ('zhangsan','张三','123');  
    11.   
    12. commit;  

    根据表,在DB Browser下生成映射,主键使用assigned方式生成

    3.3生成映射后,根据需要,完成DAO的方法和它的实现

    DAO方法:

    public boolean isLogin(TUser user) throws Exception;

    DAOImpl实现:

    [java] view plain copy
    1. public class TUserDAOImpl implements ITUserDAO {  
    2.     public boolean isLogin(TUser user) throws Exception {  
    3.         String hql = "FROM TUser AS u WHERE u.userid = ? AND u.password = ?";  
    4.         Query query = HibernateSessionFactory.getSession().createQuery(hql);  
    5.         query.setString(0, user.getUserid());  
    6.         query.setString(1, user.getPassword());  
    7.         List<User> allUser = query.list();  
    8.         if (allUser != null && allUser.size() > 0) {  
    9.             // 登陆成功  
    10.             // 取得查询的结果  
    11.             TUser result = (TUser) allUser.get(0);  
    12.             // 根据引用传递,将值设置到传入的user中  
    13.             user.setRealName(result.getRealName());  
    14.             user.setRegistDate(result.getRegistDate());  
    15.             user.setLastLoginDate(result.getLastLoginDate());  
    16.             return true;  
    17.         }  
    18.         return false;  
    19.     }  
    20. }  

    再实现Service以及工厂的代码。

    工厂类:

    public class DAOFactory{

    public static ITUserDAO getITUserDAOInstance(){

    return new TUserDAOImpl();

    }

    }

    3.4后台代码实现后,开始编写前台Struts操作代码。

    导入Struts2标签库,完成表单

    [java] view plain copy
    1. <%@ taglib uri="/struts-tags" prefix="s"%>  

    表单可以使用普通标签,也可以使用Struts2标签

    [java] view plain copy
    1. <span style="white-space:pre">      </span><center>  
    2.             <form action="tuser!login.action" method="post">  
    3.                 用户名:<input type="text" name="tuser.userid"/> <br/>  
    4.                 密码:<input type="password" name="tuser.password"/> <br/>  
    5.                 <input type="submit" value="提交" />   
    6.             </form>  
    7.         //下面的为struts标签  
    8.             <s:form action="tuser!login" namespace="/" method="post" theme="simple">  
    9.                 用户名:<s:textfield name="tuser.userid"></s:textfield> <br/>  
    10.                 密码:<s:password name="tuser.password"></s:password> <br/>  
    11.                 <s:submit value="提交"></s:submit>  
    12.             </s:form>  
    13.         </center>  

    编写Action类,完成验证的操作。

    [java] view plain copy
    1. public class TUserAction extends ActionSupport {  
    2.     private TUser tuser;  
    3.     public TUser getTuser() {  
    4.         return tuser;  
    5.     }  
    6.     public void setTuser(TUser tuser) {  
    7.         this.tuser = tuser;  
    8.     }  
    9.   
    10.     public String login() throws Exception {  
    11.         boolean flag = ServiceFactory.getITUserServiceInstance().login(tuser);  
    12.   
    13.         // 根据结果,决定跳转的位置  
    14.         if (flag) {  
    15.             // 将用户保存到session属性范围中  
    16.             ServletActionContext.getRequest().getSession().setAttribute("user",  
    17.                     tuser);  
    18.             return "suc";  
    19.         }  
    20.         // 添加错误信息,页面使用标签显示  
    21.         super.addActionError("用户名或密码错误,请重新输入!");  
    22.         return "input";  
    23.     }  
    24. }  

    配置这个Action,在struts.xml中完成。

    [java] view plain copy
    1. <struts>  
    2.     <package name="root" namespace="/" extends="struts-default">  
    3.         <action name="tuser" class="org.liky.login.action.TUserAction">  
    4.             <result name="suc">/pages/suc.jsp</result>  
    5.             <result name="input">/index.jsp</result>  
    6.         </action>  
    7.     </package>  
    8. </struts>      

    完成suc.jsp中显示用户信息的功能

    [java] view plain copy
    1. <span style="white-space:pre">      </span><center>  
    2.             用户登陆成功,当前登陆用户为: ${user.userid}   
    3.         </center>  

    在index.jsp中提示错误信息

    [java] view plain copy
    1. <span style="white-space:pre">      </span><font color="red">  
    2.             <s:actionerror/>  
    3.         </font>  

    测试项目,会提示以下错误信息。

    java.lang.NoSuchMethodError:antlr.collections.AST.getLine()

    这种错误是由于项目中加入了多个版本的支持jar包,各个版本之间有相同的类,但方法不同,造成冲突。

    这里的冲突jar包是Struts2加入的2.7.2.jar造成的,需要将该包删除,该包是MyEclipse工具提供的,因此需要通过MyEclip-se的操作来删除,无法直接删除。

    windows-->preference-->MyEclipse-->project capabilities-->Struts2中找到MyEclipse提供的antlr-2.7.2jar并删除。(这个jar包是MyEclipse自动加入的)

    删除后,必须重新发布项目,并重新启动服务器才可以。

    注:MyEclipse8.6就这两个冲突;7.5是冲突两个,少了三个;5.5是冲突一个,缺5个;

    最好的做法备份项目Tomcat下的lib中的jar包,包含struts和Hibernate的所有jar包。


  • 相关阅读:
    JAVA入门到精通-第22/23讲-容器、集合类
    JAVA入门到精通-第24讲-容器、集合类
    JAVA入门到精通-第20/21讲-二进制.位运算.位移运算
    JAVA入门到精通-第19讲-多维数组
    JAVA入门到精通-第18讲-排序查找
    JAVA入门到精通-第16讲-数组
    spring demo
    springmvc启动加载指定方法
    Java 日志
    web前端框架
  • 原文地址:https://www.cnblogs.com/hanjun0612/p/9779770.html
Copyright © 2011-2022 走看看