13 hibernate核心
表和表的关系:
常见有7中关系:
单项关系一下四种
1-1 外键1-1,主键1-1的关系
1-n
n-1
n-n
多项关系:互相使用;
1-1
1-n(n-1)
n-n
以下有两个表,user_info、和login连个表。表和字段如下;
User_info
Uid truename phone sex
Longin
Lid longinname password uid
这里建立了user类和longin类,同事new了user
User表中不含login字段,但是longin表中有user_info字段,但是在login的类中加入了user应用;
注:a在单项外键1-1中第一个表的主键是另外一个表的外键,所以在另外一个表里,这个外键不受约束可以随便写。为了达到主外键一一对应就用到unique写法如下
<many-to-one name="user" column="uid" not-null="true" class="User" unique="true" cascade="all">
</many-to-one>当把配置文件和类写好就可以自动生成数据库连接表了;
保存的时候:这里先将user先存入进去,因为只有主键先获得持久化才能跟其他表有关系;注意外键配置时候必须不能为空;也就是说user_info是父表,另外的表longin为子表,但查询的时候必须先查询子表,也就是login表,因为user_info表中没有login表中的属性,但login表中有user_info的应用:
//这里只保存了一个关联表被关联的不保存一般会报错,但是有这样的配置就会保存一个表:级联(如:两表通过 id字段建立一对一关系,同时选项上了“实施参照完整性”“级联更新相关字段”“级联删除相关记录”,目的是实现,当在employee建立新用户时,同时自动在user_right表中给其建立相应的权力记录,但我发现如在employee中新增一个用户时,user_right并没有同步增加一条记录,但是在employee中删除一个用户时,user_right中却会同步更新!):cascade(级联)="all"它将配置的关联和被关联的对象共存亡;
多项外键1-1:其它不变就是对象的模型变了,在user表中加入(表名)longin对象字段,也就是双向包含,所以在user配置中加入了<one-to-one name="login"class="Login"property-ref(表示关联对方的属性)="user"></one-to-one>这样保存数据顺序和上一致,但是查询可以是反向和正向,有利于查询
b共享主键关联:可以是主键名不一样,但主键值必须一样,也就是关系模型有变化,对象模型则不会变化;
1-1的单项共享主键关联:主键在longin中,所以先创建longin在创建user
1-1的双项共享主键关联:保存的时候以login的主键为主,所以先保存login:查询则无所谓;
单项n-1:先保存有主键的对象在保存无主见的对象;<many - to-one></many-to-one>,连个表字段:
T_room user
Id idname 1— ---- n id username rooomid
双项n-1:数据库不变,只是变对象用到private Set<User> users;,一个循环语句for(User user:users)
单项1-n:主控权放在1的上面,而n-1主控权在n的一方,所以在1的一方加上引用
room 1-------- n user
双项1-n:就是在在n的一方加上引用,在user方加上<many -to-one>
注:在1掌控的时候,会发送多余的sql语句(update),所以效率就下降了,所以可以在配置文件中加入inverse=true反转(就是将主控权交给多的一方,false的话就是自己掌控),这时候注意的是操作数据只能从n的一方去操作;而有n掌控时候就不会发多余的;
n-n的关系:实现的时候需要一个中间表,中间表中有连个字段,它们就是联合主键(联合主键就是这个表里字段值不能一样的,两个字段加起来做一个主键),保存的时候先保存无set的那个对象;映射是<many -to- many>.
在双项多对多中要从两个对象中分别查询的话配置xml文件是一样的;(也就是<set>配置)
集合映射:中的例子映射,一般用set设置的值不会有顺序的。而用list设置的值就会有顺序的(这里的list是个接口,不能是arrylist,但是new的时候就得是arrylist),同样的也要修改配置文件
继承映射:将对象的映射关系在表里面体现出来
(1)每个类分层结构一张表:一个父类不管他有多少子类都将他们与父类数据放入一张表中;
也就是整个树一张表,subclass代表子类它的名字与类名绑定的,discriminator是个鉴别器这里的type就是鉴别器,是用来识别数据类型的一个字段,
例子如下:父类是persion,两个子类是student和work
Id name age school factory type
1 aaa 55 qinghua s
2 bbb 22 shuoshuodian w
有这张表体可以看出只有学校和工厂才能分清楚他们是什么人,在配置文件中不能加不能为空的判断,这样也有问题,应为的字段可以空,就没有意义
(2)每个子类一张表,对象模型不变,也就是类代码不变,只需修改配置文件(数据模型)
和以上的类一样所以就做三张表,
T_person
Id name age sex
T_student
Id school pid
T_work
Id factory pid
说明:这里的pid是外键就是person的id字段不同但值相同(也可以去掉pid用共享主键来达到要求)这里所用就是共享主键,从建表看,生成了第三个表达到结果:可以加不能为空的配置
(3)每个具体的类一张表;对象模型还是不变,变的还是数据库
例子如下:建立三张表
T_pserson
T_studnet
Id name age school
T_factory
Id name age factory
说明:这俩个子表的id不能相同 ,用到联合子类,这里产生了person表,但是是空的为了 不让这个表产生可以用abstract =true;这里假如加了不能为空的话,就不能手动的向表中插入数据了;
-----------------------------------------------------------------------------------------------------------------
HQL讲解:
语法:1.实体查询
String hql = " from TUser";
执行这条语句会返回TUser以及TUser子类的纪录。
注: 如果 TUser 类具有外键, 查询会报错!
解决方法: select 别名。属性 from 类 as 别名。 没有别名。属性仍然报错!
hql = "from java.lang.Object"
会返回数据库中所有库表的纪录。
where 语句
hql = "from TUser as user where user.name='yyy'";
其中,as可以省略也一样
hql = "from TUser user where user.name='yyy'";
where子句中,我们可以通过比较运算符设定条件,如:=, <>, >, <, >=, <=, between, not between, in, not in, is,like等。
2.属性查询
List list = session.createQuery("select user.name, user.age from TUser as user").list();
还可以在HQL中动态构造对象实例的方法,将数据封装。
List list = session.createQuery("select new TUser(user.name, user.age) from TUser as user").list();
Iterator it = list.iterator();
while(it.hasNext() ) {
TUser user = (TUser)it.next();
System.out.println(user.getName());
}
但是要注意这里的TUser对象只是对name和age属性的封装,其他状态均未赋值,所以不能用它来进行更新操作。
也可以在HQL的Select子句中使用统计函数
"select count(*) ,min(user.age) from TUser as user"
也可以使用distinct关键字来删除重复纪录。
select distinct user.name from TUser as user;
3.实体的更新与删除
hibernate 2中需要先查询出实体,设置属性后再保存。
hibernate 3中,提供了更灵活的方式(bulk delete/update)
更新:
Query query = session.createQuery("update TUser set age=18 where id=1");
query.executeUpdate();
删除:
session.createQuery("delete TUser where age>=18");
query.executeUpdate();
4.分组与排序
Order by子句:
from TUser user order by user.name, user.age desc
Group by子句和Having子句
"select count(user), user.age from TUser user group by user.age having count(user)>10"
5.参数绑定
通过顺序占位符?来填充参数:
1)hibernate 2 中通过session.find方法来填充
session.find("from TUser user where user.name=?", "Erica", Hibernate.STRING);
多个参数的情况:
Object[] args = new Object[] {"Erica", new Integer(20)};
Type[] types = new Type{Hibernate.STRING, Hibernate.INTEGER};
session.find("from TUser user where user.name=? and user.age=?", args, types);
2)通过Query接口进行参数填充:
Query query = session.createQuery("from TUser user where user.name=? and user.age>?");
query.setString(0,"Erica");
query.setInteger(1, 20);
通过引用占位符来填充参数:
String hql = "from TUser where name=:name";
Query query = session.createQuery(hql);
query.setParameter("name","Erica");
甚至可以将查询条件封装为一个
class UserQuery {
private String name;
private Integer age;
//getter and setter
}
String hql = "from TUser where name=:name and age=:age";
Query query = session.createQuery(hql);
UserQuery uq = new UserQuery();
uq.setName("Erica");
uq.setAge(new Integer(20));
query.setProperties(uq); //会调用里面的getter?
query.iterate();
6.联合查询
也可以使用 inner join,left outer join, right out join, full join
排列组合:form TUser, TAddress
事实上sql和hql除了语法上相似外,差别很大,完全不是一个概念.这里所操作的都是对象的属性;sql是关系数据库查询语言,面对的数据库;而hql是Hibernate这样的数据库持久化框架提供的内置查询语言,虽然他们的目的都是为了从数据库查询需要的数据,但sql操作的是数据库表和字段,而作为面向对象的hql操作的则是持久化类及其属性。hql语句执行后的结果都是对象;
以oracle的案例数据库来讲解;分别有三个脚本语句文件,将三个脚本文件打开粘贴到oracle中,在dos下按命令User\sqlplus scott to tiger 接着把sql脚本拷贝运行,也就是案 例数据库,分别是创建数据、添加数据、删除冗余数据。
1 Hibernian中的column属性:们声明从JavaBean的id属性到表的id列的映射. property和Hibernate column属性都有相同的值,我们本来可以忽略Hibernate column属性,但是为了清晰起见,我们还是把column列出来. 是个特殊的标 签.它被用来声明表的主键
2在myclipse中可以自动的生成Hibernian配置文件但是手动导包的时候他不会把log4j property文件导入,需要我们自己去导入,还要在myeclipse中手动导入junit组件
3这种写法:也可以是一种循环for(Object obj:list): 这是一种新的循环遍历集合的方式,冒号前边定义变量,代表集合中当前操作的元素,它的类型是集合中元素的类型,在循环体中直接用。
冒号后边就是一个集合。这种写法比较简单,易于理解。
4当现有表后又文件的时候hql读取表的时候出现的CGLIB错误说明数据表中的字段为空了,必须赋值
5写Hql语句的时候可以使用myclipse中的HQL编辑器他可以将hql语句自动翻译为sql语句,但是有时候这个编辑器会报错打不开,就要看看工作路径下…data文件的配置,看的是configfile的配置路径和是否能够找到session工厂,还有就是映射文件不能错;
6 hql支持查询对象的别名打点,就可以实现多表查询,还支持左右链接和内联。
7数据表达链接方式:左外链接,右外连接,内连接,全连接
左外链接:把左边的那个表中不符合条件的字段查出来,右外连接一样
内连接:发送等值链接条件
全连接:左右都不符合条件的值都显示出来
这里的简写id就是对象中的持久化标识,就是配置文件中<id>标签中name的值
With可以在join后面设置条件,createQuery发出的是hql语句,
支持:子查询+聚集函数,分组查询(分组查询用having加条件:)
8 ROWNUM 是sql中的函数:限制返回数据的条数(类似游标工作)系统任务这样的函数起始值是1
所以rownum>某个数字或rownum = 非数字都是 不合法的:但是 可以用rownum<=某个数字
HQL中有这个函数但是没有此功能。用这个也就是查询最大的几个数据,所以也叫TOP n 方法
Hibernate中的缓存 一级缓存:session(进程)级别(list和ireator查询缓存都在)不关闭session的话一直都存在
二级缓存:sessionfactory应用中,是服务器级别的 ,只要网站不关闭就一直存在,一般会在里面放一些不重要的东西
用cout(*)的时候在hibernate中返回的一定是integer和long版本不同也会不同的
原生SQL(netive SQL):
就是像mysql 、oracle等自己的一些特性就称作原生sql
二级缓存: 只需要查一次数据库,在次操作数据不用去查询了,它会首先找缓存,看看有没有,如果有就直接用,没有的时候在去查!
在hibernate中用的都是EHCache,不支持集群,Hibernate的二级缓存是应用服务器级别的,他的最大的好处就是跨session的,把一些不时常用不到的数据放到session中
还有一些如SwarmCache和JBoss TreeCache都是企业级的分布式的
配置二级缓存:1首先在hibernate.cfg.xml中的配置
<property name="cache.use_second_level_cache">true</property> //开启缓存
<propertyname="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>//缓存提供商
2上述就配置提供了缓存,还要在相应的表中配置缓存
<cache usage="read-only"/>
3.当这里启用了EHcache的时候就要导入ehcache.xml文件(在hibernate-3.2\etc的包中)这样就不会报错,里面有相应的配置
4 解释:当查询的时候先从一级缓存中查,然后从二级缓存中查询,如果都查不到的话就会发sql继续查询