Session操作过程中的pojo对象存在三种状态:
1) 瞬时态:该对象在数据库中没有对应的数据
2) 持久态:数据库中存在该对象对应的数据,同时操作该对象的Session也存在。
3) 游离态:数据库中包含该对象对应的数据,但操作此对象的Session已经不存在或被关闭了。
三种状态之间的转换:
瞬时 à 持久:save(),saveOrUpdate()
持久 à 瞬时:delete()
持久 à 游离:close()
游离 à 持久:update(),saveOrUpdate()
针对持久态对象,Hibernate还存在以下两个特点:
1) 持久态对象,在同一Session中只存在同一个。
a) 如果连接不关闭,多次查询同一条数据,只返回同一个对象,也就是只查询一次数据库。
b) 此功能也被称为一级缓存,但实际开发中实用性很低。
2) 修改持久态对象的属性,可以自动同步到数据库对应的数据中。
a) 当修改了一个持久态对象的属性,而且提交了事务,则数据库自动调用更新操作,也一起修改。
b) 当登陆后,要求将当前系统时间,作为最后登陆时间保存到数据库中时,可以使用。
先建立项目,根据需要加入框架支持。
加入Hibernate:略
加入Struts2
支持加入后,先建立一张用户表。
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','èy','123'); commit;
根据表,生成映射。
主键使用assigned方式生成
生成映射后,根据需要,完成DAO的方法
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中 user.setRealName(result.getRealName()); user.setRegistDate(result.getRegistDate()); user.setLastLoginDate(result.getLastLoginDate()); return true; } return false; } }
再实现Service以及工厂的代码。
后台代码实现后,开始编写前台Struts操作代码。
导入Struts2标签库,完成表单
<%@ taglib uri="/struts-tags" prefix="s"%>
表单可以使用普通标签,也可以使用Struts2标签
<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> <br/> <hr/> <br/> <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) { // 将用户保存到session属性范围中 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中显示用户信息的功能
<center> 用户登陆成功,当前登陆用户为: ${user.userid} </center>
在index.jsp中提示错误信息
<font color="red"> <s:actionerror/> </font> <br/>
测试项目,会提示以下错误信息。
java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I
java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I
这种错误是由于项目中加入了多个版本的支持jar包,各个版本之间有相同的类,但方法不同,造成冲突。
这里的冲突jar包是Struts2加入的2.7.2.jar造成的,需要将该包删除,该包是MyEclipse工具提供的,因此需要通过MyEclip-se的操作来删除,无法直接删除。
删除后,必须重新发布项目,并重新启动服务器才可以。
注意这里的包冲突问题。
实际开发中,只有当出现多对多关系时,才有可能出现复合主键的表,例如:学生选课功能,需要设计,学生表,课程表和选课表,其中选课表应该只有两个字段(学生id,课程id),而且应该是复合主键。
但实际开发中,Hibernate推出了多对多关系映射的功能,该功能专门针对多对多关系中间表进行处理,因此复合主键映射在开发中没用了。
这里建立一个中间表,来简单看一下复合主键映射的实现方式,要求了解HQL中类关系查询的形式。
先建立一张选课表
CREATE TABLE course ( cid number(8) primary key , title varchar2(50) not null ); INSERT INTO course VALUES (1,'Javaù±ó・¨'); INSERT INTO course VALUES (2,'JavaWeba・¢'); INSERT INTO course VALUES (3,'Javaóòμòü'); INSERT INTO course VALUES (4,'Androidó|óa・¢'); INSERT INTO t_user (userid,real_name,password) VALUES ('lisi','à','abc'); commit;
create table user_course ( userid varchar2(40) , courseid number(8) , primary key (userid,courseid) ); INSERT INTO user_course VALUES ('zhangsan',2); INSERT INTO user_course VALUES ('zhangsan',4); INSERT INTO user_course VALUES ('lisi',1); INSERT INTO user_course VALUES ('lisi',3); commit;
准备生成映射
主键生成方式可以不选,因为Hibernate认为,只要是复合主键,不可能是自增长的。
生成后会发现,多出了一个Id类,该类出现的原因是因为主键的作用。
主键的作用是唯一标识,保证数据不重复,普通的单字段主键,在映射时,都是映射成普通的数据类型。
但复合主键要比较重复,必须比较多个键都相同,才能算重复。
因此,Hibernate自动生成了id类,并在里面包含了userid和courseid,同时通过覆写equals和hashCode方法,来完成是否重复的比较,这样就可以自动针对id判断是否重复了。
映射文件中也体现了这个关系。
<hibernate-mapping> <class name="org.liky.primary.pojo.UserCourse" table="USER_COURSE" schema="SUNXUN"> <composite-id name="id" class="org.liky.primary.pojo.UserCourseId"> <key-property name="userid" type="java.lang.String"> <column name="USERID" length="40" /> </key-property> <key-property name="courseid" type="java.lang.Integer"> <column name="COURSEID" precision="8" scale="0" /> </key-property> </composite-id> </class> </hibernate-mapping>
编写一个操作,来看类之间关系的查询。
实现根据某个学生id查询该学生选择的课程信息。
public class Test { public static void main(String[] args) { // UserCourse uc = new UserCourse(new UserCourseId("zhangsan", 1)); // UserCourse uc2 = new UserCourse(new UserCourseId("zhangsan", 1)); // // System.out.println(uc.getId().equals(uc2.getId())); String hql = "FROM UserCourse AS uc WHERE uc.id.userid = ?"; Query query = HibernateSessionFactory.getSession().createQuery(hql); query.setString(0, "zhangsan"); System.out.println(query.list()); } }
这里一定要注意,按照类的关系,查找数据,通过UserCourse找到里面的id,再找到里面的userid,作为条件,不要管数据库里表是怎样的设计和关系。
1、Struts2 + Hibernate完成登陆
2、背:三种查询,get和load的区别,Session的三种状态以及转换,持久态对象的特性。
3、掌握类之间关系的HQL编写方法