ctrl+1
ctrl+t
在配置文件中hibernate这个前缀可以省略不写
如:<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
可写为<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
当我们的类名或属性名与数据库中的关键字冲突时,我们可以修改表中的字段名,也可以在映射文件
中加上反引号(`)在tab键上方,这时会当作字符串处理;或修改对应的表名称
如:在oracle中user是一个关键字
<class name="User" table="`user`"> 或 <class name="User" table="tuser">
<property name="name" column="tname"/> 如这种
</class>
在配置文件中如果没有指定table、column则hibernate会按默认执行,即表名与类名相同,字段名
与属性名相同.
如果要求不允许有相同的name,则可以加上: unique="true"如下
<property name="name" unique="true"/>
对于下面这句代码
User user = (User) session.get(User.class, id);
我们可以这样理解
由于Session可以管理多个数据库表所对应的多个实体对象,如果查询id为1的实体对象,
Session.get方法需要知道从哪个数据库表中查询id为1的记录,所以,除了给get方法传递所
要查询的实体对象的id值外,还必须给get方法传递实体对象的类型,get方法才能知道去哪个
数据库表中进行查询
通过学习,我们可以发现通过session去查询数据库有很大的局限性,它只能通过id去查询,而
在现实使用中,我们的需求肯定不只这些.这时我们就需要通过hql完成查询,hql是通过query创建
的:Query query = session.createQuery(hql);
以往的sql是查表,而这里的hql是查询对象
还有一种比hql更方便的查询方式:Criteria,这也是由session创建的:
Criteria crit = session.createCriteria(Class clazz);
使用 命名参数 替换?
如:String hql = "from User as user where user.name=?";
query = session.createQuery(hql);
query.setString(0, name);//下标从0开始,跟jdbc不同
可通过命名参数修改为
String hql = "from User as user where user.name=:name";需要加上一个冒号
query = session.createQuery(hql);
query.setString(name, "xyls");
这样做就可以避免因为失误造成错误
实现分页
query.setFirstResult(0);//从哪一条开始取
query.setMaxResults(10);//取多少条记录
好处:跨数据库,可移植,不论用哪一种数据库,都可以通过此种方式,hibernate中通过方言类生成分页语句
oracle用rowNormal
mysql用limit
sqlserver用top
要注意单向关联与双向关联的关系
多对多关系(如:teacher-student),在操作和性能方面都不太理想,所以多对多的映射使用较少,
实际使用中最好转换成一对多的对象模型,Hibernate会为我们创建中间关联表,转换成两个一对多的关系.
多对一的关系使用的最多
在学习Hibernate如何处理对象之间的关联关系的底层细节时,可以从两个方面去考虑:
.如何将对象之间的关联关系保存到数据库中
.如何检索出关联的对象
List存储是有序的,而Set是无序的
<set name="emps">
<key column="depart_id"/>
<one-to-many class="Employee"/>
</set>
<list name="emps">
<key column="depart_id"/>
<!-- 下面这列不需要程序代码与之对应,这是hibernate的需要 ,进行排序-->
<list-index column="order_col"/>
<one-to-many class="Employee"/>
</list>
bag标签与list是相对应的,使用bag将不会进行排序了,可用下面的代码替换上面的
表结构中不会多出order_col这一列
<bag name="emps">
<key column="depart_id"/>
<one-to-many class="Employee"/>
</bag>
下面是使用Map的形式
<map name="emps">
<key column="depart_id"/>
<map-key type="string" column="name"/>
<one-to-many class="Employee"/>
</map>
下面是使用数组的形式,数组存储也是有序的,使用很少
<array name="emps">
<key column="depart_id"/>
<index column="array_col"/>
<one-to-many class="Employee"/>
</array>
我们在hibernate中常使用Set
List集合类型在有些一对多关联关系中可能会很有用,例如:在论坛的版面管理中,将会涉及到
版面的上移/下移等操作,这就需要在版面集合中维护顺序,用List集合类型就能很好的解决这个问题.
hibernate为了完成懒加载的功能,将所有的集合类都重写了一遍,如果我们进行强制类型转换,
运行时会报异常.
***级联(cascade)和关系维护(inverse):
hibernate默认对关联属性不进行实际的操作,通过配置级联可以实现
级联cascade:用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似的操作
一般对 多对一,多对多不设置级联,在一对一,一对多中设置级联
如:<set name="emps" cascade="save-update">//cascade有很多可选用的值
<key column="depart_id"/>
<one-to-many class="Employee"/>
</set>
**hibernate缺省情况下是维护关联关系的inverse="false" **
inverse:是否放弃维护关联关系(在java中两个对象产生关联关系时,对数据库表的影响),
在一对多和多对多的集合定义中使用,inverst="true"表示该对象不维护关联关系,该属性的值一般在
使用有序集合时设置成false(hibernate缺省值是false).
一对多维护关联关系就是更新外键,
多对多维护关联关系就是在中间表中增删记录.(两端都告诉,会报异常,可通过放弃关系维护避免)
注:配置成一对一的对象不维护关联关系
inverse属性只会在集合中出现,如Set,List,array,Map,不同于cascade
如:<set name="emps" inverse="true">//效率会更高一些,不会产生update语句,一端不会考虑多端
<key column="depart_id"/>
<one-to-many class="Employee"/>
</set>
注:inverse不允许在有序的集合中使用,如:List,数组等 因为inverse端放弃维护关联关系,有序集合
就不会再去记忆插入进来的数据的顺序
hibernate不允许多的一端放弃维护关联关系
继承关系映射:
在一张表中实现
<discriminator column="type" type="int"/>//鉴别器,用来区别不同的子类,应放在id属性下面
type="string"是默认的
如:<subclass name="Skiller" discriminator-value="1">
<property name="skill"/>
</subclass>
<subclass name="Sales" discriminator-value="2">
<property name="sell"/>
</subclass>
discriminator-value="*"用来区分
特有的字段不能加上非空约束
每个子类对应一张表,效率低,但是在关系模型上更合理
<joined-subclass name="Skiller" table="skiller">
<key column="emp_id"/>
<property name="skill"/>
</joined-subclass>
<joined-subclass name="Sales" table="sales">
<key column="emp_id"/>
<property name="sell"/>
</joined-subclass>
另一种情况:还需要鉴别器,单独一张表处理sales,效率得到了提升
<discriminator column="type" type="int"/>
<subclass name="Skiller" discriminator-value="1">
<property name="skill"/>
</subclass>
<subclass name="Sales" discriminator-value="2">
<join table="sales">
<key column="emp_id"/>
<property name="sell"/>
</join>
</subclass>
如果有异常,可以通过删除数据库完成操作,因为之前会有三张表
每个类独立映射:不再提取公共类,不需要关联查询,每个具体类一张表
(混全使用"一个类继承体系一张表"和"每个子类一张表"),需要更换主键生成策略hilo,不再需
要鉴别器,操作时报异常,需要删除相关表,或删除数据库,重建
如果主表是抽象的,加一个属性abstract="true",就不会产生Employee表了
<id name="id">
<generator class="hilo"/>
</id>
<union-subclass name="Skiller" table="skiller">
<property name="skill"/>
</union-subclass>
<union-subclass name="Sales" table="sales">
<property name="sell"/>
</union-subclass>
注意一条原则:表的数目不要超过类的数目,表越多关联查询就越多,效率就越低