Hibernate查询技术(3)

3.2HibernateSession操作的三种状态(背)

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

1) 瞬时态:该对象在数据库中没有对应的数据

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

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


三种状态之间的转换:

瞬时 à 持久:save()saveOrUpdate()

持久 à 瞬时:delete()

持久 à 游离:close()

游离 à 持久:update()saveOrUpdate()



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

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

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

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

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

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

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


3.3Struts2 + Hibernate实现用户登陆功能(重点)

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

加入Hibernate:略

加入Struts2

wKiom1MVWKXT8_bjAAGufZ4HC7M605.jpg


wKiom1MVWL6DWl2TAAL_4r9nF-Y804.jpg


支持加入后,先建立一张用户表。

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;

根据表,生成映射。

wKioL1MVWNaAQ8C-AAJpg-6iV7c910.jpg


主键使用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的操作来删除,无法直接删除。

wKiom1MVWemToYp_AAtxlyko0rk691.jpg

wKioL1MVWcPg0f85AAXn0wKvQ60214.jpg

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

注意这里的包冲突问题。

3.4Hibernate中的复合主键映射(了解)

实际开发中,只有当出现多对多关系时,才有可能出现复合主键的表,例如:学生选课功能,需要设计,学生表,课程表和选课表,其中选课表应该只有两个字段(学生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;

准备生成映射

wKioL1MVWi7D0E9QAAJjviW77Tc634.jpg


主键生成方式可以不选,因为Hibernate认为,只要是复合主键,不可能是自增长的。

生成后会发现,多出了一个Id类,该类出现的原因是因为主键的作用。

主键的作用是唯一标识,保证数据不重复,普通的单字段主键,在映射时,都是映射成普通的数据类型。

但复合主键要比较重复,必须比较多个键都相同,才能算重复。

因此,Hibernate自动生成了id类,并在里面包含了useridcourseid,同时通过覆写equalshashCode方法,来完成是否重复的比较,这样就可以自动针对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,作为条件,不要管数据库里表是怎样的设计和关系。

4、总结

1、Struts2 + Hibernate完成登陆

2、背:三种查询,getload的区别,Session的三种状态以及转换,持久态对象的特性。

3、掌握类之间关系的HQL编写方法


你可能感兴趣的:(数据库,技术,update,close,而且)