Arce 发表于 2021-7-5 10:10:10

Hibernate 一对多双向映射及乐观锁使用

  Hibernate 一对多双向映射及乐观锁使用
  
  在“Hibernate关联关系映射实例速查”一文中,通过myeclipse5.5,快速做出了Hibernate各种映射的示例。时隔快一年了,但是还是有博友向我索要工程源码,很遗憾的是已经找不到了。但找到一了一个测试代码:对双向关联和乐观锁的测试。其实映射类型很多,搞清楚一对多,基本上所有的映射就搞明白了,一对一也是一对多的特例而已,多对多也可以转换为一对多和多对一,并且实际中很少用到多对多。
  还是老规矩,因为是测试,代码几乎全部是myeclipse生成的,我稍作了修改。并且应博友“阿飞”的留言,我做了详细的注释。
  例子两部分:
  1、一对多双向映射:模型是“班级-学生”模型。两个实体分别是Tclass和Student。
  2、乐观锁的是使用,版本分别使用递增整数和时间戳。两个实体分别是Foo和Bar。
  Tclass实体及其映射:
  public class Tclass implements java.io.Serializable {

    // Fields

    private Long cid;

    private String cname;

    private Set students = new HashSet(0);

    // Constructors
    // Property accessors
    .......

    public String toString() {
      return "Tclass{" +
                "cid=" + cid +
                ", cname='" + cname + '\'' +
                '}';
    }
}
  <hibernate-mapping>
    <class name="stu.one2many.pojo.Tclass" table="tclass">
      <id name="cid" type="java.lang.Long">
            <column name="cid"/>
            <generator class="native"/>
      </id>
      <property name="cname" type="java.lang.String">
            <column name="cname" length="24" not-null="true"/>
      </property>
      <!-- set元素属性说明:
         name="students" 设置表示多个学生的变量名;
         inverse="true" 关系控制反转,不掌握主控权,表示Tclass不控制与Student关联关系,而是将这种关联控制的权利转给Student。
         cascade="all" 表示级联操作,操作班级的时候,对班级关联的学生也做同样的操作。
         lazy="true" 查询班级的时候,延迟查询班级下的学生。
      -->
      <set name="students" inverse="true" cascade="all" lazy="true">
            <key>
                <!--
                  name="fk_cid" 指定关联的外键列;
                  not-null="true" 说明这个外间列不能为空,多余的。
                -->
                <column name="fk_cid" not-null="true"/>
            </key>
            <!-- 指定所关联的类 -->
            <one-to-many class="stu.one2many.pojo.Student"/>
      </set>
    </class>
</hibernate-mapping>
  Student实体及其映射
  public class Student implements java.io.Serializable {

    // Fields

    private Long sid;

    private Tclass tclass;

    private String sname;


    // Constructors
    // Property accessors
    .......

    public String toString() {
      return "Student{" +
                "sid=" + sid +
                ", sname='" + sname + '\'' +
                '}';
    }
}
  <hibernate-mapping>
    <class name="stu.one2many.pojo.Student" table="student">
      <id name="sid" type="java.lang.Long">
            <column name="sid" />
            <generator class="native" />
      </id>
      <!-- 表示多个Student关联一个Tclass -->
      <!--
            name="tclass" 关联的成员变量名;
            class="stu.one2many.pojo.Tclass" 表示所关联的类;
            fetch="select" 查询策略,有两个选项select和join,
          select表示通过外联接来进行查询,查询速度稍慢,但消耗资源少;
          join表示通过内连接来查询,速度快,但消耗资源多.
         -->
      <many-to-one name="tclass"
            class="stu.one2many.pojo.Tclass"
            fetch="select">
            <!-- 指定关联的外键列 -->
            <column name="fk_cid" not-null="true" />
      </many-to-one>
      <property name="sname" type="java.lang.String">
            <column name="sname" length="24" not-null="true" />
      </property>
    </class>
</hibernate-mapping>
  测试班级学生模型:
  public class Test {

    /**
   * @param args
   */
    public static void main(String[] args) {
      testSave();
//      testDeleteTclass();

    }

    public static void testSave() {
      Tclass c = new Tclass();
      c.setCname("某班级");
      Student s1 = new Student();
      Student s2 = new Student();
      s1.setSname("张三");
      s1.setTclass(c);
      s2.setSname("李四");
      s2.setTclass(c);
      c.getStudents().add(s1);
      c.getStudents().add(s2);

      Session session = HibernateSessionFactory.getSession();
      Transaction tx = session.beginTransaction();
      session.save(c);
      tx.commit();
      session.close();
    }

    public static void testUpdateClass() {
      System.out.println("----------------正在调用testUpdateClass()----------------");
      Session session = HibernateSessionFactory.getSession();
      Tclass c = (Tclass) session.load(Tclass.class, Long.valueOf(1L));
      System.out.println(c);
      c.setCname("班级更名");
      session.beginTransaction().commit();
    }

    public static void testUpdateStudent() {
      System.out.println("----------------正在调用testUpdateStudent()----------------");
      Session session = HibernateSessionFactory.getSession();
      Tclass c = (Tclass) session.load(Tclass.class, Long.valueOf(3L));
      Student s = (Student) session.load(Student.class, Long.valueOf(2L));
      s.setSname("学生改名换姓-王八");
      s.setTclass(c);
      System.out.println(c);
      System.out.println(s);
      session.beginTransaction().commit();
      System.out.println(s);
      System.out.println(s.getTclass());
    }

    public static void testDeleteStudent() {
      System.out.println("----------------正在调用testDelete()----------------");
      Session session = HibernateSessionFactory.getSession();
      Student s = (Student) session.load(Student.class, Long.valueOf(5L));
      System.out.println(s);
      System.out.println(s.getTclass());
      session.delete(s);
      session.beginTransaction().commit();
    }

    public static void testDeleteTclass() {
      System.out.println("----------------正在调用testDelete()----------------");
      Session session = HibernateSessionFactory.getSession();
      Tclass c = (Tclass) session.load(Tclass.class, Long.valueOf(3L));
      System.out.println(c);
      session.delete(c);
      session.beginTransaction().commit();
    }

    public static void testQueryClass() {
      System.out.println("----------------正在调用testQueryClass()----------------");
      Session session = HibernateSessionFactory.getSession();
      Tclass c = (Tclass) session.load(Tclass.class, new Long("1"));
      System.out.println(c);
      System.out.println(c.getStudents());

    }

    public static void testQueryStudent() {
      System.out.println("----------------正在调用testQueryStudent()----------------");
      Session session = HibernateSessionFactory.getSession();
      Student s = (Student) session.load(Student.class, new Long("1"));
      System.out.println(s);
      System.out.println(s.getTclass());
    }
}
  下面是乐观锁的使用:
  1、基于整数的版本控制
  Foo实体和映射文件
  public class Foo implements java.io.Serializable {

    // Fields

    private Long pid;

    private Integer version;

    private String name;

    // Constructors
    // Property accessors
    .......

    public String toString() {
      return "Foo{" +
                "pid=" + pid +
                ", version=" + version +
                ", name='" + name + '\'' +
                '}';
    }
}
  <hibernate-mapping>
    <class name="stu.one2many.pojo.Foo" table="foo"
         optimistic-lock="version">
      <id name="pid" type="java.lang.Long">
            <column name="pid" />
            <generator class="native" />
      </id>
      <!-- 版本控制字段必须在id后配置 -->
      <version name="version" type="java.lang.Integer">
            <column name="version" />
      </version>
      <property name="name" type="java.lang.String">
            <column name="name" length="24" not-null="true" />
      </property>
    </class>
</hibernate-mapping>
  测试:
  public class TestFoo {

    /**
* @param args
*/
    public static void main(String[] args) {
testSave();
   
    }
    public static void testSave(){
Foo foo1 = new Foo("foo1");
   
Session session = HibernateSessionFactory.getSession();
session.save(foo1);
session.beginTransaction().commit();
      session.close();
    }
}
  2、基于时间戳的版本控制
  public class Bar implements java.io.Serializable, Comparable {

    // Fields   

    private Long id;
    private Date timestamp;
    private String name;

    // Constructors
    // Property accessors
    .......

    public String toString() {
      return "Bar{" +
                "id=" + id +
                ", timestamp=" + timestamp +
                ", name='" + name + '\'' +
                '}';
    }

    /**
   * 排序接口方法实现,为了能对查询结果按照id的大小进行排序
   * @param o 排序对象
   * @return 比较值
   */
    public int compareTo(Object o) {
      Bar bar = (Bar) o;
      Long res = this.id - bar.getId();
      return res.intValue();
    }
}
  <hibernate-mapping>
    <class name="stu.one2many.pojo.Bar" table="bar" optimistic-lock="version">
      <id name="id" type="java.lang.Long">
            <column name="id" />
            <generator class="native" />
      </id>
      <version name="timestamp" type="java.util.Date">
            <column name="timestamp" length="0" not-null="true" />
      </version>
      <property name="name" type="java.lang.String">
            <column name="name" length="24" not-null="true" />
      </property>
    </class>
</hibernate-mapping>
  public class TestBar {
    public static void main(String args[]) {
      testUpdateBar();
      testQueryBar();
    }

    public static void testSaveBar() {
      Bar bar = new Bar("bar");
      Session session = HibernateSessionFactory.getSession();
      session.save(bar);
      session.beginTransaction().commit();
      session.close();
    }

    public static void testQueryBar() {
      Session session = HibernateSessionFactory.getSession();
      String hql = "from Bar";
      Query query = session.createQuery(hql);
      List<Bar> barList = query.list();
      Collections.sort(barList);
      for (Bar bar : barList) {
            System.out.println(bar.getId() + ":\t" + bar.getTimestamp().getTime());
      }
      session.close();
    }

    public static void testUpdateBar() {
      Session session = HibernateSessionFactory.getSession();
      String hql = "from Bar";
      Query query = session.createQuery(hql);
      List<Bar> barList = query.list();
      for (Bar bar : barList) {
            bar.setName("newBar");
      }
      session.beginTransaction().commit();
      session.close();
    }
}
  public class TestStack {
    public static void main(String args[]){
      test();
    }
    public static voidtest(){
      Stack stack = new Stack();
      String s1= "1";
      String s2="2";
      String s3= "3";
      String s4= "4";
      stack.push(s1);
      stack.push(s2);
      stack.push(s3);
      stack.push(s4);

      for(;!stack.isEmpty();){
            System.out.println(stack.pop());
      }

      //for语句先判断是否符合条件,然后确定是否执行循环
      for(int i=0;i>10;i--){
            System.out.println(">>> "+i);
      }
    }
}
  下面是SessionFactory工具和hibernate配置文件:
  import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;

/**
* Configures and provides access to Hibernate sessions, tied to the
* current thread of execution.Follows the Thread Local Session
* pattern, see {@link http://hibernate.org/42.html }.
*/
public class HibernateSessionFactory {

    /**
   * Location of hibernate.cfg.xml file.
   * Location should be on the classpath as Hibernate uses   
   * #resourceAsStream style lookup for its configuration file.
   * The default classpath location of the hibernate config file is
   * in the default package. Use #setConfigFile() to update
   * the location of the configuration file for the current session.   
   */
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    privatestatic Configuration configuration = new Configuration();
    private static org.hibernate.SessionFactory sessionFactory;
    private static String configFile = CONFIG_FILE_LOCATION;

    static {
      try {
      configuration.configure(configFile);
      sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
      System.err
      .println("%%%% Error Creating SessionFactory %%%%");
      e.printStackTrace();
}
    }
    private HibernateSessionFactory() {
    }

    /**
   * Returns the ThreadLocal Session instance.Lazy initialize
   * the <code>SessionFactory</code> if needed.
   *
   *@return Session
   *@throws HibernateException
   */
    public static Session getSession() throws HibernateException {
      Session session = (Session) threadLocal.get();

if (session == null || !session.isOpen()) {
      if (sessionFactory == null) {
    rebuildSessionFactory();
      }
      session = (sessionFactory != null) ? sessionFactory.openSession()
      : null;
      threadLocal.set(session);
}

      return session;
    }

    /**
   *Rebuild hibernate session factory
   *
   */
    public static void rebuildSessionFactory() {
try {
      configuration.configure(configFile);
      sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
      System.err
      .println("%%%% Error Creating SessionFactory %%%%");
      e.printStackTrace();
}
    }

    /**
   *Close the single hibernate session instance.
   *
   *@throws HibernateException
   */
    public static void closeSession() throws HibernateException {
      Session session = (Session) threadLocal.get();
      threadLocal.set(null);

      if (session != null) {
            session.close();
      }
    }

    /**
   *return session factory
   *
   */
    public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
    }

    /**
   *return session factory
   *
   *    session factory will be rebuilded in the next call
   */
    public static void setConfigFile(String configFile) {
HibernateSessionFactory.configFile = configFile;
sessionFactory = null;
    }

    /**
   *return hibernate configuration
   *
   */
    public static Configuration getConfiguration() {
return configuration;
    }

}
  

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

<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>

    <session-factory>
<property name="connection.username">root</property>
<property name="connection.url">
      jdbc:mysql://localhost:3306/testdb
</property>
<property name="dialect">
      org.hibernate.dialect.MySQLDialect
</property>
<property name="myeclipse.connection.profile">
      com.mysql.jdbc.Driver
</property>
<property name="connection.password">leizhimin</property>
<property name="connection.driver_class">
      com.mysql.jdbc.Driver
</property>
<property name="show_sql">true</property>
<!--<property name="format_sql">true</property>-->
      <property name="hbm2ddl.auto">create</property>


      <mapping resource="stu/one2many/pojo/Tclass.hbm.xml" />
<mapping resource="stu/one2many/pojo/Student.hbm.xml" />
<mapping resource="stu/one2many/pojo/Foo.hbm.xml"></mapping>
<mapping resource="stu/one2many/pojo/Bar.hbm.xml" />

    </session-factory>

</hibernate-configuration>
  数据库用的是mysql5,sql脚本我导出了一份如下:
  /*
SQLyog Enterprise - MySQL GUI v6.5
MySQL - 5.0.45-community-nt : Database - testdb
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

create database if not exists testdb;

USE testdb;

/*Table structure for table bar */

DROP TABLE IF EXISTS bar;

CREATE TABLE bar (
id bigint(20) NOT NULL auto_increment,
timestamp datetime NOT NULL,
name varchar(24) NOT NULL,
PRIMARY KEY(id)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

/*Table structure for table foo */

DROP TABLE IF EXISTS foo;

CREATE TABLE foo (
pid bigint(20) NOT NULL auto_increment,
version int(11) NOT NULL,
name varchar(24) NOT NULL,
PRIMARY KEY(pid)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

/*Table structure for table student */

DROP TABLE IF EXISTS student;

CREATE TABLE student (
sid bigint(20) NOT NULL auto_increment,
fk_cid bigint(20) NOT NULL,
sname varchar(24) NOT NULL,
PRIMARY KEY(sid),
KEY FK8FFE823B3AA29689 (fk_cid),
CONSTRAINT FK8FFE823B3AA29689 FOREIGN KEY (fk_cid) REFERENCES tclass (cid)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=gbk;

/*Table structure for table tclass */

DROP TABLE IF EXISTS tclass;

CREATE TABLE tclass (
cid bigint(20) NOT NULL auto_increment,
cname varchar(24) NOT NULL,
PRIMARY KEY(cid)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=gbk;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;

  具体测试运行的结果运行下即可看到。
  源码压缩包太大4M多,我删除了所有引用的包。使用的是hibernate3.1

  
页: [1]
查看完整版本: Hibernate 一对多双向映射及乐观锁使用