Hibernate是开源的ORM(对象关系映射)框架。对JDBC进行轻量级的封装,将pojo和数据库表建立映射关系,是一个全自动的orm框架。它可以自动生成sql语句,自动执行。使码农可以使用面向对象的思想来操作数据库。
版本是5.0.7
hibernate
英 [ˈhaɪbəneɪt] 美 [ˈhaɪbərneɪt]
vi.
(某些动物)冬眠,蛰伏
解压后的目录:documentation:文档,API文档
lib:Hibernate编译和运行所依赖的JAR包。required子目录下的是运行hibernate必须的jar包。
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driverproperty>
<property name="hibernate.connection.url">jdbc:mysql:///studentproperty>
<property name="hibernate.connection.username">rootproperty>
<property name="hibernate.connection.password">rootproperty>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialectproperty>
<property name="hibernate.show_sql">trueproperty>
<property name="hibernate.format_sql">trueproperty>
<property name="hibernate.hbm2ddl.auto">updateproperty>
<property name="hibernate.connection.isolation">4property>
<property name="hibernate.current_session_context_class">threadproperty>
<mapping resource="com/hero/pojo/Customer.hbm.xml" />
<mapping resource="com/hero/pojo/LinkMan.hbm.xml" />
<mapping resource="com/hero/pojo/Role.hbm.xml" />
<mapping resource="com/hero/pojo/User.hbm.xml" />
session-factory>
hibernate-configuration>
class Customer { }
Customer.hbm.xml
<hibernate-mapping package="com.hero.pojo" >
<class name="Customer" table="cst_customer" >
<id name="custId" column="cust_id" >
<generator class="native">generator>
id>
<property name="custPhone" column="cust_phone" >property>
class>
hibernate-mapping>
@Test
public void TestA() {
//配置加载类,加载主配置,加载ORM元数据;使用空参,加载默认位置(src下的hibernate.cfg.xml)的配置文件
Configuration conf = new Configuration().configure();
//1.负责保存和使用所有配置信息,消耗内存很大 2.属于线程安全对象
//因为上面两个原因,所有保证在web项目中只有一个sessionFactory
SessionFactory factory = conf.buildSessionFactory();
//获得一个新的session
Session session = factory.openSession();
//获取并开启事务
Transaction transaction = session.beginTransaction();
//---------------------------------------------
Customer customer = new Customer();
customer.setCustName("百度");
session.save(customer);
//---------------------------------------------
transaction.commit();
//transaction.rollback();
session.close();
factory.close();
}
实体类创建注意事项:
1.要有空参构造器(底层是反射)
2.提供set/get,私有参数
private int id; //成员变量
一对set/get方法叫做一个属性,即使set/get是没有意义的,一个类中有多少个属性取决于有多少对set/get
3.持久化类中的属性,最好使用包装类型
4.持久化类需要提供oid和数据库中的主键相对应(没有主键的表是无法使用hibernate的)
5.不要用final修饰class(代理是用cglib继承的,如果用final就无法继承)
主键类型:
1.自然主键(少见,例如身份证号码)
在业务中,某个属性刚好不重复可以代表每个不同的行
2.代理主键(常见)
一个没业务意义的列,但是不重复可以代表不同的行
主键生成策略(其中)
每条记录录入的时候,主键的生成规则
1.identity 主键自增,由数据库来维护主键值,不需要指定主键值
<id name="custId" column="cust_id" >
<generator class="identity">generator>
id>
2.increment 主键自增,由hibernate来维护主键,每次插入会查询数据库,然后id+1
开发中不要用,因为有线程安全问题。而且所有的数据库都有自己的维护自增主键的算法,不要外界框架来帮忙
3.sequence:oracle中的主键生成策略
4.hilo:主键自增,由hibernate来维护主键,采用高低位算法
5.native(自动三选一:identity,sequence,hilo)
6.uuid:产生随机字符串,必须要string类型
7.assigned开发人员自己录入,自然主键
对象分为三种状态
1.瞬时态:,数据库中没有ID和你对应,没有在session中缓存,失去引用后就会被垃圾回收,永远没有你存在的痕迹
2.持久态:在提交事务后数据库有ID对应,和session有关联
3.游离态|托管状态:有Id对应,没有和session关联
Customer customer = new Customer();//没有id,没有和session关联=>瞬时态
customer.setCustName("百度");//瞬时态
session.save(customer);//有id,有关联,持久态
//---------------------------------------------
transaction.commit();
//transaction.rollback();
session.close();//有id,没关联,游离态
factory.close();
save方法的本质:将瞬时态对象转化成持久态对象
在session.save(customer);前打断点
如果主键生成策略是native,那么在session.save(customer);执行后会打印Insert语句,目的是为了获得ID
但是如果主键生成策略是increment
那么session.save(customer);执行后会打印,目的是为了获得ID
Hibernate:
select
max(cust_id)
from
cst_customer
提交事务后才会打印insert语句
如果是uuid,那么save不会打印任何语句,提交事务后才会打印insert语句
持久化:持久化状态的对象的任何变化都会自动同步到数据库中,使用hibernate的目的就是同步数据库,所以用持久态对象进行增改
Customer c = session.get(Customer.class, "2");
System.out.println(c);
c.setCustName("六六六");
transaction.commit();
session.close();
factory.close();
上面的代码修改了c对象的属性,在提交事务后会修改数据库里的名字属性
saveOrUpdate:可以将对象转换成持久态(不管你是游离态还是瞬时态)
save:把瞬时态变成持久态
close:关闭session,把持久态变成游离态
update:把游离态变成持久态
delete:把持久态变成瞬时态
get:获得一个持久态对象
提高操作数据库的效率
查询数据库活的一个快照
持久态:其实就是在session中有缓存数据
缓存中的对象会同步到数据库中
查询数据先走缓存,如果缓存中有,就不去数据库了
但是如果数据库数据变了,hibernate是不知道的,还是去缓存,结果就会出错
1 0001 读未提交
2 0010 读已提交
4 0100 可重复读
8 1000 串行化
<property name="hibernate.connection.isolation">4property>
//获取并开启事务
Transaction transaction = session.beginTransaction();
事务在service层,需要session
dao层要用session操作数据
两个层的session必须一样
JDBC的时候要手动绑定线程
现在框架sf.getCurrentSession()
使用sf.getCurrentSession
要在主配置文件中配置
<property name="hibernate.current_session_context_class">threadproperty>
*注意:***getCurrentSession获得的session提交事务后会自动关闭session,如果你手动close那么就会抛异常
HQL 在查询多表但是不复杂的时候用
Criteria 单表查询
SQL原生态的 适合特别特别复杂的业务
HQL查询
String hql = select 属性 from 对象完整类名
如果是select *,那么可以省略成from 对象完整类名
如果类的名字不重复,那么可以直接写类的名字,不用带包名
在Hql中,是不可以出现任何关于数据库信息的词句,完全面向对象
//基础查询
String hql = "from Customer";
Query query = session.createQuery(hql);
List list = query.list(); //返回所有数据列表
for(Customer c : list){
System.out.println(c);
}
//query.uniqueResult(); 如果你知道只有一条结果
条件查询
String hql = "from Customer where custId = "+"2";
Query query = session.createQuery(hql);
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
问号占位符
String hql = "from Customer where custId = ? ";
Query query = session.createQuery(hql);
query.setString(0, "3");//0代表第一个外号,内容是“3”
//推荐使用setParameter,不管你是什么类型都可以用
query.setParameter(0, "3");
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
//命名占位符
//如果业务使语句?的位置变化,靠顺序就难了
//为数据起一个随便的名字,格式是 :+名字
String hql = "from Customer where custId = :hero ";
Query query = session.createQuery(hql);
//重载方法,赋予名字是hero值“6”
query.setParameter("hero", "6");
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
分页查询
String hql = "from Customer ";
Query query = session.createQuery(hql);
//起始行,从第几行开始抓
query.setFirstResult(0);
//一共呢要抓几行数据啊
query.setMaxResults(3);
List c = query.list();
System.out.println(c);
criteria 英[kraɪ’tɪərɪə]
美[kraɪˈtɪrɪə]
n. (批评、判断等的) 标准,准则( criterion的名词复数 ); (criterion的复数)
criteria不用写语句,完全面向对象查询。QBC(query by Criteria)
//查询所有Customer对象
Criteria criteria = session.createCriteria(Customer.class);
List c = criteria.list();
//criteria.uniqueResult();
System.out.println(c);
//条件查询
Criteria criteria = session.createCriteria(Customer.class);
// Restrictions可以点出来许多sql条件
criteria.add(Restrictions.eq("custId", "2"));
Customer c = (Customer) criteria.uniqueResult();
System.out.println(c);
//分页查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List c = criteria.list();
System.out.println(c);
//查询总行数
Criteria criteria = session.createCriteria(Customer.class);
//projections可以点出聚合函数
criteria.setProjection(Projections.rowCount());
Long c = (Long)criteria.uniqueResult();
System.out.println(c);
原生态SQL查询
//查询所有Customer对象
String sql = "select * from cst_customer";
SQLQuery query = session.createSQLQuery(sql);
//因为你写的sql,框架不知道你查的是什么类型,
所有列表里每个数据都是object数组,存放表的每一个属性
List<Object[]> c = query.list();
for(Object[] objs : c){
System.out.println(Arrays.toString(objs));
}
楼上的方法太麻烦了,框架有解决办法
//查询所有Customer对象
String sql = "select * from cst_customer";
SQLQuery query = session.createSQLQuery(sql);
//告诉框架你的实体类型
query.addEntity(Customer.class);
List c = query.list();
System.out.println(c);
//占位符查询
//String sql = "select * from cst_customer limit ?,?";
String sql = "select * from cst_customer where cust_id = ?";
SQLQuery query = session.createSQLQuery(sql);
//告诉框架你的实体类型
query.addEntity(Customer.class);
//第一个占位符值是2
query.setParameter(0, "2");
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
上图是数据库表的表示方式,那么在POJO中如何表达?
少见
例如
客户表:id=1 name=百度 id=2 name=腾讯
职员表:id =1 name=张三 cid=1
如果POJO表达关系
class company{
private int id;
private String name;
private Set staffs;
}
class staff{
private int id;
private String name;
private Company com;
}
//客户类:客户有百度,腾讯,阿里
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
private Set linkMans;
}
<hibernate-mapping package="com.hero.pojo" >
<class name="Customer" table="cst_customer" >
<id name="cust_id" >
<generator class="native">generator>
id>
<property name="cust_name" column="cust_name" >property>
<property name="cust_source" column="cust_source" >property>
<property name="cust_industry" column="cust_industry" >property>
<property name="cust_level" column="cust_level" >property>
<property name="cust_linkman" column="cust_linkman" >property>
<property name="cust_phone" column="cust_phone" >property>
<property name="cust_mobile" column="cust_mobile" >property>
<set name="linkMans" >
<key column="lkm_cust_id">key>
<one-to-many class="LinkMan"/>
set>
class>
hibernate-mapping>
//一个客户对象有多个联系人,客户公司是百度,百度的联系人有好多个
public class LinkMan {
private Long lkm_id;
private Character lkm_gender;
private String lkm_name;
private String lkm_phone;
private String lkm_email;
private String lkm_qq;
private String lkm_mobile;
private String lkm_memo;
private String lkm_position;
//表达多对一关系
private Customer customer ;
}
<hibernate-mapping package="com.hero.pojo" >
<class name="LinkMan" table="cst_linkman" >
<id name="lkm_id" >
<generator class="native">generator>
id>
<property name="lkm_gender" >property>
<property name="lkm_name" >property>
<property name="lkm_phone" >property>
<property name="lkm_email" >property>
<property name="lkm_qq" >property>
<property name="lkm_mobile" >property>
<property name="lkm_memo" >property>
<property name="lkm_position" >property>
<many-to-one name="customer" column="lkm_cust_id" class="Customer" >
many-to-one>
class>
hibernate-mapping>
@Test
//保存客户 以及客户 下的联系人
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
Customer c = new Customer();
c.setCust_name("百度");
LinkMan lm1 = new LinkMan();
lm1.setLkm_name("李彦宏");
LinkMan lm2 = new LinkMan();
lm2.setLkm_name("陆奇");
//表达一对多,客户下有多个联系人
c.getLinkMans().add(lm1);
c.getLinkMans().add(lm2);
//表达对对对,联系人属于哪个客户
lm1.setCustomer(c);
lm2.setCustomer(c);
session.save(c);
session.save(lm1);
session.save(lm2);
//-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}
@Test
//为客户增加联系人
public void fun2(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
//1> 获得要操作的客户对象
Customer c = session.get(Customer.class,2L);
//2> 创建联系人
LinkMan lm1 = new LinkMan();
lm1.setLkm_name("张三");
//3> 将联系人添加到客户,将客户设置到联系人中
c.getLinkMans().add(lm1);
lm1.setCustomer(c);
//4> 执行保存
session.save(lm1);
//-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}
级联操作:save-update,不要用delete,太危险了
@Test
//为客户删除联系人,这里只是解除了张三作为百度联系人的属性,数据库中还是有张三的记录的
//只是张三的外键变成了空
public void fun3(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
Customer c = session.get(Customer.class, 2L);
LinkMan linkMan = session.get(LinkMan.class, 5L);
c.getLinkMans().remove(linkMan);
linkMan.setCustomer(null);
//-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}
//上面保存新增的百度联系人
//如果新增了100个,难道要一个个save么?
session.save(c);
session.save(lm1);
session.save(lm2);
<set name="linkMans" cascade="save-update" >
<key column="lkm_cust_id">key>
<one-to-many class="LinkMan"/>
set>
同样的,在多的一方也可以级联操作。例如,添加了一个腾讯的李四,保存李四的同时也添加腾讯公司的信息
<many-to-one name="customer" column="lkm_cust_id" class="Customer" cascade="save-update" >
many-to-one>
//3操作
Customer c = new Customer();
c.setCust_name("腾讯");
LinkMan lm1 = new LinkMan();
lm1.setLkm_name("李四");
//表达一对多,客户下有多个联系人
c.getLinkMans().add(lm1);
//表达对对对,联系人属于哪个客户
lm1.setCustomer(c);
//只保存李四,不保存腾讯,但是因为级联或保存腾讯
session.save(lm1);
下面是执行的SQL语句,添加了一个腾讯的李四,所以在表中添加腾讯customer,linkman李四
先添加腾讯信息
再添加李四信息(包含了外键腾讯,这是linkman自己维护外键)
维护外键(这是customer方维护外键)
inverse 英[ˌɪnˈvɜ:s]
美[ˌɪnˈvɜ:rs]
adj. 相反的; 逆向的; 倒转的;
n. 相反; 倒转; 相反的事物;
vt. 使倒转; 使颠倒;
很明显,最后的维护外键是不需要的,所以在配置文件中配置
Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
cst_linkman
(lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?
<set name="linkMans" cascade="save-update" inverse="true" >
<key column="lkm_cust_id">key>
<one-to-many class="LinkMan"/>
set>
//这行代码也可以不用写了
//因为customer已经不维护外键了
//对象中的linkmans集合已经和我没关系了
c.getLinkMans().add(lm1);
如果customer维护外键,不设置级联,然后删除阿里对象,那么会删除从表的阿里的联系人,同时删除阿里customer
如果customer不维护外键,不置级联,然后删除阿里对象,那么会删除从表的阿里的联系人,同时删除阿里customer
//角色对象
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
//表达多对多
private Set users = new HashSet();
}
<hibernate-mapping package="com.hero.pojo" >
<class name="Role" table="sys_role" >
<id name="role_id" >
<generator class="native">generator>
id>
<property name="role_name" >property>
<property name="role_memo" >property>
<set name="users" table="sys_user_role" inverse="true" >
<key column="role_id" >key>
<many-to-many class="User" column="user_id" >many-to-many>
set>
class>
hibernate-mapping>
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private Character user_state;
//表达多对多
private Set roles = new HashSet();
}
<hibernate-mapping package="com.hero.pojo" >
<class name="User" table="sys_user" >
<id name="user_id" >
<generator class="native">generator>
id>
<property name="user_code" >property>
<property name="user_name" >property>
<property name="user_password" >property>
<property name="user_state" >property>
<set name="roles" table="sys_user_role" cascade="save-update" >
<key column="user_id" >key>
<many-to-many class="Role" column="role_id" >many-to-many>
set>
class>
hibernate-mapping>
操作和一对多是一样的
//这个代码出现了报错
//在配置的时候,没有配置inverse属性
//所以默认是都维护外键
//在一对多的时候,双方维护外键
//先建立主表,然后建立从表,从表顺便维护外键,在建立从表的时候写好外键数据
//然后主表维护外键,把对于的从表的外键修改成目标数据
//但是多对多
//双方都会维护中间表
//user表建立插入数据,role表建立插入数据,中间表建立
//user维护主键,让中间表插入数据
//role表维护主键,让中间表插入数据
//这样主键就冲突了
User user1 = new User();
User user2 = new User();
Role role1 = new Role();
Role role2 = new Role();
user1.setUser_name("李彦宏");
user2.setUser_name("麻花藤");
role1.setRole_name("保安");
role2.setRole_name("保镖");
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role1);
user2.getRoles().add(role2);
role1.getUsers().add(user1);
role1.getUsers().add(user2);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
//-------------------------------------------------
//4提交事务
tx.commit();
解决办法1:java代码少些一半,不写
role1.getUsers().add(user1);
role1.getUsers().add(user2);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
这样只有一方维护外键了
解决办法2:inverse
写上面的java代码,但是配置中让某一方放弃维护
//为郝强勇新增一个角色
//3操作
//1> 获得郝强勇用户
User user = session.get(User.class, 1l);
//2> 创建公关角色
Role r = new Role();
r.setRole_name("男公关");
//3> 将角色添加到用户中
user.getRoles().add(r);
//在user中配置级联,那么就不用下面的保存角色代码了
//4> 将角色转换为持久化
//session.save(r);
//-------------------------------------------------
//4提交事务
//为郝强勇解除一个角色
//3操作
//1> 获得郝强勇用户
User user = session.get(User.class, 1l);
//2> 获得要操作的角色对象(保洁,保安)
Role r1 = session.get(Role.class, 1l);
Role r2 = session.get(Role.class, 2l);
//3> 将角色从用户的角色集合中移除
user.getRoles().remove(r1);
user.getRoles().remove(r2);
//-------------------------------------------------
//4提交事务
查询
五种查询:
1.oid查询 : get (customer.class,1L) 根据主键
2.对象属性导航查询 :根据customer对象,通过getLinkMan()方法来查询联系人
3:HQL
4:criteria
5:原生态SQL
前两种太简单了,SQL也不用讲
//如果没有重复的类名,可以省略包名
String hql = "from Customer";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
System.out.println(list);
//查询所有表,没什么卵用,还可能死机
String hql = "from java.lang.Object";
//不可以出现数据库表的字段,必须是类中的属性字段
//根据cust_id排序
String hql = "from Customer order by cust_id asc ";
String hql2 = "from Customer order by cust_id desc ";
//统计查询
String hql = "select count(*) from Customer ";
String hql2 = "select avg(cust_id) from Customer ";
String hql3 = "select sum(cust_id) from Customer ";
String hql4 = "select max(cust_id) from Customer ";
String hql5 = "select min(cust_id) from Customer ";
String hql = "select cust_id from Customer ";
查询出的结果是List<string>
String hql = "select cust_id,cust_name from Customer ";
查询出的结果是List<Object[]>
//你不想用List
//这个时候一定要有构造器Customer(cust_id,cust_name){}
//同时还要有空参构造器
String hql = "select new Customer(cust_id,cust_name) from Customer ";
hql多表查询,HQL的语句进行多表查询用的比较少,因为语法比较诡异
//学习HQL语法(不常用) - 多表查询语法
public class Demo2 {
//回顾-原生SQL
// 交叉连接-笛卡尔积(避免)
// select * from A,B
// 内连接
// |-隐式内连接
// select * from A,B where b.aid = a.id
// |-显式内连接
// select * from A inner join B on b.aid = a.id
// 外连接
// |- 左外
// select * from A left [outer] join B on b.aid = a.id
// |- 右外
// select * from A right [outer] join B on b.aid = a.id
//---------------------------------------------------------------------
//HQL的多表查询
//内连接(迫切)
//外连接
// |-左外(迫切)
// |-右外(迫切)
@Test
//HQL 内连接 => 将连接的两端对象分别返回.放到数组中.
public void fun1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
String hql = " from Customer c inner join c.linkMens ";
Query query = session.createQuery(hql);
List
//排序
Criteria criteria = session.createCriteria(Customer.class);
//criteria.addOrder(Order.asc(""));
criteria.addOrder(Order.desc("cust_id"));
List list = criteria.list();
离线查询
1.类级别查询(单表查询,查询一个类)
懒加载|延迟加载
get没有策略
load应用类级别的加载策略,默认是懒加载
使用对象的时候session必须是没有被关闭的
建议使用load
//get方法,是执行后立即执行SQL语句
Customer c = session.get(Customer.class,2L);
//get不具有懒加载的功能
//load方法的作用是和get一样的,但是他是延迟加载的
Customer c = session.load(Customer.class,2L);
//在使用到对象的时候才会打印SQL语句
syso(c)
// 是否对类进行延迟加载: 可以通过在class元素上配置lazy属性来控制.
//lazy:true 加载时,不查询.使用时才查询b(默认是true)
//lazy:false 加载时立即查询.
//如果在session关闭后才使用对象,就会空指针
2.关联级别查询
集合策略,根据customer取linkman,早customer中配置
//集合级别的关联
Customer c = session.get(Customer.class, 2l);
Set linkMens = c.getLinkMens();//关联级别
System.out.println(linkMens);
<class name="Customer" table="cst_customer" lazy="false" >
<id name="cust_id" >
<generator class="native">generator>
id>
<property name="cust_name" column="cust_name" >property>
<property name="cust_source" column="cust_source" >property>
<property name="cust_industry" column="cust_industry" >property>
<property name="cust_level" column="cust_level" >property>
<property name="cust_linkman" column="cust_linkman" >property>
<property name="cust_phone" column="cust_phone" >property>
<property name="cust_mobile" column="cust_mobile" >property>
<set name="linkMens" lazy="" fetch="" batch-size="3" >
<key column="lkm_cust_id" >key>
<one-to-many class="LinkMan" />
set>
class>
//默认就是这种方式
//集合级别的关联
//fetch:select 单表查询
//lazy:true 使用时才加载集合数据.
Customer c = session.get(Customer.class, 2l);
Set linkMens = c.getLinkMens();//关联级别
System.out.println(linkMens);
///集合级别的关联
//fetch:select 单表查询
//lazy:extra 极其懒惰.与懒加载效果基本一致. 如果只获得集合的size.只查询集合的size(count语句)
Customer c = session.get(Customer.class, 2l);
Set linkMens = c.getLinkMens(); //关联级别
System.out.println(linkMens.size());
System.out.println(linkMens);
//集合级别的关联
//fetch:join 多表查询,一次性多个表全部查,所以lazy失效
//lazy:true|false|extra 失效.立即加载
Customer c = session.get(Customer.class, 2l);
Set linkMens = c.getLinkMens();//关联级别
System.out.println(linkMens.size());
System.out.println(linkMens);
//fetch: subselect 子查询
//lazy: true 懒加载
String hql = "from Customer";
Query query = session.createQuery(hql);
List list = query.list();
for(Customer c:list){
System.out.println(c);
System.out.println(c.getLinkMens().size());
System.out.println(c.getLinkMens());
}
//fetch: subselect 子查询
//lazy: false 立即加载
String hql = "from Customer";
Query query = session.createQuery(hql);
List list = query.list();
for(Customer c:list){
System.out.println(c);
System.out.println(c.getLinkMens().size());
System.out.println(c.getLinkMens());
}
//fetch: subselect 子查询
//lazy: extra 极其懒惰
String hql = "from Customer";
Query query = session.createQuery(hql);
List list = query.list();
for(Customer c:list){
System.out.println(c);
System.out.println(c.getLinkMens().size());
System.out.println(c.getLinkMens());
}
关联属性策略
根据linkman取customer
<class name="LinkMan" table="cst_linkman" >
<id name="lkm_id" >
class="native">
id>
<property name="lkm_gender" >property>
<property name="lkm_name" >property>
<property name="lkm_phone" >property>
<property name="lkm_email" >property>
<property name="lkm_qq" >property>
<property name="lkm_mobile" >property>
<property name="lkm_memo" >property>
<property name="lkm_position" >property>
--
fetch 决定加载的sql语句
select: 使用单表查询
join : 多表查询
lazy 决定加载时机
false: 立即加载
proxy: 由customer的类级别加载策略决定.
-->
to-one name="customer" column="lkm_cust_id"
class="Customer" fetch="join" lazy="proxy" >
to-one>
class>
结论
为了提高效率,fetch的值选择select(也就是默认值)
lazy 的取值选择true(也就是默认值)
总之,不用配置
所以这里有lazy的no-session问题
如果session关闭后,才使用对象,懒加载的对象就空指针了
web层使用对象,但是dao层的session已经关闭了
解决办法:扩大session作用范围,原来是包裹service的范围,现在扩大到包裹三层
使用过滤器,包裹web层
批量抓取()
<set name="linkMens" lazy="" fetch="" batch-size="3" >
<key column="lkm_cust_id" >key>
<one-to-many class="LinkMan" />
set>
String hql = "from Customer";
Query query = session.createQuery(hql);
List list = query.list();
//查询到所有的customer,遍历出来
//每个customer对象中的集合,会一条条发送SQL(where 外键=“”)
//配置了batch-size后,就是一次性3条SQL语句发送过去
for(Customer c:list){
System.out.println(c);
System.out.println(c.getLinkMens().size());
System.out.println(c.getLinkMens());
}