
正文
Hibernate入门4.核心技能
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
Hibernate入门4.核心技能 20131128
代码下载 链接: http://pan.baidu.com/s/1Ccuup 密码: vqlv
前言:
前面学习了Hibernate3的基本知识,并且应用在简单的实践中。这些知识Hibernate的基本知识,只能说是会使用简单的hibernate了。这一章学习的是Hibernate的核心技能。主要知识点:
Hibernate中持久化类的关联关系、Hibernate的批量处理技术、Query接口的核心方法和使用、HQL语言的查询、Criteria接口的核心方法以及查询技巧、Restrictions的使用方法、DetachedCriteria离线查询的技巧、Hibernate事务处理
1.Hibernate中的关联关系
关联关系指的是类之间的引用关系,是实体对象之间普遍存在的一种关系。使用Hibernate框架可以完整的表述这种关联关系,如果映射的十分恰当,Hibernate的关联映射将在很大程度上简化对于持久层数据的访问。
1.1一对多的关联关系
单项的N-1的关系,只能够从N访问到1的一端,在类与类的各种关联关系中,单项N-1关联和关系数据库中的外检参照关系最为相似。比如Customer和Order,使用的是N-1的单项关联,即从Order到Customer的关联关系。(其实这里已经买下一个地雷了,我们使用Order表示订单,在数据库中,对应的表的名字可以是order,当然是不可以的,因为order是关键字。在数据库的创建表的过程中,我习惯使用小写字母,这里就会出现非常隐蔽的错误,我们不断的调试程序,却始终找不到错误。)
Customer.java
package com.yang.hib.model;
public class Customer {
private int id;
private String userName;
private String password;
private String realName;
private String address;
private String mobile;
private String email;
public Customer(){}
public Customer(String userName, String password, String realName,
String address, String mobile, String email) {}
//getter & setter
}
Order.java:
package com.yang.hib.model;
import java.util.Date;
public class Order {
private int id;
private String orderNo;
private Date date;
private double total;
private Customer customer;
public Order(){}
public Order(String orderNo, Date date, double total, Customer customer) {}
//getter & setter
public void setCustomer(Customer customer){ this .customer = customer;}
public Customer getCustomer(){ return this .customer;}
}
Customer.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.yang.hib.model" >
<class name= "Customer" table= "customer" >
<!—参考之前的代码-->
</class>
</hibernate-mapping>
Order.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.yang.hib.model" >
<class name= "Order" table= "myorder" >
<!—注意这里的数据表不可以是order,关键字一般情况下不能够用作表名-->
<id name= "id" column= "id" >
<generator class= "native" />
</id>
<property name= "orderNo" column= "orderno" type= "string" />
< property name= "date" column= "orderdate" type= "timestamp" />
< property name= "total" column= "total" type= "double" />
<many-to-one name= "customer" column= "customer_id" class= "Customer" cascade= "save-update" />
<!— 这一句是最为核心的配置信息,实现多对一的级联关系 -->
</class>
</hibernate-mapping>
HibernateUtil.java
package com.yang.hib.util;
public class HibernateUtil {
private static String HIBERNATE_CONFIG_FILE = "hibernate.cfg.xml";
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new Configuration();
private static SessionFactory sessionFactory ;
/*静态代码段,在该类加载的时候,执行这一段代码,这里使用的是单例模式,同时为了在多线程中使用session,使用了线程的局部变量,之前在Java进阶中的关于线程同步的知识中,最后一种方式便是使用的这一种线程局部变量将他保护起来的方式*/
static {
try {
configuration .configure(ClassLoader. getSystemResource ( HIBERNATE_CONFIG_FILE ));
sessionFactory = configuration .buildSessionFactory();
} catch (Exception e){
System. err .println("%%%%%Error Creating session factory %%%%%%%%");
e.printStackTrace();
}
}
//禁止外部创建该类型的对象
private HibernateUtil(){}
public static Session getSession() throws HibernateException{
Session session = threadLocal .get();
if (session == null || !session.isOpen()){
if ( sessionFactory == null ){
sessionFactory = configuration .buildSessionFactory();
}
session = ( sessionFactory != null )? sessionFactory .openSession(): null ;
threadLocal .set(session);
}
return session;
}
public static void reBuildSessionFactory(){
try {
configuration .configure( HIBERNATE_CONFIG_FILE );
sessionFactory = configuration .buildSessionFactory();
} catch (Exception e){
System. err .println("%%%%Error Creating SessionFactory %%%%%");
e.printStackTrace();
}
}
public static void closeSession() throws HibernateException{
Session session = threadLocal .get();
threadLocal .set( null );
if (session != null ){
session.close();
}
}
public static SessionFactory getSessionFactory(){
return sessionFactory ;
}
public static void setHibernateConfigFile(String hibernateConfigFile){
HIBERNATE_CONFIG_FILE = hibernateConfigFile;
}
public static Configuration getConfiguration(){
return configuration ;
}
}
TeatMain.java
package com.yang.main;
public class TestMain {
public static void addCustomerAndOrder(){
Customer customer = new Customer("yang","12345","杨腾飞","广州","15800027127","1076906529@qq.com");
System. out .println("add customer to database");
addCustomer (customer);
Order order1 = new Order("A1", new Date(),42.8,customer);
System. out .println("add order to database");
addOrder (order1);
order1 = new Order("A2", new Date(),35.9,customer);
System. out .println("add antother order to database");
addOrder (order1);
}
public static void addCustomer(Customer customer){
Session session = HibernateUtil. getSession ();
Transaction trans = session.beginTransaction();
session.save(customer);
trans.commit();
HibernateUtil. closeSession ();
}
public static void addOrder(Order order){
Session session = HibernateUtil. getSession ();
Transaction trans = session.beginTransaction();
session.save(order);
trans.commit();
HibernateUtil. closeSession ();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
addCustomerAndOrder ();
}
}
我们可以根据订单查询出数据库中的对应的顾客的信息,修改TestMain.java函数:
public static void findOrder( int id){
Session session = HibernateUtil. getSession ();
Order order = (Order) session.get(Order. class , id);
Customer customer = order.getCustomer();
System. out .println( "Id:"+order.getId()+
"\ntotal:" + order.getTotal()+
"\norderdate:" + order.getDate().toLocaleString() +
"\nrealName:"+customer.getRealName()+
"\nmobile:" + customer.getMobile());
HibernateUtil. closeSession ();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//addCustomerAndOrder();
findOrder (1);
}
这个时候,我们发现在控制台中是执行了两个SQL语句,对于两个表的查询,我们可以使用连接的形式使用一条SQL语句便可以完成这些查询:
在hibernate-mapper配置信息中,对于<many-to-one>元素中可以使用指定的属性来让hibernate使用连接的方式:
<many-to-one name=”customer” fetch=”join” column=”customer_id” class=”Customer”/>实现。对于many-to-one元素的fetch属性也可以使用outer-join属性替代,默认情况之下使用的是fetch=”select”。
1.2单项的1-N的关系
Customer与Order就是一对多的关系,我们可以在Order中添加orders集合属性
Customer.java
private Set<Order> orders= new HashSet<Order>();
public void setOrders(Set<Order> orders){ this .orders = orders;}
public Set<Order> getOrders(){ return this .orders;}
配置文件中添加如下配置信息:
Customer.hbm.xml
<set name= "orders" >
<key column= "customer_id" /><!—这里是对应的另一个表中的字段-->
<one-to-many class= "Order" />
</set>
在Hibernate中通过比较两个持久化对象 的标识符属性 ID 来判 断两者是否是相等的,这需要在实体类中对equals()和hashCode()方法重写。
重写hashCode()
public int hashCode(){
final int prime = 31;
int result = 1;
result = result*prime + ((id==null)?0:id.hashCode());
return result;
}
也就是将id+prime作为其对象的hashCode
同时对已比较两个对象是否相等,如果两者的引用是同一个对象的话,那么无论怎样都是相等的,否则如果对象是null的话,那么两者肯定不相等,因为如果两个都是null的话,那么在前面的判断中两者引用都是null则相等。继而继续判断:将obj转换成为目标类型的对象,这个时候原始的对象的id如果是null,也就是数据库中没有该数据,另一个对象也是没有持久化的,内容虽然不相同,但是两者的都没有id,则判断两者是相等的。
参考代码:
Customer c1 = new Customer("yang","12345","杨腾飞","广州","15800027127","1076906529@qq.com");
Customer c2 = new Customer("yang","134545","杨腾飞","广州","15800027127","1076906529@qq.com");
System. out .println(c1.equals(c2));
正常情况之下,两者是不想等的,但是在Hibernate重写equals函数之后,两者就是相等的。很诡异的吧,其实我现在也不是很理解。但是这是在Hibernate中比较数据库中的两个对象,就只会根据id来判断。
public boolean equals(Object obj){
if ( this == obj){ return true ; }
if (obj == null ){ return false ;}
if (getClass() != obj.getClass()){ return false ;}
Customer other = (Customer) obj;
if (id == null ){
if (other.id != null ){ return false ;}
} else if ( ! id.equals(other.id)){
return false ;
}
return true ;
}
下面查询执行用户的订单:
public static void findOrderByCustomer(Integer id){
Session session = HibernateUtil. getSession ();
Customer customer = (Customer) session.get(Customer. class , id);
Set<Order> orders = customer.getOrders();
for (Order order : orders){
System. out .println( "id:"+ order.getId()+
",\torderNo:"+order.getOrderNo()+
",\ttotal:" + order.getTotal()+
",\tdate:"+order.getDate().toLocaleString());
}
}
一般使用的技术是双向的1-N级联,也就是在两个里面都配置级联关系,形成双向的级联。
YangTengfei
2013.11.28





![【JAVAEE】[No81]Struts2+Spring3+Hibernate4+Maven+EasyUI整合入门视频教程 【JAVAEE】[No81]Struts2+Spring3+Hibernate4+Maven+EasyUI整合入门视频教程](https://www.04ip.com/template/qe/style/noimg/17.jpg)
![[No81]Struts2+Spring3+Hibernate4+Maven+EasyUI整合入门视频教程 [No81]Struts2+Spring3+Hibernate4+Maven+EasyUI整合入门视频教程](https://www.04ip.com/template/qe/style/noimg/5.jpg)
