以前学习java的时候,一开始就学习了hibernate,那时候总觉得ssh非常高大上,所以就急忙看了下相关视频。不过因为实际需要不高,所以后来一直没有使用上hibernate组件。现在一年过去了,也疯狂学习了java一段时间了,做过几个不大的项目,但是总算对java有些了解。现在参加了工作,公司使用的就是ssh,所以这两天又重新开始捣鼓hibernate。这次学习直接使用editplus,直接开发。看了官网的demo,发现英语也没有想象中那么困难。哈哈,把自己的学习记录下来吧。这里主要记录三个方面:
1.如何搭建hibernate
2.几种常用映射关系(one - to -one,one - to - many, many - to - one, many - to - many)
搭建hibernate(直接使用文本编辑器)
第一步:这个过程也不复杂,主要是下载到hibernate相关jar包,然后将必要的jar引入到classpath中,具体什么是classpath,大家可以百度下。如果不导入到classpath中,会出现不能找到类的异常。为什么会出现这种情况呢?大家可以百度下,java 的类加载过程。
第二步:编写hibernate.cfg.xml文件。这个大家不用手写,直接去hibernate文章中copy一个即可。下面给出我的代码
<?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>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_demo</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<!--if the value='create, means create table, every time open hibernate, if will drop the old scheme'-->
<property name="hbm2ddl.auto">update</property>
<mapping resource="User.xml"/>
<mapping resource="Address.xml"/>
</session-factory>
</hibernate-configuration>
第三步:开始制作一个工具类,用来初始化hibernate组件。由于难度不高,直接给出代码,这些在文章中都已经有了,大家可以自己下载document看看。下面是代码:
import java.io.*;
import org.hibernate.*;
import org.hibernate.cfg.*;
/**
* that is a hibernate config util
* */
public class HibernateConfigurationUtil{
private static HibernateConfigurationUtil singleton = new HibernateConfigurationUtil("hibernate.cfg.xml");
private static SessionFactory factory;
/**
* singleton pattern
* */
private HibernateConfigurationUtil(String configXml){
init(configXml);
}
public void init(String configXml){
Configuration cfg = new Configuration().configure(new File("hibernate.cfg.xml"));
factory = cfg.buildSessionFactory(); // build the session factory
}
public static SessionFactory getSessionFactory(){
if(factory == null) return null;
return factory;
}
/**
* open a new Session
*
* */
public static Session openSession(){
Session session = factory.openSession();
return session;
}
}
注意下,这个类使用单例设计模式,因为hibernate组建在启动Configuration时,是非常耗时的,而且这个对象在启动之后不能改变,所以每个工程中,启动一次即可。
第三步:编写BaseHibernateDao,这个类注意是封装了save, delete, update, load这四个方法。
import java.io.*;
import org.hibernate.*;
import org.hibernate.cfg.*;
/**
* that is the base hibernate dao,
* it define a series of method to access database
* if you want to 'delete, update a object, the object must exists in hibernate memery'
*
* @author luohong
* @date 2014-08-07
* */
public class BaseHibernateDao{
public BaseHibernateDao(){
}
/**
* try to save a object
* */
public void save(Object object){
Session session = HibernateConfigurationUtil.openSession();
// open transaction
Transaction transaction = session.beginTransaction();
session.save(object);
// commint transaction
transaction.commit();
}
/**
* try to update a object
* */
public void update(Object object){
Session session = HibernateConfigurationUtil.openSession();
// open transaction
Transaction transaction = session.beginTransaction();
session.update(object);
// commint transaction
transaction.commit();
}
/**
* try to delete a object
* */
public void delete(Object object){
Session session = HibernateConfigurationUtil.openSession();
// open transaction
Transaction transaction = session.beginTransaction();
session.delete(object);
// commint transaction
transaction.commit();
}
/**
* try to load a object from database by className and id
* */
public Object load(Class<?> className, Serializable id){
Session session = HibernateConfigurationUtil.openSession();
// there is no need for transaction
return session.load(className, id);
}
}
注意:在save, update, delete方法中,只用了Transaction,要开启事务,否则数据库找不到相关记录。
第四步:到了这里之后,就非常简单了,只需要针对具体的类,扩展BaseHibernateDao即可。下面给出一个一对多的例子。模拟情景:用户(User)拥有多个住址(Address)首先给出两个类:
import java.util.*;
public class User{
private int id;
private String password;
private String name;
private Set<Address> addressSet;
public void setAddressSet(Set<Address> addressSet){
this.addressSet = addressSet;
}
public Set<Address> getAddressSet(){
return addressSet;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setId(int id){
this.id = id;
}
public int getId(){
return id;
}
public void setPassword(String password){
this.password = password;
}
public String getPassword(){
return password;
}
public String toString(){
return "id = " + id + ", name = " + name + ", password = "
+ password + ", addressSet = " + addressSet;
}
}
/**
* that is the user address
* a user have many address, but a adress belong to a user
* It is the classical 1 * n relationship
* @author luohong
* @date 2014-08-07
* */
public class Address {
//=====================properties=============================
private int id;
//private User belongTo;
private String code;
private String city;
private String street;
private String homeNumber;
//===================setter and getter========================
public void setId(int id){
this.id = id;
}
public int getId(){
return id;
}
/*
public void setBelongTo(User user){
this.belongTo = belongTo;
}
public User getBelongTo(){
return belongTo;
}
*/
public void setCode(String code){
this.code = code;
}
public String getCode(){
return code;
}
public void setCity(String city){
this.city = city;
}
public String getCity(){
return city;
}
public void setHomeNumber(String homeNumber){
this.homeNumber = homeNumber;
}
public String getHomeNumber(){
return homeNumber;
}
public String getStreet(){
return street;
}
public void setStreet(String street){
this.street = street;
}
//========================toString================================
public String toString(){
return "id = " + id + ", city = " + city + ", street = " + street + ", homeNumber = " + homeNumber
+ ", code = " + code;// + ", belongTo = " + belongTo;
}
}
给出相关的User.xml, Address.xml;这个例子使用的是单向一对多。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="User" table="user">
<id name="id">
<generator class="increment"/>
</id>
<property name="password"/>
<property name="name"/>
<!--one to many-->
<set name="addressSet" cascade="all">
<!--define the foreight column name-->
<key column="user_id"/>
<!--define the foreight table name-->
<one-to-many class="Address"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Address" table="address">
<id name="id">
<generator class="increment"/>
</id>
<property name="code"/>
<property name="city"/>
<property name="street"/>
<property name="homeNumber"/>
</class>
</hibernate-mapping>
然后编写一个UserDao,继承BaseHibernateDao,也很简单,哈哈,一看就懂,这就是hibernate的厉害之处。
import java.util.*;
import org.hibernate.*;
/**
* user dao extends BaseHibernateDao
* you can add new functions to the custom dao
*
*
* @author luohong
* @date 2014-08-07
* */
public class UserDao extends BaseHibernateDao{
/**
* delete a user by userId
*
* */
public void deleteById(String id){
if (id == null) return; // do nothing
String hql = "delete User where id=?";
// 1 open session
Session session = HibernateConfigurationUtil.openSession();
// 2 create a query
Query query = session.createQuery(hql);
// 3 set the parameter to query
query.setString(1, id);
// 4 execute query
query.executeUpdate();
}
/**
* find all user from database
* */
public List<User> findAllUsers(){
String hql = "from User";
Session session = HibernateConfigurationUtil.openSession();
Query query = session.createQuery(hql);
List userList = query.list();
return (List<User>)userList;
}
}
剩下的就是测试啦,come on...
import java.io.*;
import java.util.*;
/**
* hibernate orm 框架demo
* @author luohong
* @date 2014-08-06
*
* */
public class HibernateDemo{
public static void main(String[] args) throws Exception{
UserDao userDao = new UserDao();
User user = new User();
user.setName("luohong");
user.setPassword("luohong");
Set<Address> addressSet = new HashSet<Address>();
for(int i=0; i<3; i++){
Address address = new Address();
address.setCode("111");
address.setCity("hongkang");
address.setStreet("universal street");
address.setHomeNumber("a-2846");
//address.setBelongTo(user);
addressSet.add(address);
}
user.setAddressSet(addressSet);
userDao.save(user);
}
}
下面是程序的运行结果:
Hibernate: select max(id) from user
Hibernate: select max(id) from address
Hibernate: insert into user (password, name, id) values (?, ?, ?)
Hibernate: insert into address (code, city, street, homeNumber, user_id, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into address (code, city, street, homeNumber, user_id, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into address (code, city, street, homeNumber, user_id, id) values (?, ?, ?, ?, ?, ?)
<span style="color:#ff0000;">Hibernate: update address set user_id=? where id=?
Hibernate: update address set user_id=? where id=?
Hibernate: update address set user_id=? where id=?</span>
从运行结果我们可以看到,在这种一对多关系中,这种配置方式需要执行的sql是比较多的,因为hibernate是先分别插入两个表的数据,然后在更新多表一方的id值,就如果上面红色语句部分。这其实是没有必要的,那么我们应该怎么办呢?没错,在配置一对多一的一方时,指定好 inverse="true":然后在代码里面主动设置address与user的关联,也就是address.setBelongTo(user);
<set name="addressSet" inverse="true" cascade="all">
<key column="user_id" not-null="true"/>
<one-to-many class="Address"/>
</set>
这就代表:address讲主动获取user对象的id值,在插入前就已经获得了user的id值了,只需要插入数据即可。而没有设置inverse="true"时,则直接插入new出来的address对象,然后再更新值。
下面是加入了inverse="true"的hibernate执行语句:
Hibernate: select max(id) from user
Hibernate: select max(id) from address
Hibernate: insert into user (password, name, id) values (?, ?, ?)
Hibernate: insert into address (code, city, street, homeNumber, user_id, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into address (code, city, street, homeNumber, user_id, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into address (code, city, street, homeNumber, user_id, id) values (?, ?, ?, ?, ?, ?)
上面的例子是基于单向的一对多,下面给出双向配置,其实也很简单,只需要在多的一方加入:
<many-to-one name="belongTo" class="User" column="user_id" cascade="save-update" insert="false" update="false">
</many-to-one>
在这里面,我们可以看到,无非就是指定关联的column,以及关联的表,并且配置级联关系。
作为一对多,还有一种典型的一对多关系,那就是自关联啦。
例子:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Category" table="category">
<id name="id">
<generator class="increment"/>
</id>
<property name="name"/>
<set name="categories" cascade="all">
<key column="parent_id"></key>
<one-to-many class="Category"></one-to-many>
</set>
<many-to-one name="parent" class="Category" cascade="save-update" column="parent_id">
</many-to-one>
</class>
</hibernate-mapping>
下面使用hibernate来配置多对多...
实体类:
package net.itaem.hibernate.entity;
import java.util.HashSet;
import java.util.Set;
/**
* 建立多对多
* */
public class Student {
private Integer id;
private String name;
private String number;
private Set<Teacher> teachers = new HashSet<Teacher>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", number=" + number + "]";
}
}
package net.itaem.hibernate.entity;
import java.util.HashSet;
import java.util.Set;
public class Teacher {
private Integer id;
private String name;
private String number;
private Set<Student> students = new HashSet<Student>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + ", number=" + number
+ "]";
}
}
下面是xml的配置:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="net.itaem.hibernate.entity.Student" table="student">
<id name="id">
<generator class="increment"/>
</id>
<property name="name"></property>
<property name="number"></property>
<!-- 配置多对多 -->
<set name="teachers" cascade="all" table="student_teacher">
<!-- 指定外键关联 -->
<key column="student_id"/>
<!-- 指定关联类属性 -->
<many-to-many class="net.itaem.hibernate.entity.Teacher" column="teacher_id"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="net.itaem.hibernate.entity.Teacher" table="teacher">
<id name="id">
<generator class="increment"/>
</id>
<property name="name"></property>
<property name="number"></property>
<!-- 配置多对多 -->
<set name="students" inverse="true" cascade="all" table="student_teacher">
<!-- 指定外键关联 -->
<key column="teacher_id"/>
<!-- 指定关联类属性 -->
<many-to-many class="net.itaem.hibernate.entity.Student" column="student_id"/>
</set>
</class>
</hibernate-mapping>
然后是测试类:
package net.itaem.hibernate.dao;
import java.util.HashSet;
import java.util.Set;
import net.itaem.hibernate.entity.Student;
import net.itaem.hibernate.entity.Teacher;
public class StudentDao extends BaseHibernateDao{
public static void main(String[] args) {
Student student = new Student();
student.setName("student");
student.setNumber("201111701222");
Set<Teacher> teachers = new HashSet<Teacher>();
for(int i=0; i<10; i++){
Teacher t = new Teacher();
t.setName("teacher" + i);
t.setNumber("20111170122" + i);
teachers.add(t);
}
student.setTeachers(teachers);
new StudentDao().save(student);
System.out.println(((Student)new StudentDao().load(Student.class, new Integer(1))).getTeachers());
}
}
输出结果:
Hibernate: select max(id) from student
Hibernate: select max(id) from teacher
Hibernate: insert into student (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into teacher (name, number, id) values (?, ?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: select student0_.id as id1_2_0_, student0_.name as name2_2_0_, student0_.number as number3_2_0_ from student student0_ where student0_.id=?
Hibernate: select teachers0_.student_id as student_1_2_0_, teachers0_.teacher_id as teacher_2_3_0_, teacher1_.id as id1_4_1_, teacher1_.name as name2_4_1_, teacher1_.number as number3_4_1_ from student_teacher teachers0_ inner join teacher teacher1_ on teachers0_.teacher_id=teacher1_.id where teachers0_.student_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
Hibernate: select students0_.teacher_id as teacher_2_4_0_, students0_.student_id as student_1_3_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_, student1_.number as number3_2_1_ from student_teacher students0_ inner join student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
这样子,双向的多对多也就配置完成了。