关闭

hibernate笔记

669人阅读 评论(0) 收藏 举报

●参考位置
1)文档
2)例子程序  \project\etc\hibernate.properties

●hibernate初理解
将面向关系的sql语句进行封装,成为面向对象的写法,
完成增删改查。
Object Relationship mapping  关系映射
hibernate帮我们屏蔽了relationship关系这层的逻辑,
我们只用采用面向对象的写法就可以。

●资源下载
1)slf4j
2)hibernate-distribution

●第一个小实验
1)建立项目引入jar包
·hibernate-distribution-3.6.2.Final-dist\hibernate-distribution-3.6.2.Final\hibernate3.jar
·hibernate-distribution-3.6.2.Final-dist\hibernate-distribution-3.6.2.Final
  \lib\required\目录下所有jar包
·hibernate-distribution-3.6.2.Final-dist\hibernate-distribution-3.6.2.Final
  \lib\jpa目录下的包
·slf4j-1.6.1\slf4j-1.6.1\slf4j-nop-1.6.1.jar
·jdbc mysql驱动包

2)建立数据库表
create database hibernate;
use hibernate;
create table student(id int primary key, name varchar(20),age int);

3)建立student类(与数据库里的类对应)
  student类中要么不要有构造方法,要么必须有公共的无参构造方法因为hibernate要调
4)建立配置文件hibernate.cfg.xml  hibernate-distribution-3.6.2.Final\project\etc中可查
从参考文档中copy,在参考手册中的3.8. XML 配置文件文中有.
在src根目录建立hibernate.cfg.xml将内容粘贴。
修改对应配置
connection.driver_class 为com.mysql.jdbc.Driver
connection.url          为 jdbc:mysql://localhost/hibernate
connection.username     为 root
connection.password     为 root
由于我们很少用hibernate的连接池 所以注释掉
<!--  <property name="connection.pool_size">1</property> -->
这项为定义hibernate将语句转换为哪个数据库的方言
dialect                 为 org.hibernate.dialect.MySQLDialect
current_session_context_class
                    暂时不讲3.2新加的
cache.provider_class为二级缓存 优化 留着
show_sql            是否打印SQL语句 默认true 留着
format_sql          是否格式化的打印SQL语句 true
hbm2ddl.auto        是否让hibernate自动建表 暂时注释掉
mapping resource为com/bjsxt/hibernate/model/Student.hbm.xml 映射的路径

5)建立student的映射配置文件
这个映射文件和类放在一个包里
student.hbm.xml
继续copy 在文档中有 映射文件的基本结构 (1.1.3 映射文件)
<hibernate-mapping package="com.bjsxt.hibernate.model">属性package=类所在的包名
 <class name="Student" table="student"> name=类名 table=表名
  <id name="id" column="id"></id> name=主键成员变量名 column=主键列名
  <property name="name" column="name"> 非主键的成员变量和列
  <property name="age" column="age"></property>
  <property name="brithday"
   column="brithday" type="time"></property>
  <!--或者这么写
  <id name="id" type="int">
             <column name="id" />
              <generator class="native" />
         </id>
  <property name="name" type="java.lang.String">
              <column name="name" />    列名为name
         </property>
  -->
   
 </class>
</hibernate-mapping>

6)测试
类中
Student s = new Student();
s.setId(1);
s.setName("s1");
s.setAge(1);
//new一个配置文件对象
Configuration cfg = new Configuration();
//读取默认的配置文件并建立sessionFactory 理解为产生与数据库连接的一个工厂 读取指定配置文件在configure加参数即可
SessionFactory sf = cfg.configure().buildSessionFactory();
Session session = sf.openSession();
//将保存设置成为一个事物.
session.beginTransaction();//事物开始
session.save(s);
session.getTransaction().commit();//事物提交
session.close();
sf.close();


建表语句  这样写不需要配置hbm2ddl
new SchemaExport(new Configuration().configure()).create(true, true);
第一个true 是否打印 第二个true 是否真正的创建表

●annotation小实验
在hibernate3.6的这个版本中,Annotation类库集成到了hibernate3.6,所以不在需要添加hibernate-annotations.jar hibernate-commons-annotations.jar等类库了。但是必须添加hibernate-jpa-2.0-api-1.0.0.Final.jar。
建立teacher表
建立Teacher类 
  @Entity            在类前加入 表示 此类是实体类 和数据库表对应
  @Id                加在主键的get方法上 表示此键为主键
  @Table(name="xxx") 加在类前 此类对应的表名为xxx
  @Column(name="xxx")此属性的字段名设置为xxx
  @Transient         此属性是临时的,不要持久化到数据库中
  @Enumerated(EnumType.STRING)
                   此属为枚举类型,STRING是将字符串存入,
                   ORDINAL是将序号存入。
在hibernate.cfg.xml中加入以下句子告诉hibernate
此类为实体类其中有annotation符合JPA标准
<mapping class="com.bjsxt.hibernate.modle.Teacher"/>
测试类的写法:在hibernate新版本中,我们可以像xml配置一样写添加语句了。

●基本配置 hibernate-distribution-3.6.2.Final\project\etc中可查
1)<property name="hbm2ddl.auto">update</property>
  create数据库里没这个表会自动创建 先删除再创建 插入的时候都会执行删除
  update数据库的表结构修改了会自动更新 更新经常不会成功因为有约束之类的
  create-drop只要关闭sessionFactior就会自动删除表
  validate操作之前检查表与配置是否一致不一致就报错
2)先表再类
3)搭建日志环境显示ddl输出
·由于hibernate是用slf4j接口所以可以直接使用slf4j的实现
·如果要使用log4j的实现则需要使用转换器,
即引入log4j的jar包后还要引入slf4j-log4j2-1.6.1.jar
·在scr目录下粘贴\project\etc\log4j.properties
因为这个配置文件中的log4j.logger.org.hibernate.tool.hbm2ddl=debug
·此时可以输出一些数据库的ddl,想存入文本只需要改配置即可
4)搭建junit测试环境
·引入jar包
·详细配置参考junit笔记

●hibernate.cfg.xml的配置
  从参考文档中copy,在参考手册中的3.8. XML 配置文件文中有.
  在src根目录建立hibernate.cfg.xml将内容粘贴。
  修改对应配置 connection.driver_class为com.mysql.jdbc.Driver
  connection.url      为 jdbc:mysql://localhost/hibernate
  connection.username 为 root
  connection.password 为 root
  由于我们很少用hibernate的连接池 所以注释掉
  <!--  <property name="connection.pool_size">1</property> -->
  这项为定义hibernate将语句转换为哪个数据库的方言
  dialect             为 org.hibernate.dialect.MySQLDialect
  current_session_context_class
                    暂时不讲3.2新加的
  cache.provider_class为二级缓存 优化 留着
  show_sql            是否打印SQL语句 默认true 留着
  format_sql          是否格式化的打印SQL语句 true
  hbm2ddl.auto        是否让hibernate自动建表 暂时注释掉
  mapping resource为com/bjsxt/hibernate/model/Student.hbm.xml 映射的路径

  配置例
   <session-factory>

  <!-- 数据库连接信息 -->
  
  <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_20110721</property>
  <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.password">root</property>
  <property name="hibernate.connection.username">root</property>

  
  <!-- 其他配置 -->
  
  <!-- 显示SQL语句 -->
  
  <property name="show_sql">true</property>
  
  <property name="format_sql">false</property>
  
  <!--
 
   create:先删除表,再创建表。
   
    create-drop: 启动时建表,退出前删除表。
   
    update:表不存在,就创建,如果不一致就更新,如果一致,就什么都不做
   
    validate:启动时验证表结构与映射文件中说明的是否一致,不一致就报错。
  
  -->
  
  <property name="hbm2ddl.auto">update</property>


  
  <!-- 声明映射文件
  
  <mapping resource="cn/itcast/a_helloworld/User.hbm.xml" />
  
  -->

 
 </session-factory>

●annotation
  @Entity            在类前加入 表示 此类是实体类 和数据库表对应
  @Id                加在主键的get方法上 表示此键为主键
  @Table(name="xxx") 加在类前 此类对应的表名为xxx
  @Column@Column(updatable = false, name = "flight_name", nullable = false, length=50)
  此属性的字段名设置为xxx
  @Transient         此属性是临时的,不要持久化到数据库中
  @Enumerated(EnumType.STRING)
                   此属为枚举类型,STRING是将字符串存入,
                   ORDINAL是将序号存入。
  @GeneratedValue    此属性在数据库中为自增字段
  @SequenceGenerator(name="生成器名",
              sequenceName="数据库中的sequence名")
  @Temporal(TemporalType.)  指定时间字段映射的格式
  @Lob   指定该文本为大文本
  xml中配置
  <mapping class="com.bjsxt.hibernate.modle.Teacher"/>
●普通属性xml配置  xxxx.hbm.xml
    <class name="cn.itcast.d_hbm_property.User" table="user">
  <id name="id" type="int">
   <column name="id" />
   <generator class="native" />
  </id>

  <!--
   name:属性名,必须要指定
   length:长度,如果不指定,则是varchar(255)
   not-null:非空约束,如果不指定,默认为false
   type:类型,可以写Java类型的全限定名,也可以写hibernate类型,如果不指定,Hibernate会通过反射自己获取
   column:列名,如果不指定,列名默认为属性的名称
   -->
  <property name="name">
   <column name="name" not-null="true" default="'无名氏'"/>
  </property>
  <!--
   <property name="name" column="name" type="string"></property>
  -->
  <property name="gender" type="boolean"></property>
  <property name="birthday" column="birthday" type="date"></property>
  <property name="resume" column="resume" type="text" not-null="true"></property>
  <property name="photo" column="photo" type="binary" length="512000"></property>
  <property name="desc" column="`desc`"></property>
    </class>

●id生成策略  xxxx.hbm.xml
1)XML配置
<class name="cn.itcast.e_hbm_id.User" table="user">
  <!-- 主键 -->
  <!-- generator是配置主键生成策略 -->
  <id name="id">
   <!-- (使用数据库的自动增长策略)
    identity:对 DB2,MySQL,MS SQL Server,Sybase 和 HypersonicSQL 的内置标识字段提供支持(自动增长)。
    insert into user (name) values (?)
   <generator class="identity" />
    -->
   
    <!-- (使用Hibernate的自动增长,不能在多线程的情况下使用)
     Hibernate: select max(id) from user
    Hibernate: insert into user (name, id) values (?, ?)
   <generator class="increment" />
     -->

   <!--
    使用高低位算法生成主键值,需要数据库中有一张额外的表。
    Hibernate: insert into user (name, id) values (?, ?)
   <generator class="hilo">
    <param name="table">hi_value</param>
    <param name="column">next_value</param>
    <param name="max_lo">100</param>
   </generator>
    -->

   <!--
    根据底层数据库的能力选择 identity、sequence 或者 hilo 中的一个。
   <generator class="native" />
    -->
   
    <!-- (自己指定主键的方式)
     让应用程序在调用 save() 之前为对象分配一个标识符。这是 <generator> 元素没有指定时的默认生成策略。
     Hibernate: insert into user (name, id) values (?, ?)
   <generator class="assigned" />
     -->
   
   <!--
    由Hibernate生成UUID值并自动设置为主键值
    Hibernate: insert into user (name, id) values (?, ?)
   -->
   <generator class="uuid" />
  </id>
  <property name="name" />
 </class>
  5.1.2.2.1. Various additional generators中
2)annotation
  在自增属性的get方法前加入@GeneratedValue
  (strategy=GenerationType.SEQUENCE)
  strategy可以取以下四种
·GenerationType.SEQUENCE 在oralce可以用但是在mysql不能用
  @SequenceGenerator(name="生成器名",sequenceName=
 "数据库中的sequence名")
  @GeneratedValue
(strategy=GenerationType.SEQUENCE,generator="生成器名")
  此时id的取值就是这个生成器生成的值。
·GenerationType.IDENTITY 在oracle不能用但是在mysql可以用
·GenerationType.TABLE 使用表生成并保存
  @TableGenerator(name = "GEN",
  table="Teacher_GEN", //表名
  pkColumnName="pk_key",//主键字段名
  valueColumnName="pk_value",//值字段名
  pkColumnValue="Teacher",//主键的值
  allocationSize=1 //步进值,每次加1
  )
要使用它,就是从这个表中选出key为teacher的记录的value是多少,
取出后,value+1。每个记录对应一个表的自增字段。
@GeneratedValue(strategy=GenerationType.TABLE,generator="GEN")
·GenerationType.AUTO

3)联合主键
  新建主键类,将联合主键移入。
  这个类必须  实现java.io.Serializable接口
            重写equals方法,确定主键各个属性的值相同才返回true
     重写hashCode方法 返回this.name.hashCode();
在模型类中存一个主键类的引用。
·在xml中配置
  <composite-id name="pk" class="StudentPK">
 <key-property name="id"></key-property>
 <key-property name="name"></key-property>
  </composite-id>
·annotation配置
第一种
  在主键类前加@Embeddable
  在模型类的主键属性前加@Id
第二种
  在模型类的主键属性前加@EmbeddedId
第三种
  保持模型类的联合主键的属性并在这些属性前加@Id
  在模型类前加@IdClass(value="主键类.class")

●核心开发
1)Configuration
  Configuration().configure();建立与数据库的连接
2)SessionFactory
  Configuration().configure().buildSessionFactory();
  建立一个session工厂,每个session中都有一个数据库的连接。
3)session
·得到session有两种方法
  sessionFactory.openSession();
  sessionFactory.getCurrentSession();
  都可以得到session.
区别:
  openSession永远打开新session,需要自己close
  ,而getCurrentSession如果当前环境中有就拿当前环境中的session,
  commit时自动关闭.
·在xml中 这项为currentSession的配置
  <property name="current_session_context_class">thread</property>
  可以取jta、 thread当前线程、 managed、 custom.Class
·getCurrentSession的作用: 界定事物边界 此时在service层事物就可以开启
4)对象的三种状态
  Transient     对象刚new出来,仅在内存里有
  Persistent    调用了save方法后,已经存入数据库 内存数据库都有
  Detached      close之后 已经脱离了管理 只有数据库中有 内存没有
·三种状态的区别在于
  有没有id  id在数据库有没有  id在内存有没有
5)session.delete(Object obj)
  从数据库中把对象删除
  只要对对象设置了id,就可以删除。
6)session.load(class c, serializable s)
  从数据库中取出记录转换成对象
  第一个参数为取出后的类型 第二个参数为主键
  返回值是一个对象
7)session.get(class c, serializable s)
  与load差不多
  区别在于load是load出一个代理对象,
  仅仅在使用返回的对象时(除id和class之外的属性)才真正从数据库查询
  get是语句一执行,直接从数据库中查询并存入返回对象,同时load可以在class或集合中配置lazy属性
  该属性为false时和get一样当查找数据时会将与其有关的数据全部读取到内存,该属性为true时
  会等使用该数据的时候才查询。
8)session.update(Object obj)
·这里会把数据库中和obj的id一样的数据更新为obj
ps:完全的更新,即obj有些属性为空也将被更新到数据库。
·当对象为Persistent状态时,即刚存入或者刚读出时,在commit之前,
  与数据库的会话没有中断,修改它的属性,即使不调用update也会自动更新。
·部分更新
  在模型类中将不想被总是更新的属性的get方法前加入@Colum(updatable=false)
  或者使用f 后面讲
9)session.saveOrUpdate(Object obj)
  没id就save 有id就update
10)session.clear();
  无论是load还是get,都会首先查找缓存,如果没有,才会去数据库查找。
  此方法可以强制清楚缓存。
11)session.flush()
  强制进行从内存到数据库同步。
12)session.setFlushMode()
  设置同步的级别

●属性是个普通集合(集合内是非自定义对象)的映射
·set 会定义一张新表记录set中的对象 表中的记录用外键参考主表。
  再来一个该类对象中也存了set集合,也会使用这张新表。
  <class name="cn.itcast.g_hbm_collection.User" table="user">
  <id name="id">
   <generator class="native"></generator>
  </id>

  <!-- addressSet属性,Set集合
   table属性:集合表
   key子元素:集合外键
   element子元素:集合元素
   -->
  <set name="addressSet" table="user_addressSet">
   <key column="userId"></key>
   <element column="address" type="string"></element>
  </set>

  </class>
集合属性的清空方式
集合内可以是其他对象 此时inverse必须为false表示本对象可以维护关联关系
集合内如果是普通属性如字符串 则不用
teacher.getStudents().clear(); // 清空与所有学生的关联,在inverse="false"时才有效
·list

·map


●关系映射 重点 
学习此节的作用是,当建立好数据库表之后,
我们应当如何设计类才能让hibernate将类顺利持久化到数据库中。
1)对象之间的关系
·一对一单向外键关联
  @OneToOne
  @JoinColum(name="wifeId")
  在模型类中有参考类的引用作为成员变量
  在此成员变量的get方法前加入@OneToOne
  在数据库中的表会在此模型类中加入一个
  外键字段记录参考类的主键,使用@JoinColum(name="wifeId")可以为
  这个外键字段设置名字
  2)xml
 
·一对一双向外键关联
  @OneToOne(mappedBy="wife")
  在模型类中有参考类的引用作为成员变量
  在此成员变量的get方法前加入@OneToOne(mappedBy="wife")说
  说明在这个外键类中有wife属性已经做了外键关联 wife为属性名
·一对一单向主键关联(了解)
  @OneToOne
  @PrimaryKeyJoinColumn
  在模型类中有参考类的引用作为成员变量
  在此成员变量的get方法前加入
  @OneToOne
  @PrimaryKeyJoinColumn
  说明自己的主键参考对方类的主键
  此时 自己的主键不能靠GeneratedValue生成
·一对一双向主键关联(了解)
·联合主键关联
  模型类的外键要参考的类的主键是一个联合主键时
  会自动生成对应字段
  @OneToOne
  @JoinColumns设置生成的字段名
·组件映射
  组件:一个对象是另一个对象的一部分 在数据库中可以映射成一张表
  1)在主类的get组件方法前加@Embedded即可声明这个属性是一个组件
     所以组件类没有ID属性名也不能与主类相同
  2)xml
    <class name="cn.itcast.f_hbm_component.User" table="user">
  <id name="id">
   <generator class="native"></generator>
  </id>
  
  <!-- 组成关联的映射 -->
  <component name="address">
   <property name="address" column="address" type="string"></property>
   <property name="code"></property>
   <property name="phoneNumber"></property>
  </component>
    </class>
·多对一与一对多
  i.多对一单向关联
    在每个多的一方建立一个属性标记它对应的单一方
    并在此属性的get方法前加
    @ManyToOne   @JoinColumn(name="groupid")改变数据库中字段名
    xml:----------------------------------------------------------inverse 
  ii.一对多单向关联
    单一方建立set标记多的一方
    并在此属性的get方法前加
    @OneToMany 只加此属性会生成一张新表 同时参考两张表 类似多对多
    @JoinColumn(name="groupid") 加入此属性会在多的一方建立字段标记它
     对应的单一方 类似多对一
  iii.一对多 多对一双向关联
    表结构:在多的一方建立外键关联一的一方
    规律:只要有双向就指定属性
    @OneToMany(mappedBy="") 
    xml:----------------------------------------------------------
·多对多
  i.多对多单向关联
  即 老师知道他教哪些 学生 学生不知道他有哪些老师
  在老师类中的学生集合属性的get方法前加
  @ManyToMany 会生成一张新表 可以用
  @JoinTable(name="t_s",
  joinColumns={@JoinColumn(name="teacher_id")},
  inverseJoinColumns={@JoinColumn(name="student_id")})
  指定新表的名字和表内列的名字 俩属性 一个是当前 一个是对方
  ii.多对多双向关联
  即 老师知道他教哪些 学生 学生也知道他有哪些老师
  在teacher类中像单向关联一样写
  在student类中的getTeachers方法前写
  @ManyToMany(mappedBy="students")
  xml:------------------------------------------------------------
  关于inverse属性
  在多对多中插入关联数据时 如果双向都维护 默认会插入重复的数据而出错
  在多对一和一对多时插入关联数据 如果双向都维护 默认会重复更新数据 不会出错 但是会影响效率
  写了inverse会解决这个问题

2)带有关联关系的增删改查
·多对一双向的存储
  i.建立好两个对象的关联(在一个对象中设置好另一个对象的引用)
  ii.默认情况下不会自动保存关联对象。
     存多的时候@ManyToOne(cascade={CascadeType.ALL})
     存一的时候@OneToMany(cascade={CascadeType.ALL})
     此属性可以让数据库自动保存级联的对象
     规律:但是存一记录的时候自动生成的多记录的外键为空,
    需要手动存或者双向都写清楚他们的关联关系
·多对一双向读取                            
  get一个user对象时会自动get它对应的group对象
 默认情况下会自动取出关联对象。
  get一个group
 默认情况下不会自动取出关联对象。
 @OneToMany(fetch=FetchType.EAGER)才会自动取出
·多对一双向更新
  更新user时同时可以更新与user有关的group的信息
  更新group时同时可以更新与group有关的user的信息
  由cascade={CascadeType.ALL}决定
  想要做更新 先做LOAD
·多对一双向删除
  想坐删除 先LOAD
  由于是双向 所以删除一个 就会删除与之级联的所有记录
  比如 user1 user2同时参考group1 删除u1就会将u1 u2同时删除
  由cascade={CascadeType.ALL}决定
  只想删除一个:打破级联关系 u.setGroup(null);再删u
  或者使用HQL 后面讲
·集合映射
  当users为list时
  getUsers()前可以加@OrderBy()进行排序
  当users为Map时
  getUsers()前可以加@Mapname="用作key的字段名")
·继承映射
  i.Single_Table 一张表中把所有子类的字段都写上 不同的子类某些字段为空
   缺点:字段过多时一个记录的空字段会很多
   在父类中:
    父类标明@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
    区分字段@DiscriminatorColumn(
   name="discriminator",
   discriminatorType="DiscriminatorType.STRING"
   )
    代表本类类型的字符串@DiscriminatorValue("person")
   在子类中:
    不要有ID字段,只需要写出本类特有的字段即可
    区分字段@DiscriminatorValue("student")
  ii.Table_Per_Class
   缺点:通过id读取load的时候必须把每张表都搜索一遍
   在父类中:
    父类标明@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
    建立ID生成器
    @TableGenerator(
 name="t_gen",
 table="t_gen_table",
 pkColumnName="t_pk",
 valueColumnName="t_value",
 initialValue=1,
 allocationSize=1
 )
    在ID的get方法前使用此生成策略
    @GeneratedValue(generator="t_gen",strategy=GenerationType.TABLE)
   在子类中:
 只需要写@Entity
        和特有字段
  iii.JOINED  三张表  在父表中写共有的属性  在子表中写自己的属性 通过配置让存取的时候通过表连接存取
  在父类中:
    父类标明@Inheritance(strategy=InheritanceType.JOINED)
  在子类中:
 只需要写@Entity
        和特有字段


●树状结构的设计
  ·save
  为类设计父亲变量Org parent和孩子变量Set<Org> children
 
  @OneToMany(cascade=CascadeType.ALL, mappedBy="parent")
 public Set<Org> getChildren() {
  @ManyToOne
 @JoinColumn(name="parent_id")
 public Org getParent() {
  此时数据库中会有一张表 有两个字段 id parent_id
  ·load
   当fetch设定为FetchType.EAGER时取记录会取出所有与此记录有关的记录
        可以不设EAGER则每次需要取数据时会向数据库执行取数据语句@OneToMany(cascade=CascadeType.ALL, mappedBy="parent",fetch=FetchType.EAGER) 
   取出Org后使用下面的打印方法后再关闭session即可打印出树
 private void print(Org o,int leval) {
  String preStr = "";
  for(int i=0;i<leval;i++){
   preStr +=" ";
  }
  System.out.println( preStr + o.getName());
  for(Org child : o.getChildren()){
   print(child,leval+1);
  }
 }
●设计的一般规律
  ·设计实体类
  ·设计导航(编程方便)

●Hibernate 查询(Query Language)
  · NativeSQL > HQL >EJBQL  以功能顺序排列
  · QL应与导航关系结合,共同为查询提供服务
 Query q = session.createQuery("from Category");
 查出Category所有记录

 Query q = session.createQuery("from Category c where c.name > 'c5'");
 查出Categroy中名字字段大于c5的记录

 Query q = session.createQuery("from Category c order by c.name desc");
 查出category中记录按名字降序排列

 Query q = session.createQuery("select distinct c from Category c order by c.name desc");
 查出category中所有记录 并且主键不同 按将序排列

 Query q = session.createQuery("from Category c where c.id > :min and c.id < :max");
 q.setParameter("min", 2);
 q.setParameter("max", 8);
 查出category中id>2并且id<8的字段 使用:变量 进行参数设置 也可以写成方法链 因为设置完返回是他自己

 Query q = session.createQuery("from Category c where c.id >? and c.id <?");
 q.setParameter(1, 2);
 q.setParameter(2, 8);
 查出category中id>2并且id<8的字段 使用?占位符进行参数设置

 session.createQuery("from Category c where c.id in(:ids)");
 setParameterList("ids",ids)
 当参数是个集合时 比如查出 id为1 2 3

 Query q = session.createQuery("from Category c order by c.name desc");
 q.setMaxResults(4);
 q.setFirstResult(2);
 分页,从第2条开始查出4条记录(从0开始) 如果没有4条记录 则有几条拿几条

 Query q = session.createQuery("select c.id,  c.name from Category c order by c.name desc");
 查出category的id和name字段,按name降序

 Query q = session.createQuery("from Topic t where t.category.id = 1");
 查出topic表中categoryid为1的记录

 Query q = session.createQuery("from Msg m where m.topic.category.id = 1");
 查出当msg表与topic表连接后categoryid为1的记录

 Query q = session.createQuery("select t.title, c.name from Topic t join t.category c ");
 表连接查询,t.category c 指明用哪个成员变量的连接条件做连接
 
 from Msg m where m.id between 3 and 5
 from Msg m where m.id in (3,4, 5)
 from Msg m where m.cont is not null
 from Topic t where t.msgs is empty
 from Topic t where t.title like '%5'  %代表零个或者多个
 from Topic t where t.title like '_5'  _代表一个
 "select lower(t.title)," +
 "upper(t.title)," +
 "trim(t.title)," +
 "concat(t.title, '***')," +
 "length(t.title)" +
 " from Topic t "
 "select abs(t.id)," +
 "sqrt(t.id)," +
 "mod(t.id, 2)" +
 " from Topic t "
 select current_date, current_time, current_timestamp, t.id from Topic t
 current_date当前日期 current_time当前时间 current_timestamp日期和时间
 from Topic t where t.createDate < :date
 select t.title, count(*) from Topic t group by t.title
 select t.title, count(*) from Topic t group by t.title having count(*) >= 1
 have规定分组条件 只显示人数大于等于1的title的title和计数
 from Topic t where t.id < (select avg(t.id) from Topic t)
 取平均值然后取小于平均值的
 from Topic t where not exists (select m.id from Msg m where m.topic.id=t.id)
 找topic中没有msg的topic
 update Topic t set t.title = upper(t.title)

 
 int i = session.createQuery("delete from topic t where t.id = 1").executeUpdate();
 删除 返回的是int 就是影响的行数

 █HQL的执行
 ··········List<Category> categories = (List<Category>)q.list();
 ··········执行语句返回List
 ··········Msg mResult = (Msg)q.uniqueResult();
 ··········执行语句返回单独结果对象
 ··········Query q = session.createQuery("select count(*) from Msg m");
 ··········Long mResult = (Long)q.uniqueResult();
 ··········count(*) 返回是Long类型
 
 hql可以写到配置文件中 叫命名查询
   在子配置文件中写
  
   在程序中调用
 

●性能优化
·注意session.clear()的运用,尤其在不断分页循环的时候
  1)在一个大集合中进行遍历,遍历msg,取出其中含有敏感字样的对象
  2)另外一种形式的内存泄露//面试题:java有内存泄露吗?语法级别没有。static Map中存的对象引用使得对象不会被销毁
·1+N问题
  问题描述:取一个东西,由于fetchType.EAGER会将与之相关的对象(另一个表)也取出来
  1) .LAZY
  2)@BathChSize
  3)join fetch
·list和iterator 
  1)list取所有
  2)iterate 先取ID,等用到的时候再根据ID来取对象
  3)session中list第二次发出仍会得到数据库查询
  4)iterate第二次,首先找session级缓存
·一级缓存和二级缓存和查询缓存
  1)什么是缓存 就是一部分内存
  2)什么是一级缓存,session级别的缓存
    在同一个session中load同一个对象只查询一次
  3)什么是二级缓存,sessionFactory级别缓存,可以跨越session存在
    适用:经常被访问、不常改动、数量有限
  4)打开二级缓存(主配置文件) 只有使用id查找时才使用缓存的数据,使用hql时不使用,要想使用需开启查询缓存
   先导入hibernate\lib\optional\ehcache.jar
         spring\lib\commons-logging.jar
  spring\lib\concurrent\backport-util-concurrent.jar
   配置
   <property name="cache.use_second_level_cache">true</property>
   <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider
   </property>
   <class-cache usage="read-write" class="cn.itcast.o_secondcache.Emploee" /><!-- 配置需要缓存的类 不写全缓存 -->
   <collection-cache usage="read-write" collection="cn.itcast.o_secondcache.Department.emploees" />     <!-- 对集合的缓存 不配不缓存 -->---------------
 
   拷贝配置文件:将hibernate/project/etc/ehcache.xml复制到src
                 缓存算法配置项memeoryStoreEvictionPolicy="LRU"
                 其他配置查汤阳光hibernate.word
  注:或者在类的配置文件中进行二级缓存的配置(不方便 用到查)
  5)引入jar包hibernate/lib/optional/ehcache/
             和comments-logging的jar包(这是ehcache用的日志工具包)
  6)@Cache 注解使用二级缓存
   @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)读写
                                          .READ_ONLY 只读
 
  7)load默认使用二级缓存,iterator默认使用二级缓存,list不使用
  8)查询缓存:两个查询语句一样才会使用
    (查询语句查出的也会放到缓存中但是它不使用,再次查询依然会查数据库,配置此项后不会查询)
    i.打开查询缓存(二级缓存也打开)
      <property name=use"cache.use_query_cache">true</property>
    ii.调用Query的setCachable(true)方法指明使用查询缓存(1.会先从缓存中找,2.把查询结果放入缓存中)
  9)更新的时间戳缓存
    在第一次缓存之后 在第二次使用缓存前(get前),使用hql进行了更新或者删除操作,一级缓存不会发觉,
    需要手动refresh,而二级缓存会发觉,再次发出查询,再打印更改后的内容。这是因为hibernate会将我们
    的所有更新的时间都记录。这就是hibernate更新时间戳缓存。

·事物的并发处理
  1)事物:要完成一起完成,要回滚一起回滚
    特性:原子性 一致性 独立性 持久性 acid
  2)事物并发存在的问题
    i.丢失更新
     柜员查询出卡里1000元,我把100元交给柜员,柜员开始验钞。
     此时我朋友在门口atm把这1000取走,卡里实际没钱了。
     柜员验钞结束,将1000+100元设入卡中。
    ii.脏读
     读到别的事物没有提交的数据
     柜员查出卡里1000元,我把100元交给柜员,柜员刚将1100设入卡中未提交,
     你去门口ATM查钱查出了1100就是因为脏读,读到别的事物未提交的数据。
     我让柜员回滚,你取钱失败。
    iii.不可重复读 前后读出数据不一致
      我查卡里有1000,你在atm存了100,也提交了,我又读卡里有1100了。卡里到底有多少钱我不知道了。
    iiii.幻读  读到了别人提交的新插入的记录 到底有多少条记录无法确定。mysql中和不可重复读一起解决了。
·数据库的事物隔离机制
  java.sql.connection中可以看到四种机制
  1)read-uncommitted
  允许脏读存在,允许重复读存在
  2)read-commtited 
  允许重复读粗在
  4)repeatable read
  不允许别的事物访问本事物访问的资源
  8)serializable
  不允许并发
·hibernate的悲观锁
  session.load(xxx.class,1,LockMode.UPGRADE); 
  依赖数据库的具体的锁的实现
  加了锁后别的session不允许修改。
·乐观锁
  1)数据库中设置一个版本字段叫version,默认为0.
  每当有人修改的时候版本字段+1。每次修改前查看记录的版本和当初
  读到的版本是否一致。
  2)具体配置
    在实体类中加入一个version字段并在该字段的get方法前加入
    @Version
    当存入记录时hibernate会自动设置version

 

 


 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:53167次
    • 积分:1097
    • 等级:
    • 排名:千里之外
    • 原创:119篇
    • 转载:8篇
    • 译文:0篇
    • 评论:10条
    文章分类