实体类:
package com.xiangshuai.hibernate;
import java.util.HashSet;
import java.util.Set;
/**
* 顾客类
* */
public class Customer {
privateInteger id;
privateString cname;
privateSet<Order> orders=new HashSet<Order>();
publicInteger getId() {
returnid;
}
publicvoid setId(Integer id) {
this.id= id;
}
publicString getCname() {
returncname;
}
publicvoid setCname(String cname) {
this.cname= cname;
}
publicSet<Order> getOrders() {
returnorders;
}
publicvoid setOrders(Set<Order> orders) {
this.orders= orders;
}
@Override
publicString toString() {
return"Customer [id=" + id + ", cname=" + cname + ",orders=" + orders + "]";
}
}
package com.xiangshuai.hibernate;
/**
* 订单类
* */
public classOrder {
private Integer id;
privateString oname;
privateCustomer customer;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getOname() {
return oname;
}
public void setOname(String oname) {
this.oname = oname;
}
public Customer getCustomer(){
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
@Override
public String toString() {
return "Order [id="+ id + ", oname="+ oname+ "]";
}
}
实体类对应的XML文件
一的一方:Customer.hbm.xml
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- ORM元数据 表对象关系映射文件
package : 配置该配置文件中类所在的包. -->
<hibernate-mapping package="com.xiangshuai.hibernate" >
<class name="Customer" table="t_customer" >
<!-- 如果类属性 name和表列column一致可以只定name -->
<id name="id"column="id" length="255">
<generator class="native"></generator>
</id>
<property name="cname"></property>
<!-- 一对多关系用 set配置在set标签中将inverse设为ture则此xml对应的类放弃维护外键,
即Customer放弃维护外键,实际开发也一般是一的一方放弃维护外键关系
默认是flase,如果一的一方经常要维护cid外键,那么这里就不要设置,默认就好
<keycolumn="cid"> column类名这里表示在Order对应的表中的列名(表外键字段cid)cid
<one-to-manyclass="Order"/>即cid表对应的类
如果inverse设为true 也就是一的一方不负责维护外键cid的创建等等,那么在用session.sava(customer)时
虽然因为设置了cascade="save-update,delete"但也只会保存order对象中已有属性,而不会保存order对象中
没有的属性cid,因此在执行session.sava(customer)前必须执行 order1.set(customer),order1.set(customer),
让order这个多的一方维护外键,先将customer保存到对象中以生成cid这样 session.sava(customer)执行后t_order给的
cid值才不会为null
而 delete却可以直接 session.delete(customer)在删除customer的同时删除customer所拥有的所有订单-->
<set name="orders" inverse="true"cascade="save-update,delete" lazy="false">
<key column="cid"></key>
<one-to-many class="Order"/>
</set>
</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://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- ORM元数据 表对象关系映射文件
package : 配置该配置文件中类所在的包. -->
<hibernate-mapping package="com.xiangshuai.hibernate" >
<class name="Order" table="t_order" >
<id name="id"column="id" length="255">
<generator class="native"></generator>
</id>
<property name="oname"></property>
<!-- 多的一方直接用<many-to-one 标签配置与一的一方的关系即可
nameOrder的属性名 customet,class="Customer" 这个name"customer"对应的类 ,column对应的外键名即多
的一方的外键名和一一方set中的<key column="cid"></key>一致-->
<many-to-one name="customer" class="Customer"column="cid"></many-to-one>
</class>
</hibernate-mapping>
将实体类对应的xml文件mapper到hibernate.cfg.xml中
<?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 元素用于配置Hibernate中的属性
键:值
-->
<!--hibernate.connection.driver_class : 连接数据库的驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!--hibernate.connection.username : 连接数据库的用户名 -->
<property name="hibernate.connection.username">root</property>
<!--hibernate.connection.password : 连接数据库的密码 -->
<property name="hibernate.connection.password">root</property>
<!--hibernate.connection.url : 连接数据库的地址,路径 -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/demo</property>
<!-- show_sql: 操作数据库时,会向控制台打印sql语句 -->
<property name="show_sql">true</property>
<!-- format_sql: 打印sql语句前,会将sql语句先格式化 -->
<property name="format_sql">true</property>
<!-- hbm2ddl.auto: 生成表结构的策略配置
update(最常用的取值): 如果当前数据库中不存在表结构,那么自动创建表结构.
如果存在表结构,并且表结构与实体一致,那么不做修改
如果存在表结构,并且表结构与实体不一致,那么会修改表结构.会保留原有列.
create(很少):无论是否存在表结构.每次启动Hibernate都会重新创建表结构.(数据会丢失)
create-drop(极少): 无论是否存在表结构.每次启动Hibernate都会重新创建表结构.每次Hibernate运行结束时,删除表结构.
validate(很少):不会自动创建表结构.也不会自动维护表结构.Hibernate只校验表结构. 如果表结构不一致将会抛出异常.
-->
<property name="hbm2ddl.auto">update</property>
<!-- 数据库方言配置
org.hibernate.dialect.MySQLDialect (选择最短的)
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- hibernate.connection.autocommit: 事务自动提交 -->
<property name="hibernate.connection.autocommit">true</property>
<!-- 将Session与线程绑定=> 只有配置了该配置,才能使用getCurrentSession-->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 引入ORM 映射文件
填写src之后的路径
-->
<mapping resource="com/xiangshuai/hibernate/Customer.hbm.xml"/>
<mapping resource="com/xiangshuai/hibernate/Order.hbm.xml"/>
</session-factory>
</hibernate-configuration>
测试类:
package com.xiangshuai.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test;
import com.xiangshuai.hibernate.Customer;
import com.xiangshuai.hibernate.Order;
public class COdemo {
privateConfiguration conf=null;
SessionFactorysessionFactory=null;
Sessionsession =null;
@Test
public void demoSave(){
/* 因为Customer.hbm.xml<setname="orders" inverse="true"cascade="save-update,delete">中
* 因为inverse="true"设为true所以 customer不负责维护外键,
* 因为设置了级联sava-update所以只要执行session.sava(customer)就可以保存orers到数据库
* 删除也是可以直接执行session.delete(customer)就可以级联删除customer下的所有order
* */
session=getSession();Transaction tr =session.beginTransaction();
Order order1 = new Order(); Order order2 = newOrder();Customer customer1 = new Customer();
order1.setOname("订单1");order1.setCustomer(customer1);order2.setOname("订单2");order2.setCustomer(customer1);
Set<Order> orders=newHashSet<Order>();orders.add(order1);orders.add(order2);
customer1.setCname("小明");customer1.setOrders(orders);
session.save(customer1);
tr.commit();closeStream(sessionFactory,session);
}
@Test
public void delete(){
/*Customer.hbm.xml<setname="orders" inverse="true"cascade="save-update,delete">
* 因为设置了级联所以直接执行session.delete(customer)就可以级联删除customer下的所有order*/
session=getSession();Transaction tr =session.beginTransaction();
Query query = session.createQuery("fromCustomer where id=?").setInteger(0, 4);
Customer customer = (Customer)query.uniqueResult();
session.delete(customer);
tr.commit();closeStream(sessionFactory,session);
}
@Test
public void update(){
session=getSession();Transaction tr =session.beginTransaction();
Query query = session.createQuery("fromCustomer where id=?").setInteger(0, 5);
/**
* 因为在Customer.hbm.xml的set标签中并没有设lazy="false"(默认为true),所以在执行完query.uniqueResult()
* 只会向数据库将Customer查出来(执行的sql为 Hibernate:select customer0_.id as id0_,customer0_.cname as cname0_
from t_customer customer0_ wherecustomer0_.id=?),只有当真正要用到order时才会再次向数据库发sql,但如如下代码
在执行 System.out.println(customer)时因为session已经关闭,所以无法发sql会报
org.hibernate.LazyInitializationException: failed to lazily initialize acollection of role: com.xiangshuai.hibernate.Customer.orders, no session orsession was closed
at这个错
**/
Customer customer = (Customer)query.uniqueResult();
customer.setCname("小明改2");
session.update(customer);
tr.commit();closeStream(sessionFactory,session);
System.out.println(customer);
}
@Test
public void lazyselect(){
/*在Customer.hbm.xml的set标签中设lazy="false"(默认为true)--<setname="orders" inverse="true"cascade="save-update,delete" lazy="false">
* 那么会向数据库查customer对象时将orders也会一并查出
* 如执行完 .uniqueResult()会查出customer的同时查出其customer对象的属性Set<Order>order对象的记录
* sql如下--Hibernate:
select * from t_customer where id=?
Hibernate:
select orders0_.cid as cid0_1_,orders0_.id as id1_, orders0_.id asid1_0_,orders0_.oname as oname1_0_,
orders0_.cid as cid1_0_ from t_order orders0_ where orders0_.cid=?
而且此时执行customer.toString也不会再报错---这里也注意 customer和order类重写 toString方法不能两个都将对方属性toString中
否则会死循环造成java.lang.StackOverflowError 内存溢出
* */
session=getSession();Transaction tr =session.beginTransaction();
//链式操作
Customer customer = (Customer)session.createSQLQuery("select * from t_customer whereid=?").addEntity(Customer.class).setInteger(0, 5).uniqueResult();
/*SQLQuery createSQLQuery =session.createSQLQuery("select * from t_customer where id=?");
SQLQuery addEntity =createSQLQuery.addEntity(Customer.class);
Query c1 = addEntity.setInteger(0, 4);
Customer c = (Customer) c1.uniqueResult();*/
tr.commit();closeStream(sessionFactory, session);
System.out.println(customer);
}
public Session getSession() {
//1读取配置文件
conf = new Configuration().configure();
//2根据配置 创建Factory
sessionFactory= conf.buildSessionFactory();
//3通过获得操作数据库的session对象
session= sessionFactory.openSession();
returnsession;
}
public void closeStream(SessionFactorysessionFactory,Session session){
if(session!=null){
session.close();
}
if(sessionFactory!=null){
sessionFactory.close();
}
}
}