Hibernate中提供了三种查询方式:
1)Session的查询:按主键查询查询,方法为get或load
2)Query的查询:使用HQL语句或SQL语句完成查询
3)Criteria的查询:通过方法和类中属性的关系,来设置查询条件,完成查询。
Session中get和load方法的区别?
1) 如果没有查询到数据,get会返回null,而load则直接提示错误。
2) 使用load查询时,可能会出现以下错误,因为load方式使用的是懒汉式加载方法。执行load方法时,不立刻查询数据库。当用到查询出的对象的属性时,才加载数据。
-
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
解决这个异常的方法:
1) 不关连接;2)不用load,就使用get就可以了
1.1、Query查询(重点)
1.1.1HQL语句不只支持查询功能,还支持修改以及删除功能
-
public void doRemove(Integer id) throws Exception {
-
-
-
String hql = "DELETE FROM News AS n WHERE n.id = ?" ;
-
Query query = HibernateSessionFactory.getSession().createQuery(hql);
-
query.setInteger(0, id);
-
query.executeUpdate();
-
}
注:使用HQL的删除可以不需要先查询,直接删除,支持一次删除多条数据
开发中的选择:1)当删除一条数据时,直接使用session.delete()就可以,因为简单,hibernate不在乎那点查询的性能;
2)批量删除时,使用Hql形式,这是可以提高性能的方法,因为它中间省去了查询的步骤。
1.1.2HQL语句修改功能
-
public void doUpdate(News vo) throws Exception {
-
-
String hql = "UPDATE News AS n SET n.title = ?,n.content = ? WHERE n.id = ?" ;
-
Query query = HibernateSessionFactory.getSession().createQuery(hql);
-
query.setString(0, vo.getTitle());
-
-
query.executeUpdate();
-
}
开发中的选择:1)如果是直接的修改功能,肯定选择session.update()方法;
2)如果是只修改某一字段,使用HQL方式。
注:HQL语句不支持添加,但是Query支持添加。
1.1.3针对HQL的查询功能,也支持写SELECT,可以通过编写SELECT,来只查询对象中某一个或某几个属性。
但是对于多种字段不同类型的查询返回的,Hibernate中只能是数组。
例如:
-
public List testHQL() throws Exception {
-
String hql = "SELECT n.id,n.title FROM News AS n";
-
Query query = HibernateSessionFactory.getSession().createQuery(hql);
-
return query.list();
-
}
经过测试,发现当只查询一个字段时,直接返回该类型的List集合。
但查询两个以上的字段时,返回的是List<Object[]>,每一条查询出的数据,使用Object[]来表示,这就很不方便。
-
public void testHQL() throws Exception {
-
List all = ServiceFactory.getINewsServiceInstance().testHQL();
-
Object[] value1 = (Object[]) all.get(0);
-
System.out.println(value1[1]);
-
}
这样使用起来很麻烦,因此在Hibernate3.2以上的版本中,提供了一个自动转换类,可以将查询出的Object[],自动转换为pojo 对象。
-
public List testHQL() throws Exception {
-
String hql = "SELECT n.id AS id,n.title AS title FROM News AS n";
-
Query query = HibernateSessionFactory.getSession().createQuery(hql);
-
<span style="color:#cc0000;">query
-
.setResultTransformer(new AliasToBeanResultTransformer(
-
News.class));</span>
-
return query.list();
-
}
注:一般开发中不会使用这种方法,只有当表中的字段过多,但查询只需要其中的几个字段时,才会用到这种方法。
1.1.4Hibernate还可以将语句写到配置文件中
-
<query name="findAll">
-
FROM News AS n WHERE n.title LIKE ?
-
</query>
通过程序读取配置文件,取得这段HQL,并生成Query对象,完成查询。
-
Query query = HibernateSessionFactory.getSession().getNamedQuery(
-
"findAll");
-
query.setString(0, "%测试%");
-
return query.list();
这种方式在Mybatis中普遍使用,但是在Hibernate中一班很少这样做。
1.2、Criteria查询(了解)
Criteria也是Hibernate提供的一个查询对象,支持按对象的方式来完成查询。例如:
查询全部功能:
-
public List<News> testCriteria() throws Exception {
-
-
Criteria c = HibernateSessionFactory.getSession().createCriteria(
-
News.class);
-
return c.list();
-
}
如果想加入查询条件,需要使用Restrictions的各种方法来完成条件的拼写。
-
public List<News> testCriteria() throws Exception {
-
-
Criteria c = HibernateSessionFactory.getSession().createCriteria(
-
News.class);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
c
-
.add(Restrictions.or(Restrictions.eq("id", 23), Restrictions
-
.and(Restrictions.ne("id", 26), Restrictions.like(
-
"title", "%测试%"))));
-
return c.list();
-
}
如果想加入ORDER BY排序条件,需要使用Order对象。
-
c.addOrder(Order.desc("id"));
如果想加入统计函数和分组函数,则需要用到Projection这个类
-
<span style="white-space:pre"> </span>ProjectionList pro = Projections.projectionList();
-
-
pro.add(Projections.rowCount());
-
-
pro.add(Projections.groupProperty("title"));
-
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建立一张用户表
-
CREATE TABLE T_User (
-
userid varchar2(40) primary key ,
-
real_name varchar2(20) not null,
-
password varchar2(32) not null,
-
regist_date date default sysdate,
-
last_login_date date
-
);
-
-
INSERT INTO t_USER (userid,real_name,password)
-
VALUES ('zhangsan','张三','123');
-
-
commit;
根据表,在DB Browser下生成映射,主键使用assigned方式生成
3.3生成映射后,根据需要,完成DAO的方法和它的实现
DAO方法:
public boolean isLogin(TUser user) throws Exception;
DAOImpl实现:
-
public class TUserDAOImpl implements ITUserDAO {
-
public boolean isLogin(TUser user) throws Exception {
-
String hql = "FROM TUser AS u WHERE u.userid = ? AND u.password = ?";
-
Query query = HibernateSessionFactory.getSession().createQuery(hql);
-
query.setString(0, user.getUserid());
-
query.setString(1, user.getPassword());
-
List<User> allUser = query.list();
-
if (allUser != null && allUser.size() > 0) {
-
-
-
TUser result = (TUser) allUser.get(0);
-
-
user.setRealName(result.getRealName());
-
user.setRegistDate(result.getRegistDate());
-
user.setLastLoginDate(result.getLastLoginDate());
-
return true;
-
}
-
return false;
-
}
-
}
再实现Service以及工厂的代码。
工厂类:
public class DAOFactory{
public static ITUserDAO getITUserDAOInstance(){
return new TUserDAOImpl();
}
}
3.4后台代码实现后,开始编写前台Struts操作代码。
导入Struts2标签库,完成表单
-
<%@ taglib uri="/struts-tags" prefix="s"%>
表单可以使用普通标签,也可以使用Struts2标签
-
<span style="white-space:pre"> </span><center>
-
<form action="tuser!login.action" method="post">
-
用户名:<input type="text" name="tuser.userid"/> <br/>
-
密码:<input type="password" name="tuser.password"/> <br/>
-
<input type="submit" value="提交" />
-
</form>
-
-
<s:form action="tuser!login" namespace="/" method="post" theme="simple">
-
用户名:<s:textfield name="tuser.userid"></s:textfield> <br/>
-
密码:<s:password name="tuser.password"></s:password> <br/>
-
<s:submit value="提交"></s:submit>
-
</s:form>
-
</center>
编写Action类,完成验证的操作。
-
public class TUserAction extends ActionSupport {
-
private TUser tuser;
-
public TUser getTuser() {
-
return tuser;
-
}
-
public void setTuser(TUser tuser) {
-
this.tuser = tuser;
-
}
-
-
public String login() throws Exception {
-
boolean flag = ServiceFactory.getITUserServiceInstance().login(tuser);
-
-
-
if (flag) {
-
-
ServletActionContext.getRequest().getSession().setAttribute("user",
-
tuser);
-
return "suc";
-
}
-
-
super.addActionError("用户名或密码错误,请重新输入!");
-
return "input";
-
}
-
}
配置这个Action,在struts.xml中完成。
-
<struts>
-
<package name="root" namespace="/" extends="struts-default">
-
<action name="tuser" class="org.liky.login.action.TUserAction">
-
<result name="suc">/pages/suc.jsp</result>
-
<result name="input">/index.jsp</result>
-
</action>
-
</package>
-
</struts>
完成suc.jsp中显示用户信息的功能
-
<span style="white-space:pre"> </span><center>
-
用户登陆成功,当前登陆用户为: ${user.userid}
-
</center>
在index.jsp中提示错误信息
-
<span style="white-space:pre"> </span><font color="red">
-
<s:actionerror/>
-
</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包。