微信扫一扫

028-83195727 , 15928970361
business@forhy.com

JavaEE学习笔记之SSH—Hibernate(3)

hibernate2016-07-05

封装HibernateSessionFactory

因为Session是线程不安全的,为了保证当前线程只有一个session对象,并且当前线程中的Session不能让其他线程来访问,需要将获取Session的方法进行封装,为了保证Session的线程安全性,需要将Session放到ThreadLocal中。
ThreadLocal为线程本地变量

封装过程:(非常重要)

public class HibernateSessionFactory {
    private static String configFile ="/hibernate.cfg.xml";
    //声明一个线程本地变量,用来存放当前中的Session,保证不让其他线程访问到
    private static ThreadLocal<Session> threadLocal = new ThreadLocal<>();
    private static Configuration config = new Configuration();
    private static SessionFactory sessionFactory;
    static {
        //读取配置文件
        config.configure(configFile);
        //创建sessionFactory
        sessionFactory = config.buildSessionFactory();
    }
    //获取session
    public static Session getSession() {
        /*当获取Session的时候先到当前线程的本地变量中寻找,如果有直接返回,
         *如果没有或者当前线程已经关闭需要重新开启一个Session
         *,返回,并且放到当前线程中
         */
        Session session = threadLocal.get();
        if(session == null || !session.isOpen()){
            session =(sessionFactory != null) ? sessionFactory.openSession() : null;
            threadLocal.set(session);
        }
        return session;
    }
    //关闭session
    public static void close(){
        /*
         *关闭的时候先到当前线程中的本地变量中拿到session,如果可以取到,直接关闭
         *最后将本地变量清空
         */
        Session session = threadLocal.get();
        threadLocal.set(null);
        if(session!=null){
            session.close();
        }
    }
}

下面来看看学习Hibernate框架比较难的一部分——关联关系映射。

首先关联关系分为三种:

1.一对一

2.一对多

3.多对多

映射一对一关联:
有两种方式:

a.通过主键来映射(就是让从表的主键和主表的主键一样就可以)

b.通过外键

映射一对多关联:

映射多对多关联:

两种方式:

a.双方配置<many-to-many />,借助于桥表

b.生成中间表,拆分成两个<one-to-many />

a.

b.

当然还有一种情况就是继承关系的映射 –>有三种方式:

1.每个类一张表

2.一个类域一张表

3.每个子类一张表

第一种方式
.

第二种方式

第三种方式

实例:

Animal.java

public class Animal {

    private String id;
    private String name;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return ",id=" + id + ", name=" + name + "]";
    }
}

Dog.java

public class Dog extends Animal{

    private String color;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Dog [color=" + color + super.toString() +"]";
    }

}

Bird.java

public class Bird extends Animal{

    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
    @Override
    public String toString() {
        return "Bird [type=" + type + super.toString() +"]";
    }
}

第一种方式的映射文件(inherit_per_class.hbm.xml)

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE hibernate-mapping PUBLIC   
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
<hibernate-mapping package="com.briup.day05.inherit">
    <class name="Animal" table="tbl_animal">
        <id name="id" column="id">
            <generator class="uuid.hex"/>
        </id>
        <property name="name"/>
        <!-- 以上是配置父类的基本属性,需要指定父类使用的表名-->
        <!-- 以上是配置子类的配置,需要指定子类使用的表名,使用joined-subclass来和父类关联,
        key值继承父类的,column指定子类在表中的主键;property为子类特有的属性-->
        <joined-subclass name="Dog" table="tbl_dog">
            <key column="d_id"/>
            <property name="color"/>
        </joined-subclass>      
        <joined-subclass name="Bird" table="tbl_bird">
            <key column="b_id"/>
            <property name="type"/>
        </joined-subclass>         
    </class>
</hibernate-mapping>

第二种方式的映射文件(inherit_one_class.hbm.xml)

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE hibernate-mapping PUBLIC   
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.briup.day05.inherit">
    <class name="Animal" table="tbl_allclass">
        <id name="id" column="id">
            <generator class="uuid.hex">
            </generator>
        </id>
        <!-- discriminator用来指定标识列 -->
        <discriminator column="a_value" />
        <property name="name" />
        <!-- discriminator-value用来指定标识列中应该填入的值, 用这个值来区分这条记录是属于哪个类的,property用来指明子类特有的属性 -->
        <subclass name="Dog" discriminator-value="dog">
            <property name="color" />
        </subclass>
        <subclass name="Bird" discriminator-value="bird">
            <property name="type" />
        </subclass>
    </class>
</hibernate-mapping>

第三种方式的映射文件

<?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="com.briup.day05.inherit">
    <class name="Animal" abstract="true">
        <id name="id" column="id">
            <generator class="uuid.hex"/>
        </id>
        <property name="name"/>
        <union-subclass name="Dog" table="tbl_dog">
            <property name="color"/>
        </union-subclass>
        <union-subclass name="Bird" table="tbl_bird">
            <property name="type"/>
        </union-subclass>
    </class>
</hibernate-mapping>

Hibernate配置文件(hibernate.cfg.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://127.0.0.1:3306/ssh</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property>

        <mapping resource="com/briup/day05/inherit/inherit_per_class.hbm.xml" />  -->

        <!-- <mapping resource="com/briup/day05/inherit/inherit_son_class.hbm.xml" /> -->

        <!--<mapping resource="com/briup/day05/inherit/inherit_one_class.hbm.xml" /> -->
    </session-factory>

</hibernate-configuration>

这些都配置好后,你就可以测试三种方式了,随便选择一个映射文件,测试类中代码不需要变即可测试。

测试类Test.java

public class Test {

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Transaction transaction = session.beginTransaction();

        Dog dog = new Dog();
        dog.setColor("金黄色");
        dog.setName("一休");

        Bird bird = new Bird();
        bird.setType("八哥");
        bird.setName("汪汪");
        session.save(bird);
        session.save(dog);

        transaction.commit();

        Transaction transaction2 = session.beginTransaction();
        String hql = "from Dog where name=?";
        Dog dog1 = (Dog) session.createQuery(hql)
            .setString(0, "一休")
            .uniqueResult();
        System.out.println(dog1);
        transaction2.commit();
    }
}

这里演示第一种方式的效果
结果: