13 hibernate核心java
表和表的关系:mysql
常见有7中关系:sql
单项关系一下四种 数据库
1-1 外键1-1,主键1-1的关系缓存
1-n服务器
n-1session
n-noracle
多项关系:互相使用;框架
1-1eclipse
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继续查询