起晚了,太不顺利了,车又挤又堵的,差点就迟到了
--------------------------------------
QBC也是通过Session来完成的,例如
Criteria crit = sess.createCriteria(Cat.class);
List cats = crit.list();
Query query = sess.createQuery("from Cat");
List cats = query.list();
以上两者等价。
例:
session.beginTransaction();
Criteria c = session.createCriteria(User.class);
List l = c.list();
Iterator it = l.iterator();
while(it.hasNext())
{
User u = (User)it.next();
System.out.println(u.getUsername());
}
//这就取出了所有的用户名
session.getTransaction().commit();
Criteria c = session.createCriteria(User.class);
c = c.add(Restrictions.and(Restrictions.eq("username","aa"),Restrictions.eq("password","aa")));
List l = c.list();
Iterator it = l.iterator();
迭代后就查出了用户名为aa而且密码为aa的用户
add方法添加Criterion,Restrictions的所有方法都是静态的,里面的方法都返回Criterion的具体实现子类
也就是
Criteria c = session.createCriteria(User.class);
Criterion eq = Restrictions.eq("username","aa");
Criterion eq2 = Restrictions.eq("password","aa")
c = c.add(Restrictions.and(eq,eq2));
-----------------------------------------
排序在QBC中的使用:Order
addOrder(Order asc("name")) //按照name属性来升序排列
addOrder(Property.forName("name").asc()) //和上面一样,也是按照name属性来升序排列
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.addOrder( Order.asc("name") )
.addOrder( Order.desc("age") )
.setMaxResults(50)
.list();
List cats = sess.createCriteria(Cat.class)
.add( Property.forName("name").like("F%") )
.addOrder( Property.forName("name").asc() )
.addOrder( Property.forName("age").desc() )
.setMaxResults(50)
.list();
在QBC中是不可以将两个实体类进行关联的,只能将实体类和其中的属性关联(该属性是个集合),
这将在后面的课程中详细阐明。
比如:
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%") )
.createCriteria("kittens")
.add( Restrictions.like("name", "F%") )
.list();
注意这里kittens是Cat实体类中的一个属性,且kittens是个集合
也就是找出以F开头的名字的大猫中的以F开头的名字的小猫。
--------------------------------------------
抓取策略:
有20名老师,每个老师手底下有若干个学生
有老师和学生两张表,如果要加载老师和老师手下的所有学生的话,
那么需要这么作:
select * from teachers
然后select * from students where teacher_id = ?
后面这句根据teacher_id来查询的语句总共要出现20次,因为有
20个老师。如果有n个老师的话,那么就需要有n+1条sql语句,
这就是有名的n+1查询。
如果要将所有的老师和学生用一条语句查出来的话:
用左外联的方式,因为可能会出现有的老师手底下没有学生的情况:
select * from teachers t left outer join students s
on t.id = s.teacher_id
如果转换为oracle的形式的连接语句的话,
select * from teachers, students where teachers.id = students.teacher_id(+)
FetchMode.JOIN:就是上面的连接形式加载
FetchMode.SELECT :惰性加载,就是n+1查询加载
例子:
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.setFetchMode("mate", FetchMode.EAGER)
.setFetchMode("kittens", FetchMode.EAGER)
.list();
加载猫的配偶和孩子,每只猫可能有配偶,可能有多个孩子
抓取策略的内容在后面的课程还会继续进行详细的讲解,所以这里先不用太在意这里。
-----------------------------------------
课间休息
-----------------------------------------
-------------------------------------------
QBE:
QBE是Query By Example的简写,其实也应该算是QBC的一部分。
QBE是基于示例的查询,QBE给出查询的范例,基于范例创建的查询将依据范例给出结果。
QBE的核心接口是org.hibernate.criterion.Example,方法create用于创建一个范例的实例。
如下代码:
Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.list();
将执行以下SQL:
select … from cat where (sex=‘F’ and color=‘B’)
例:
session.beginTransaction();
//第一步,创建一个样例
User u = new User();
u.setUsername("aa");
u.setPassword("aa");
Example e = Example.create(u).excludeZeroes().excludeProperty("username");
//注意这里的excludeZeroes方法排除了设置初值的情况,excludeProperty排除了setUsername,
//也就是尽管设置了username,也是无效的;当然还有其他的exclude方法
//第二步,创建criteria
Criteria c = session.createCriteria(User.class);
//第三步,将样例添加到criteria中去
c.add(e);
//按照样例查询时,是将那些不为空的属性及其值作为查询条件,
//可以使用excludeZeroes或者exludeProperty方法来排除一些特定的属性。
User uu = (User)c.uniqueResult();
session.getTransaction().commit();
---------------------------------------
老师的源代码:
//第一步,创建一个样例
User u = new User();
u.setUsername("aa");
//u.setPassword("aa");
//按样例查询时,是将那些不为空的属性及其值作为查询条件
//可以使用excludeZeroes/excludeProperty排除一些特定属性
Example e = Example.create(u)
.excludeZeroes()
.excludeProperty("password");
//第二步,创建criteria
Criteria c = session.createCriteria(User.class);
//第三步,将样例添加到criteria中
c.add(e);
User uu = (User)c.uniqueResult();
System.out.println(uu.getUsername());
--------------------------------------------------
Hibernate中的持久化对象可以是任意满足JavaBean编写规则的类,如果满足以下四点要求,会更好地在Hibernate中工作:
1、必须有一个公共的无参的构造函数
2、最好包含一个标识属性
3、最好不是final类
4、声明持久化属性及他们的getter方法和setter方法
持久化对象可继承,子类应满足条件1、2。
动态模型:
属性hibernate.default_entity_mode必须配置为dynamic-map,除此之外还可以配置为dom4j
和pojo,默认为pojo
在属性配置文件中加上 hibernate.default_entity_mode dynamic-map(也就是用一个map对应一个表)
注意dynamic-map还可以改为dom4j(用xml文件对应一个表)和pojo(用实体类对应一个表,也是我们以前一直采用的方法)
(或者在配置文件中加一条property元素也可以,name属性设为default_entity_mode)
然后在映射文件中改为 <class table="users" entity-name="user"> 因为没有使用实体类,所以不需要在class中写name属性了
也就是不再为表指明一个实体类了,让所有的表都对应到一个map上去,让map的键对应表的字段名,
值对应表中对应记录的值.这里的entity-name是很必要的,因为可能有多个映射,但是现在没有实体类与之对应了,所以应该
自己手动指定一个entityName,可以查看文档中Session中的load方法说明。
这样映射文件中的下面一系列的property元素也要进行相关的修改。
<property name="username" column="username" type="string"/>
前者相当于map中的key值,后者相当于map中的key对应的具体值,由于没有了实体类的反射机制,
这里必须加上这个type属性,而且相对的,后面的所有的字段类型都必须显式的指明,不然是无法定位类型的。
session.beginTransaction();
Map user = (Map) session.load("user", new Integer(1)); //这里的“user”注意是entity-name
System.out.println(user.get("username")); //如果运用到HQL中的话,from后面加的就是实体名entity-name
//而不是实体类名了。
session.getTransaction().commit();
也就是说hibernate的映射并不一定非要把表和一个具体的实体类相关联,可以和一个map相关联(这样就省得创建实体类了),
也可以和一个xml文件相关联。
session.beginTransaction();
Map user = new HashMap();
user.put("username","java");
user.put("password","java");
session.save("user",user); //第一个"user"是实体名entity-name
要存进去或是更新等操作的话,记住一定指定entity-name!!!!
这里看一看Oracle的主键设置:
必须:<generator class="sequence">
<param name="sequence">users_seq</param> //这里需要创建oracle数据表的序列,名为users_seq
<generator>
注意这里使用了Oracle的驱动方言,所以对应的要使用Oracle的数据库
如果没有主键生成器的话也是可以的,这时插入操作就必须设置主键的值,有主键生成器的话在插入操作前设置主键
是没有意义的!
我们常用的是identity和sequence两种主键生成器!
还有increment,它也是递增,但是不解决并发问题(是程序来控制递增),也就是先到数据库中找主键的最大值,然后
再把主键加1后插进去。
identity是数据库控制的自增,可以解决并发问题
还有native自动选取。
hilo高低位算法生成一个主键
uuid通过网卡ip地址来定位一个字符串存成一个主键
--------------------------------------------------------
上午课程总结:
1 QBC :
Criteria来创建查询的范围(即从哪些类中来插,代表的是from语句),
用Restrictions的静态方法来创建Criterion查询条件
Criterion代表查询条件(也就是where语句)
Order.asc或者Order.desc代表排序的order by
Property代表一个具体的属性,可以通过它来执行组函数。
2 QBE
Example,创建时调用Example.create方法。
Hibernate根据样例中不为空的属性(即不等于null)来设定查询条件,所以
可以通过Example.excludeZeroes来排除为0的属性或者Example.excludeProperty
来排除指定的属性名。
3 实体的三种模式
(1)POJO,要求必须要有一个实体javaBean来对应一张具体的表
(2)dynamic-map,使用Map来映射所有的表,要求为每个实体都起一个名字,就是要为属性entity-name设置值。
(3)dom4j,目前还不支持,主要是用xml文件映射一个表
4 主键生成器
(1)主键生成器的作用
(2)各种类型的主键生成器有什么区别?会使用identity/sequence就可以了。
---------------------------------------------------------------------------------------------------------
PowerDesigner的使用:
1 创建概念模型,首先要找出实体,然后再确定实体之间的关系
2 生成报告、交给负责人认可
3 生成物理模型
4 建立数据库连接
5 导入数据库
-------------------------------
数据建模技术:
数据模型:数据库系统中关于数据和联系的逻辑组织的形式表示。
层次模型、网状模型和关系模型三种,现在应用最广泛的是关系模型。
关系模型与面向对象思想不一致,因此有了ORM来解决表和对象之间的关系。
数据库模式就是数据库结构,确定数据库模式是数据库建模的最重要任务
模式分为逻辑模式、外模式和内模式,实际上可以分别对应到表、视图和索引
模式在英文中是schema
模式:也叫作逻辑模式,是数据库中全体数据的逻辑结构和特征的描述,是所有
用户的公共数据视图。
外模式:是数据库用户能够看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图
是与某应用有关的数据的逻辑表示。
内模式:是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。
外模式也叫作子模式或者用户模式,内模式也叫作存储模式。
数据库建模就是确定数据库结构的过程,也就是定义数据库模式的过程。
将现实世界中的事物以及他们之间的联系抽象出来,并且以某种组织方式存储在数据库中。
这种组织方式就是数据库结构。
现实世界中的事物在数据库设计中称为实体,而事物与事物之间的联系叫做关系。
网上购物,业务流程是什么?有哪些事物呢?哪些事物需要持久化?哪些不需要?
数据库建模方法:1 ER图 2 对象定义语言(ODL:Object Defination Language)
矩形表示实体,椭圆表示属性,菱形表示关系
先有一个思路,然后画出ER图,确定好关系,然后导入关系型数据库中。
--------------------------------
数据库范式:
一范式:数据库表中不存在重复字段,并且字段不可分割
二范式:不存在非主键字段对任一主键字段的部分依赖关系(用来约束联合主键)
一个爸爸和一个妈妈决定了一个孩子;一个妈妈决定了一个孩子就是不符合第二范式
假如必须有两个主键但是你只设了一个主键的话,那么不符合第二范式
三范式:不存在非主键对任一主键的传递依赖关系。
由a决定b,b决定c,但是没有a直接去决定c,就是传递依赖
BC范式:
任何字段都不存在传递函数依赖,即主键对主键没有传递依赖。
第一范式就不说了,只要是个合法的表都满足第一范式,但是假如有个地址的字段,里面包含
国、省份、市、地区的话,可以通过设置外键,或是分解字段的方法来解决。
二范式主要规范联合主键情况:要求非主键字段不能由符合主键的一个完全决定,而必须由符合主键共同决定!
只要没有使用联合主键,肯定不会出现违反第二范式的情况!
例:学生选课表的设计应该如何实现?
假设选课关系表为学号、姓名、年龄、课程名称、乘积、学分。
那么这个表里面的主键应该为学号和课程名称联合作为主键,这是毫无疑问的,但是不符合第二范式:因为姓名
可以由学号完全决定,和课程名称没有任何关系,也就是说姓名这个非主键字段对这个联合主键有部分依赖关系存在。
同理,学分完全由课程名称来决定,也是部分依赖的。
成绩是不存在部分依赖的,是由学号和课程名称共同决定的
所以这个表是不满足第二范式的,危害如下:
1 数据冗余
2 更新异常,若调整了课程的学分,那么每条记录都要调整
3 删除异常,假如要删一个学生,那么他选的课也跟着丢了,要是这门课没有别人选的话,该课程的信息就永远的丢失了
4 插入异常,假如新来了一门课程,但是没有人选,试问这怎么插入呢?没办法弄……
解决不满足第二范式情况的办法是分解主键
建立学生表(学号,姓名,年龄)课程表(课程名称、学分)和选课关系(学号,课程名称,成绩)
一般认为,所有单关键字的数据库表都符合第二范式,因为不可能存在组合关键字
满足第二范式的设计肯定满足第一范式的要求!
下面说说第三范式:
要求不存在非关键字段对任一候选关键字段的传递函数依赖关系,其实,就是不能出现非主键字段决定其他非主键字段!
关键字段决定了非关键字段x,而x又决定了另外一个非关键字段y,这就不满足第三范式!
假设须生关系表(学号,姓名,年龄,所在班级,教室编号,班级人数)
主键是学号
学号确定了其余的字段,但是呢,所在班级直接决定了教室编号和班级人数,这就是典型的传递依赖,不满足第三范式
解决方法:
分解实体:学生(学号,姓名,年龄,所在班级)
学院(班级,地点,人数)
两者之间用主外键关系联系起来,二者是一对多的关系。
BC范式:主键也不可以有传递依赖关系。
例:
假如一个表(班号,课程号,老师号,课程时间)
那么课程号和班号唯一决定是课程时间
而且课程号和老师号也可以决定课程时间
但是呢,班号决定了老师号,这就是说主键存在传递依赖。
解决方法:分解关系
班级号,课程号,课程时间
班级号,老师号
建立成上面两个关系表就ok了
总的来说,各个范式都是在尽力去分解,不把数据都存在一个表中。
应该尽可能的去满足范式的要求!
在性能的要求下,也并非一定要严格遵从范式要求,以适当的数据冗余来提升性能也是一个很好的选择。
怎么在数据库中的表中表示关系:
关系种类:
一对一,多对多,一对多,多对一
怎么在数据库中的表里面表示上面这四种关系??
可以通过外键方式;还可以通过主键对应方式,比如学生和电脑的一对一的关系可以通过
让学生的主键和对应电脑的主键一致来做到,其中必然有一个主键是主动变化的,而另外一个
主键是跟随这这个主键来变化
还有可以通过再建立一个关系表的方式,这个关系表中就有两个主键,一个是电脑,一个是学生
将他们两个关联起来,在学生表和电脑表中都不考虑关系的问题,全部让关系表去考虑
一对多或是多对一的关系里面,用多的那一端来存放外键,还可以用关系表方式。
多对多的关系只能用关系表来解决了,没别的办法了。
因此一对一有三种方式:主键方式,外键方式和关系表方式
一对多有两种方式:外键和关系表方式
多对多只有关系表方式
hibernate中强烈建议使用关系表,这样把对象和关系分离开来,好处理。
-----------------------------------------
学生、课程、老师、班级这四个实体的关系把它们弄清楚!