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 void test(){
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>();
private static 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. 本站所有资源来自网络搜集或用户上传,仅作为参考不担保其准确性!
2. 本站内容仅供学习和交流使用,版权归原作者所有!© 查看更多
3. 如有内容侵害到您,请联系我们尽快删除,邮箱:kf@codeae.com