Hibernate ORM框架——综合

换一个连接数据mySql数据库的项目:HibernateStudy_cascade_inverse_query
**********1.支持sql server需要的设置*******************************************************
    a):驱动jar的处理-->导入sqljdbc42.jar连接数据库驱动
    b):修改hibernate.cfg.xml中配置相关的连接,方言
        <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
        <property name="connection.url">jdbc:sqlserver://localhost:1433;databaseName=demo</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>
        <property name="dialect">org.hibernate.dialect.SQLServer2008Dialect</property>
    c):开启TCP/IP的支持-->计算机管理,服务和应用程序,SQL Server配置管理器,SQL Native Cloient 10.0配置,客户端协议 
    d):启动sql server的服务
    
**********2.关联数据的处理****************************************************************
关联数据的插入,更新(修改),删除的顺序
    假定A是主表,B是子表
    create table A
    (
        aid varchar2(255 char) not null,
        primary key(aid)
    )
    create table B
    (
        bid varchar2(255 char) not null,
        primary key(bid),
        raid foreign key(aid) references A   //外键
    )

在MySQL数据库层面***************************************
    a)insert(添加操作) :
        先主表,后从(子)表
    b)update(更新)(我们一般是不更新表的主键)
        在数据库层面来看,如果不考虑更新主键,顺序是无关紧要的。
    c)delete(删除)
        先删从表(子表)的,然后再删主表


在hibernate代码层面*************************************
关联数据如果MySQL的代码和自己预想中的有出入,如何处理,需考虑的点。
    1.考虑调用session对象的save,update,delete的顺序问题
    2.考虑在代码层面有没有设置关系,外键是否允许为null
    3.考虑对象此时的状态
    帮助判断工具:sql server的监听器


**********3.cascade(级联)*************************************************************

 
**********4.inverse(确定关系维护方)******************************************************
关系维护,本质就是谁负责处理外键列的值。

inserse 一般是出现的映射文件的set元素里面

因为出现在set里面,也就是出现主表的映射文件中

如果把inserse设置为true,就表示由对方,也就是
子表来维护关系(就不会继续进行修改操作,[而此时查表时的外键值也为空]),主的一方不管。
-->在添加子表的时候,相关联的主表就跟着添加了

一般默认inserse的值为false,即为自己就是维护关系方,会进行修改(更新)操作

所以一般来说永远交给子表来维护关系,是比较合理的(比如:一个应届生,他并不属于任何部门,
那么在这个应届生中存在两张表,一张是个人的信息表,一张是部门表。在个人信息表中的所属部门可以为空,
等到该应届生,正式成为某某部门的时候,才不为空。也同时说明,外键一般时可以为空的)


**********5.关联数据的查询形式(检索策略)****************************************************
关联数据的加载,有3种情况
1.延迟(lazy)也叫作懒加载:
    当只在查找班级数据后,马上调用session.close();那么久默认为延迟(lazy)加载。即后面还没有查找完的语句就不查找了
    默认:lazy="true"
    
2.勤加载(eager)
    当只在查找班级数据后,马上调用session.close();而后面还没有查找完的语句就系统仍然自动查找,称为勤加载(eager)
    lazy="false"如在学生这边加,在查询学生信息的同时也查询班级信息是正常的
    
3.外键加载(显式加载):
    outer-join="true":查询的SQL语句中只用左外连接显示出一条查询结果
    避免普通查询,两张表,则需要发送两条select语句。

 

补充:3.级联cascade

(1)class类映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping package="shuang.m2oo2m">
    <class name="ClassInfo" table="CLASSINFO">
        <id name="cid" column="cid">
            <generator class="assigned"></generator>
        </id>
        <property name="name"></property>
        
        <set name="persons" cascade="all">
            <key column="rci"></key>
            <one-to-many class="Person"/>
        </set>
    </class>
</hibernate-mapping>

(2.1)Main测试,级联添加

private static void cascadeInsert() {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session s = sf.openSession();
        Transaction tx = s.beginTransaction();
        
        ClassInfo ci = new ClassInfo();
        ci.setCid("c1111");
        ci.setName("banji1");
        
        Set<Person> set = new HashSet<Person>();
        
        Person p = new Person();
        p.setPid("p111");
        p.setName("ren1");
        //p.setCi(ci);可以不需要,
        set.add(p);
        
        ci.setPersons(set);//此处已经说明了它俩关联了
        
        s.save(ci);
        //只把ci的数据持久化(save),不save人。并且在ClassInfo_m2oo2m.xml里写cascade="all"
        //班级和人的数据均正常添加
        
        tx.commit();
        s.close();
        sf.close();
        
        
        //运行结果为:先查询这个班级有没有人,然后再添加班级,添加人
        /*create table CLASSINFO (
           cid varchar(255) not null,
            name varchar(255),
            primary key (cid)
        )
        
        create table persons (
           pid varchar(255) not null,
            name varchar(255),
            rci varchar(255),
            primary key (pid)
        )
        
        alter table persons 
           add constraint FK7q2p61lu2253rtputmlhokd1e 
           foreign key (rci) 
           references CLASSINFO
           
           
           
        -----------------重点-----------------------   
        select
            person_.pid,
            person_.name as name2_1_,
            person_.rci as rci3_1_ 
        from
            persons person_ 
        where
            person_.pid=?
        insert 
        into
            CLASSINFO
            (name, cid) 
        values
            (?, ?)
        insert 
        into
            persons
            (name, rci, pid) 
        values
            (?, ?, ?)
        update
            persons 
        set
            rci=? 
        where
            pid=?*/        

        
        
        
        //反之,如果不使用级联(在ClassInfo_m2oo2m.xml里写cascade="all")
        //则数据在直接添加时并不会去找是存在临时的人的数据,
        //但是又因为人和班级有关联,会报错
        /*Hibernate: 
            insert 
            into
                CLASSINFO
                (name, cid) 
            values
                (?, ?)
        Hibernate: 
            update
                persons 
            set
                rci=? 
            where
                pid=?*/
    }

 

(2.2)Main测试,级联删除

private static void cascadeDelete() {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session s = sf.openSession();
        Transaction tx = s.beginTransaction();
        
        ClassInfo ci = s.get(ClassInfo.class, "c1111");
        s.delete(ci);
        /*不使用级联的普通删除结果(不在ClassInfo_m2oo2m.xml里写cascade="all"):
         * 先根据id查到所删除的数据,然后再修改所关联的人的班级信息为null。
         * 最后删除该行
         * Hibernate: 
            select
                classinfo0_.cid as cid1_0_0_,
                classinfo0_.name as name2_0_0_ 
            from
                CLASSINFO classinfo0_ 
            where
                classinfo0_.cid=?
            Hibernate: 
                update
                    persons 
                set
                    rci=null 
                where
                    rci=?
            Hibernate: 
                delete 
                from
                    CLASSINFO 
                where
                    cid=?*/
        
        
        /*使用级联的普通删除结果(在ClassInfo_m2oo2m.xml里写cascade="all"):
         * 班级和所关联的人的数据都一同删掉
         * Hibernate: 
                select
                    classinfo0_.cid as cid1_0_0_,
                    classinfo0_.name as name2_0_0_ 
                from
                    CLASSINFO classinfo0_ 
                where
                    classinfo0_.cid=?
            Hibernate: 
                select
                    persons0_.rci as rci3_1_0_,
                    persons0_.pid as pid1_1_0_,
                    persons0_.pid as pid1_1_1_,
                    persons0_.name as name2_1_1_,
                    persons0_.rci as rci3_1_1_ 
                from
                    persons persons0_ 
                where
                    persons0_.rci=?
            Hibernate: 
                update
                    persons 
                set
                    rci=null 
                where
                    rci=?
            Hibernate: 
                delete 
                from
                    persons 
                where
                    pid=?
            Hibernate: 
                delete 
                from
                    persons 
                where
                    pid=?
            Hibernate: 
                delete 
                from
                    CLASSINFO 
                where
                    cid=?
         * */
        
        tx.commit();
        s.close();
        sf.close();
        
        
    }

补充:4.inverse(确定关系维护方)
Main测试
private static void testInverse() {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session s = sf.openSession();
        Transaction tx = s.beginTransaction();
        
        ClassInfo ci = new ClassInfo();
        ci.setCid("c1111");
        ci.setName("banji1");
        
        Set<Person> set = new HashSet<Person>();
        
        Person p = new Person();
        p.setPid("p111");
        p.setName("ren1");
        p.setCi(ci);
        set.add(p);
        
        ci.setPersons(set);
        p.setCi(ci);
        
        s.save(ci);
        s.save(p);
        
        tx.commit();
        s.close();
        sf.close();
    }


补充:5.关联数据的查询形式(检索策略)
(5.1)班级的映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping package="shuang.m2oo2m">
    <class name="ClassInfo" table="CLASSINFO">
        <id name="cid" column="cid">
            <generator class="assigned"></generator>
        </id>
        <property name="name"></property>
        
        <set name="persons" lazy="true">
            <key column="rci"></key>
            <one-to-many class="Person"/>
        </set>
    </class>
</hibernate-mapping>

(5.2)Main测试代码(是否为勤加载或者懒加载)
private static void LazyFlag() {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session s = sf.openSession();
        Transaction tx = s.beginTransaction();
        
        ClassInfo ci = s.get(ClassInfo.class, "c1111");
        System.out.println(ci.getName());
        
        tx.commit();
        s.close();
        
        Set<Person> persons = ci.getPersons();
        for(Person p : persons){
            System.out.println(p.getName());
        }
        
        s.close();
        sf.close();

        /*不写,默认懒加载==班级的映射文件中,默认:lazy="true"
         * 当只在查找班级数据后,马上调用session.close();那么久默认为延迟(lazy)加载。即后面还没有查找完的语句就不查找了
         * Hibernate: 
                select
                    classinfo0_.cid as cid1_0_0_,
                    classinfo0_.name as name2_0_0_ 
                from
                    CLASSINFO classinfo0_ 
                where
                    classinfo0_.cid=?
            banji1
         * */
        
        /*反之:如果班级的映射文件中,设置关键词lazy="false":即为勤加载
         * 当只在查找班级数据后,马上调用session.close();而后面还没有查找完的语句就系统仍然自动查找,称为勤加载(eager)
         * */
        
        //注意:一般班级中默认是懒加载,人中默认是勤加载,是正常的
    }

 

(5.3)外键加载(显式加载)

班级映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping package="shuang.m2oo2m">
    <class name="ClassInfo" table="CLASSINFO">
        <id name="cid" column="cid">
            <generator class="assigned"></generator>
        </id>
        <property name="name"></property>
        
        <set name="persons" outer-join="true">
            <key column="rci"></key>
            <one-to-many class="Person"/>
        </set>
    </class>
</hibernate-mapping>

Main测试:

private static void showLoad() {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session s = sf.openSession();
        Transaction tx = s.beginTransaction();
        
        ClassInfo ci = s.get(ClassInfo.class, "c1111");
        System.out.println(ci.getName());
        
        tx.commit();
        s.close();
        sf.close();
        
        /*在班级映射文件中使用关键词outer-join="true"的查询结果:
         * 会在查询班级的同时,把相关联表的一起查询
         * Hibernate: 
                select
                    classinfo0_.cid as cid1_0_0_,
                    classinfo0_.name as name2_0_0_,
                    persons1_.rci as rci3_1_1_,
                    persons1_.pid as pid1_1_1_,
                    persons1_.pid as pid1_1_2_,
                    persons1_.name as name2_1_2_,
                    persons1_.rci as rci3_1_2_ 
                from
                    CLASSINFO classinfo0_ 
                left outer join
                    persons persons1_ 
                        on classinfo0_.cid=persons1_.rci 
                where
                    classinfo0_.cid=?
            banji1
         * */
        
        
        
        /*不使用的结果:只会查询他自己的
         * Hibernate: 
                select
                    classinfo0_.cid as cid1_0_0_,
                    classinfo0_.name as name2_0_0_ 
                from
                    CLASSINFO classinfo0_ 
                where
                    classinfo0_.cid=?
            banji1
         * 
         * */
        
        //好处:避免普通查询,两张表,则需要发送两条select语句。
    }

 


/*以上个人整理笔记,如果有误或者有不懂的地方,欢迎评论与指出*/

posted @ 2017-08-17 22:13  梁宝谊  阅读(831)  评论(0编辑  收藏  举报