很多朋友在使用Hibernate添加有关关联对象的时候都喜欢使用一个对象对应一个save方法的方式来进行保存,但是这家种方法可以说非常的低智,优其是我们使用了Hibernate,学习过Hibernate的朋友们应该都知道,Hibernate的实现方式其实就是对JDBC的一个轻量级的封装,但是它里面提供了自已的一种数据库查询规范HQL,通过编写HQL使用得工程师
们不须要对SQL语句非常的了解,只需要了解对象之间的关联就可以,这样就可以很容易的实现面向对象的方式来编写HQL语句进行查询,Hibernate最终还是会将其转换为SQL语句并执行,Hibernate提供了很多非常实用的特性和方法,使用得我们在开发效率上可以提高几十倍的速度,但对于初学者而言这并不是一件好事,话题好象有些讲偏了题目了,不过在这里我只是做了一个简单的介绍,接下来我们还是回到题目上,使用Hibernate在保存对象与关联对象的时候使用多个save方法,这不是一件好事,只是体现了Hibernate的个基础特性,我们都知道Hibernate提供了一个非常好的功能,那就是级联,通过使用配置,我们可以体现事物的原子性,有一句非常好的话来描述级联,主增从增,主改从改,主删从删,也就是说主表的更改会同时更改子表,而你并不须要特意针对子表来做另外的一些工作,我们针对的只有子表,不过有一些朋友还是对这个不太了解,也有朋友曾经问过我好几次,这也就是我今天要写这个文章的原因,下面我就用一个小例子来讲解并实现这种方式,我将用MyEclipse IDE来实现:该项目的业务很简单,就是用来描述一个用户所对应的身份证号和所对应的职位,用户与他的身份证为一对一的关联,与职位为一对多的关系,我的实现是在添加用户信息和身份证号与及职位的时候使用级联来操作,只使用一个save方法,在添加完后在同一个session下返回刚添加的数据给用户,首先需要准备好Hibernate相关的依赖JAR包和一个MySql5驱动JAR,我在MyEclipse中新建一个Java工程,将相关的JAR包通过引用添加到该工程中去,主个时候需要抒写一个配置,该配置用来定义数据连接池和需要Hibernate来接管的持久化对象,
文件内容如下:
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="hibernate.connection.url"> jdbc:mysql://localhost/test </property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <!--此处可使用delete 或 update 根据情况而定--> <property name="hibernate.hbm2ddl.auto">create</property> <property name="hibernate.show_sql">false</property> <property name="hibernate.format_sql">true</property> <mapping resource="com/lianghe/hibernate/domain/IdCard.hbm.xml" /> <mapping resource="com/lianghe/hibernate/domain/User.hbm.xml" /> <mapping resource="com/lianghe/hibernate/domain/Department.hbm.xml" /> </session-factory> </hibernate-cofiguration>
接下来需要定义实体BEAN与及相关映射文件源码
User.java
package com.lianghe.hibernate.domain;
import java.util.Date;
public class User {
private Integer id;
private String name;
private Date birthday;
/* 用户职位 */
private Department department;
/* 用户身份证关联号 */
private IdCard idCard;
// get set ......
}
Idcard.java
package com.lianghe.hibernate.domain;
public class IdCard {
private Integer id;
private String name;
private User user;
// get set .......
}
Department.java
package com.lianghe.hibernate.domain;
import java.util.HashSet;
import java.util.Set;
public class Department {
private Integer id;
private String name;
private String desc;
private Set<User> users = new HashSet<User>(0);
// get set ........
}
User.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.lianghe.hibernate.domain"> <class name="User" table="user"> <id name="id" column="id"> <generator class="native"></generator> </id> <property name="name" column="name" /> <property name="birthday" column="birthday" /> <many-to-one name="department" column="department_id" cascade="all"/> <one-to-one name="idCard" class="IdCard" property-ref="user" cascade="all"/> </class> </hibernate-mapping>
IdCard.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.lianghe.hibernate.domain"> <class name="IdCard" table="id_card"> <id name="id" column="id" type="java.lang.Integer"> <generator class="foreign"> <param name="property">user</param> </generator> </id> <property name="name" column="i_name" /> <one-to-one name="user" class="User" constrained="true"></one-to-one> </class> </hibernate-mapping>
Department.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.lianghe.hibernate.domain"> <class name="Department" table="department"> <id name="id" column="id"> <generator class="native" /> </id> <property name="name" column="name" /> <property name="desc" column="desc" /> <set name="users" inverse="false" lazy="true"> <key column="department_id"></key> <one-to-many class="User" /> </set> </class> </hibernate-mapping>
上面也就是我将要实现的这个小例程所需要的进行处理的对象和相关映射文件的描述,到了这个时候接下我我们想要怎样就怎样了,可以进行任何的CRUD操作
接下来我就编写一个测试对象来对上面持久对象进行CRUD的操作
HibernateTest.java
package com.test;
import java.util.Date;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.lianghe.hibernate.domain.Department;
import com.lianghe.hibernate.domain.IdCard;
import com.lianghe.hibernate.domain.User;
public class HibernateTest{
private static Configuration config;
private static SessionFactory sessionFactory;
private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
static {
config = new Configuration().configure();
sessionFactory = config.buildSessionFactory();
}
/**
* 该方法用于获取 session,并将session存放到当前线程副本,用于在全局使用
*
* @return
*/
public static Session getSession() {
Session session = (Session) threadLocal.get();
if (session != null && !session.isOpen()) {
return session;
}
session = sessionFactory.openSession();
threadLocal.set(session);
return session;
}
/**
* 关闭 session
*/
public static void closeSession() {
Session session = (Session) threadLocal.get();
if (session != null && !session.isOpen()) {
session.close();
threadLocal.set(null);
}
}
public static void main(String[] args) {
Session session = null;
Transaction transaction = null;
try {
session = getSession();
transaction = session.beginTransaction();
User user = new User();
IdCard idCard = new IdCard();
Department department = new Department();
/* add start */
user.setName("陈涛");
user.setBirthday(new Date());
idCard.setName("123456789012345678");
department.setName("开发部");
department.setDesc("2");
user.setIdCard(idCard);
user.setDepartment(department);
idCard.setUser(user);
department.getUsers().add(user);
/* 这里我只使用了一个save方法,相关联的持久对象在些时都会持久化到数据库 */
session.save(user);
transaction.commit();
System.out.println("添加成功!开始获取数据");
session.flush();
/* 当添加成功之后再使用flush方法将数据库数据与持久化对象数据进行同步 */
System.out.println("User 数据== " + user.getId() + ";"
+ user.getName() + ";" + user.getBirthday());
System.out.println("Card 数据 == " + user.getIdCard().getId() + ";"
+ user.getIdCard().getName() + ";"
+ user.getIdCard().getUser().getName());
System.out.println("部门数据 == " + user.getDepartment().getId() + ";"
+ user.getDepartment().getName() + ";"
+ user.getDepartment().getDesc());
/* 添加结束 */
/* 删除操作开始 */
user = (User)session.get(User.class,1);
session.delete(user);
/* 删除操作结束 */
/* 更新开始 */
user = (User)session.get(User.class,1);
user.setName("chentao");
idCard = user.getIdCard();
idCard.setName("907867564534231258");
department = user.getDepartment();
department.setName("测试部");
department.setDesc("1");
user.setIdCard(idCard);
user.setDepartment(department);
session.saveOrUpdate(user);
/* 更新结束 */
} catch (HibernateException ex) {
transaction.rollback();
ex.printStackTrace();
} catch (Exception ex) {
transaction.rollback();
ex.printStackTrace();
} finally {
closeSession();
}
}
}
好了,我想要实现的目的也达到了,其实说白了就是说了一些使用级联来简化编程的操作,其中包括了 one-to-one 和 many-to-one 的级联操作,实现级联主要就是在关联映射文
件关联对象的配置节点上添加了属性cascade,该属性参数你可以选择,使用 all 就代表全部的相关CRUD操作,save-update表示添加和更新的操作,delete 只使用删除上的功能
,这些都可以随意选择,根据自已的情况来定义,感兴趣的朋友可以把代码复制下去体验一下哦!
总节:
通过在上面的实现中,可以充分理解到Hibernate的实用之处,当然还有一点就是在添加之后使用了 flush 来将数据进行同步的操作可以将数据库数据与持久对象数据保持一至,
如果是分开使用save来持久化,将会达不到想要的结果,因为相关的关联对象都是独立,但它们共同指向了一个内存地址