JavaEE:Hibernate笔记

一、开发流程

1.设计实体类(JavaBean):
注意:
hibernate对实体对象的限制:设计的实体对象必须要有无参的构造方法


2.写映射文件(名称一般为"实体类名.hbm.xml"):
<hibernate-mapping package="实体类全名">
<class name="类名" table="表名" [lazy="false" dynamic-insert="true"]>         //name为类名,table为表名(可不写,不写时类名与表名称相同),lazy为延迟检索
   <id name="属性名" column="主键列名" type="列类型" [unsaved-value="-1"]>  //name为类中属性,column为表列名(可不写,同上),unsaved-value用于判断id是否为-1
       <generator class="native或identiry"/>       //class为hibernate生成器,native或increment为主键生成器(自增)
   </id>  
   <property name="属性名" column="列名" type="列类型" [unique="true" access="property|field" update="false"] insert="false"/>  //unique指定该列中的值是否唯一,access指定访问方式(field为访问实体类的变量,property为访问实体类方法,即属性)
   或者:
   <property name="属性名" type="列类型">
        <column name="列名" sql-type="sql类型">  //显式指定表列的sql类型
   </property>
</class>
</hibernate-mapping>

3.配置hibernate.cfg.xml文件(一般不要改文件名):
<hibernate-configuration>
    <session-factory>
        //连接数据库的驱动
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        //连接的url
        <property name="connection.url">jdbc:mysql:///数据库名</property>
        //用户名
        <property name="connection.username">root</property>
        //密码
        <property name="connection.password">root</property>
        //指定连接哪种类型的数据库
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
        //设置操作数据库方式,update方式只更新数据库中的表,不删除表,其他的都先删除原表再建新表
        <property name="hbm2ddl.auto">create | update | none | create-drop</property>
        //用于显示hibernate编写的sql语句(不用设置)
        <property name="show_sql">true</property>
        //配置映射文件所在路径
        <mapping resource="映射文件路径"/>
    </session-factory>
</hibernate-configuration>

3.编写工具类代码(以下类全为hibernate包中的类,放在静态中是为了只加载一次,提高性能):
private static  SessionFactory sf = null;
static{
    方法链编程:
    sf = new Configuration().addClass(类1.class)
                          .addClass(类2.class)
                          .addClass(类3.class)
                          .buildSessionFactory();
    普通方式:
    Configuration conf = new Configuration();
    conf.configure():  //读取配置文件
    或者:
    conf.configure("文件路径");  //当hibernate.cfg.xml文件名被改过后要这么设置
    或者:
    conf.addClass(类.class);     //加载类的映射文件,该文件要与类放一个目录下才能用此方法
    或者:
    conf.addResource("文件路径");//映射文件名与类名不一样时用这方法
    sf = conf.buildSessionFactory(): //构造一个Session工厂,用来new一个Session类
}
Session session = sf.openSession();  //得到一个Session对象,用于返回出去给别的类进行CRUD操作


4.在Dao在写调中代码:
(1)多种查询操作:
按id查询:
实体类 别名 = session.get(实体类.class,id);             //根据给出id与实体类型,找出数据库中与实体类对应的数据,返回为实体类

实体类 别名 = session.load(实体类.class,id);            //和get一样
hql查询:
String hql = "from 实体类 as 别名 where 别名.属性=:引用名";//hql语言查的是实体对象,不是表,只能hibernate中使用
Query query = session.createQuery(hql);                //编译hql语句
query.setString(0,值);             //和PreparedStatement方法一样,只是这里从0开始
查询多条数据:
实体类 别名 = session.createQuery().uniqueResult();   //查询结果只有一个对象时可以这么用
List list = session.createQuery(hql).list();          //查询结果是一个List集合
查出分页数据:
query.setFirstResult(0):  //从0行开始
query.setMaxResults(10);  //取10行
按条件查询(criteria)
Criteria c = session.createCriteria(实体类.class);
c.add(Restrictions.eq("属性名",属性值)):  //增加条件,判断是否相等
gt("属性名",属性值);  //小于
c.list();  //返回List集合
分页:
c.setFirstResult(0);  //从0行开始
c.setMaxResults(10):  //取10行

(2)增删改操作:
Transaction tran = session.beginTransaction():  //增删改操作必须开启事务
添加方法:
tran.save(实体类); //保存实体类中的信息到数据库中,先保存,失败后回滚
tran.persist(实体类);//同save一样,不同的是当没开启事务时不执行保存操作
添加或更新方法:
session.saveOrUpdate(实体类);  //保存或更新,对象变成持久的
session.merge(实体类);         //保存或更新,对象还是脱管的
删除方法:
tran.delete(实体类);   //删除,会根据id删除
tran.commit();     //提交事务
tran.rollback();   //出现异常时回滚,可以不写,当出异常时系统默认会自动回滚
session.close();   //关闭连接
session.evict();   //将一个对象变为游离状态
session.flush();   
session.clear();   //清理


二、映射关系
1.多对一映射:
对象关系:
每一个多方对象都保存着一个单方对象
表关系:
多方表加入一个单方表的主键作为外键,关联单方表

(1)在映射文件中配置
多方表映射文件:
<class name="多方类">
   <id name="id">
       <generator class="native"/>
   </id>
   //映射多方表到单方表中的关系,
   <many-to-one name="单方类引用变量" column="多方表外键" class="单方类" [cascade="save-update" not-null="true"]/> //not-null设置多方的外键不能为空,cascade为级联操作
</class>
单方表映射文件:
<class name="单方类">
   <id name="id">
       <generator class="native"/>
   </id>
</class>

(2)在Dao中写代码:
保存代码:
//当单方存数据时,第一次多方外键会为空,当单方表有值时,再执行一次更新操作,将单方的主键值存入多方表中的外键中
session.save(单方对象);  //当多方表外键不能为空时,单方对象必须先存入
session.save(多方对象);  
查询代码:
多方类 别名 = session.get(多方类.class,多方id值); //结果中多对象中会有单方的对象,hibernate会执行两次sql语句

2.一对多映射:
对象关系:
一个单方对象有一个集合保存多个多方对象,一个多方对象保存一个单方对象
表关系:
多方表加入一个单方表的主键作为外键,关联单方表

(1)在映射文件中配置
单方表映射文件:
<class name="单方类">
   <id name="id">
       <generator class="native"/>
   </id>
   //将单方类中集合映射到表中,cascade属性执行级联操作,当单方表修改时,多方表也作修改操作
   //delete在删除单方时也删除多方表,all-delete-orphan
   <set name="单方类中集合引用" order-by="要排序的列名 asc或desc" cascade="save-update,delete,all-delete-orphan" [inverse="true" lazy="false"]> //inverse让单方表放弃维护之间的关系
       <key column="多方表外键"/>
       <one-to-many class="多方类"/>
   </set>
   如果用的是List集合,则这样配:
   <list name="单方类中集合引用">  //将单方类中集合映射到表中
       <key column="多方表外键"/>
       <list-index column="列名"/>     //用来在表中记录第几个员工
       <one-to-many class="多方类"/>
   </list>
   或
   <bag name="单方类中集合引用">
       <key column="多方表外键">
       <one-to-many class="多方类"/>
   </bag>
  如果用的是Map集合,则这样配:
  <map name="单方类中集合引用">  //将单方类中集合映射到表中
       <key column="多方表外键"/>
       <map-key type="string" column="多方表列名">     //这个列记录每个员工的在map中的key
       <one-to-many class="多方类"/>
   </map>
</class>
多方表映射文件:
同多对一相同

(2)在Dao中写代码:
保存代码:
session.save(单方对象); //必须设置cascade属性,不然会报错,多对一关系也会这样
session.save(多方对象1);  
session.save(多方对象2);  

session.save(多方对象1);  
session.save(多方对象2);  
session.save(单方对象);
查询代码:
单方类 别名 = session.get(单方类.class,单方类id);  //会查出所有单方类所应有的多方类,并存入单方类集合属性中

3.一对一映射:
对象关系:
一个主对象中保存着一个副对象,一个副对象中也保存着一个主对象
表关系:
第一种方法:
在副表中id即是主键又是外键,将副表id与主表id进行了外键约束
第二种方法:
副表中增加一个唯一的外键,关联主表id

(1)在映射文件中配置
主表映射文件:
第一种方法:
<class name="主类">
   <id name="id">
        <generator class="native"/>
   </id>
   <one-to-one name="主类属性名(副类引用)" class="副类全名" [cascade="save-update,delete"]/>  //主对象中的保存的副对象的引用名,即主对象的属性名,cascade级联操作表的方式
</class>
第二种方法:
<class name="主类">
   <id name="id">
        <generator class="native"/>
   </id>
   <one-to-one name="主类属性名(到副类引用)" property-ref="副对象属性名(主类引用)"/> //副对象属性名==副对象中保存的主对象
</class>
副表映射文件:
第一种方法:
<class name="副类">
   <id name="id">
       //此标签指明副表主键id从主对象中取得
       <generator class="foreign">
            <param name="property">副类属性名(到主类引用)</param> //副类属性名就是保存着主对象的属性
       </generator>
   </id>
   <one-to-one name="副类属性名(到主类引用)" class="主类全名" constrained="true"/> constrained为副表增加到主表的外键约束
</class>
第二种方法:
<class name="副类">
   <id name="id">
       <generator class="native"/>
   </id>
   <many-to-one name="主表名" column="副表外键" unique="true"/> //用一个单独的列作为外键关联主表,unique指明外键唯一的
</class>

(2)在Dao中写代码:
保存代码:
只要写保存副对象就能将主对象也保存了:
session.save(副对象);
两个对象都保存也一样效果,前后顺序没关系,都执行了两条插入语句:
session.save(主对象);
session.save(副对象);

session.save(副对象);
session.save(主对象);
session
查询代码:
主对象 别名 = session.get(主对象.class,主对象id);  //查询用了两表联查,用了一句,给副类也赋值了

副对象 别名 = session.get(副对象.class,副对象id);  //也会查出主类的值,只是要用两条查询语句

4.多对多映射:
(1)对象关系:
A对象中用一个集合保存着多个B对象
B对象中也用一个集合保存着多个A对象
表关系:
利用第三张表来存放A表与B表的id

(2)在映射文件中配置:
A类映射文件:
<class name="A类名">
   <id name="id">
       <generator class="native"/>
   </id>
   <set name="A类中的集合别名" table="连接AB表的中间表名" inverse="true">  //集合中保存的是多个B对象,要在其中一方配inverse属性,让一方放弃对关系的维护,否则会出会重插操作,会出错
       <key column="中间表列名1"/>  //此id对应A表id
       <many-to-many class="B类全名" column="中间表列名2"/> //此id对应B表id
   </set>
</class>
B类映射文件:
<class name=B类名">
   <id name="id">
       <generator class="native"/>
   </id>
   <set name="B类中的集合别名" table="连接AB表的中间表名">  //集合中保存的是多个A对象
       <key column="中间表列名1"/>  //此id对应B表id
       <many-to-many class="A类全名" column="中间表列名2"/> //此id对应A表id
   </set>
</class>

(3)在Dao中写代码:
保存代码:
session.save(A对象);  //前后互换效果一样,执行的sql语句也一样
session.save(B对象);
查询代码:
A对象 别名 = session.get(A对象.class,A对象id); //会将A对象中集合中所需的值也查出来的


5.组件映射:
(1)对象关系:
整体对象中,有一个用于保存着一个组件的对象属性
组件对象中无整体对象的属性

(2)表关系:
两个关联对象保存在一张表

(3)在映射文件中配置:
整体类映射文件:
<class name="整体类名" table="表名">
    <id name="id">
        <generator class="native"/>
    </id>
    <component name="到组件对象的引用" class="组件类全名">  //name就是整体类中保存的组件对象
        <property name="组件类属性1" column="列名1" type="列类型"/>
        <property name="组件类属性2" column="列名2" type="列类型"/>
    </component>
</class>

6.影射继承关系:
(1)对象关系(三种方法一样):
父类,有id及其他属性
子类,要继承父类,无id属性,只有其他属性,可以有多个子类

(2)表关系(父子表的id值不会重复):
方法一(single):
父子类全合并在一张表中
方法二(joined):
父表与每个子类都是一对一
父表,有父类属性列,几个子类,就产生几个只有id值的null行,供子表id取值
子表,id列+子类属性列
方法三(union):
一个类一张表,每张表都是完整的,不存在父子表关系
父表,父类属性
子表,父类+子类属性

(3)在映射文件中配置(只需一个父类映射文件):
方法一(single):
<class name="父类全名" table="表" discriminator-value="分隔列值">
    <id name="id属性" column="id列名" type="表列类型">
         <generator class="native" />
    </id>
    <discriminator column="列名" type="类型"/>  //增加分隔列,区分父子类数据(必须加这行)
    <property name="父类属性" column="列名" type="表列类型"/>
    <subclass name="子类全名" discriminator-value="分隔列值">  //分隔列值会显示在分隔列中(可以没有,没有指定该值,会将子类全名作为值)
         <property name="子类属性" column="列名" type="表列类型"/>
    </subclass>
</class>
方法二(joined):
<class name="父类全名" table="父表">
    <id name="父类id属性" column="父表id列名" type="表列类型">
         <generator class="native" />
    </id>
    <property name="父类属性" column="父表列名" type="表列类型"/>
    <joined-subclass name="子类全名" table="子表">
         <key column="子表id列名"/>   //此id为子表id列,值从父类id中取得
         <property name="子类属性" column="子表列名" type="表列类型"/>
    </joined-subclass>
</class>
方法三(union):
<class name="父类全名" table="父表">
    <id name="父类id属性" column="父表id列名" type="表列类型">
         <generator class="hilo">  
                <param name="table">表名</param>  //创建一个产生id值的表
                <param name="column">列名</param> //该列存放产生id次数
                <param name="max_lo">10</param>   //设置每次产生id步长
         </generator>
    </id>
    <property name="父类属性" column="父表列名" type="表列类型"/>
    <union-subclass name="子类全名" table="子表">
         <property name="子类属性" column="子表列名" type="表列类型"/>
    </union-subclass>
</class>


三、控制hibernate查询时的检索方式:
可以用在class、set、many-to-one标签上
1.fetch:
fetch="join"       //用迫切左外连接的方式查询
fetch="select"     //让lazy选择
fetch="subselect"  //用嵌套的子查询方式查询
2.lazy:
lazy= true | false //开启懒加载 | 关闭懒加载
lazy= extra        //开启非常懒加载,只查指定数据
lazy= proxy | noproxy  //使用按类级别的设置 | 不使用类级别的设置
3.batch-size:
batch-size="数值"   //查询多个客户时,一次查询定单集合的数量


四、CRUD方法:
1.Session方法:
s.load():          //加载查询,不存在时抛异常
s.get();           //查询,不存在时返回null
s.save();          //保存
s.saveOrUpdate():  //保存或更新
s.update();        //更新,如果想数据没改变时不进行更新,要在映射文件中:<class name="".. select-before-update="true">
s.delete();        //删除
s.flush();         //数据库和缓存同步,以缓存为准,不提交.
s.refresh();       //缓存和数据库同步,执行查询,更新缓存的对象.
s.clear();         //清空缓存,释放空间
s.createQuery(hql).iterate();   //对结果进行迭代
分组函数:count() sum() max() min() avg()

2.hql语法:
String hql = "hql语句";   //hql与sql基本一样,将sql的表名与列名换成类名与属性名就即可
hql = "from java.lang.Object";       //多态查询,查所有Object类及子类映射的表
hql = "from java.io.Serializable";   //多态查询,查询所有实现该接口的类所对应的表
Querty q = session.createQuery(hql语句);  //相当于编译hql语句
q.uniqueResult();   //当只有一条结果时用
q.executeUpdate();  //更新
q.setFirstResult(开始行号).setMaxResults(行数).list();  //分页取数据
q.uniqueResult();       //只有一行数据用
像jdbc中的PreparedStatement同样效果:
按参数名:
q = session.createQuery("from User类 where name属性=:参数名1 and password属性=:参数名2");
q.setString("参数名1","值");
q.setString("参数名2","值");
按索引:
q = session.createQuery("from 类 where 属性1=? and 属性2=?");
q.setString(0,"值"); //hql语句从0开始
q.setString(1,"值");
命名查询:
在类映射文件中class标签后增加:
<query name="参数名">
        <![CDATA[from 类 where 属性=?]]>
</query>
在代码中调中此语句:
q = s.getNamedQuery("参数名");
q.setString(0, "值");

3.qbc语法(Criteria,主要用于动态查询):
Criteria crt = session.createCriteria(类.class);
Criterion a1 = Restrictions.eq("属性名","值");  //判断该属性名是否等于该值,相当于where中的=
Criterion a2 = Restrictions.like("属性名","值");  //相当于where中的like
Criterion a3 = Restrictions.and(a1,a2);       //相当于sql中的and
Criterion a4 = Restrictions.or(a1,a3);        //相当于sql中的or
Criterion a5 = Restrictions.lt(属性,值);      //相当于sql中的<
Criterion a6 = Restrictions.ge(属性,值);      //相当于sql中的>=
crt.add(a1).list();                           //将条件加入查询,得到结果
crt.addOrder(类全名.desc("属性名")).list();   //对结果集降序排列
crt.setFirstResult(开始行号).setMaxResults(行数).list(); //分页取数据
crt.uniqueResult();                           //结果只有一行时用


五、在hibernate.cfg.xml文件中的一些配置:
<session-factory>
1.配置c3p0数据源:
  导包:c3p0-0.9.1.2.jar
  <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
  <property name="c3p0.max_size">最大连接数</property>
  <property name="c3p0.min_size">最小连接数</property>
  <property name="c3p0.acquire_increment">增量数</property>

2.配置数据库连接的隔离级别:
  //隔离级别数:1:读未提交 2:读已提交 4:可重复读 8:串行化(悲观锁) ansi sql 
  <property name="connection.isolation">hibernate中的数据隔离级别数</property>

3.采用线程本地化技术,为每个线程开启一个独立的session(可防止并发问题,在web中要常用):
  <property name="current_session_context_class">thread</property>
  在程序中调用:
  SessionFactory.getCurrentSession();
</session-factory>


六、配置二级缓存: 
用hql语句更新时,会更新二级缓存中的时间戳,当发现数据更新时,会查库,再更新二级缓存的数据。
用对象进行更新时,会一起更新二级缓存中的数据,因此更新完后再查时直接查二级缓存,不查库
1.使用ehcache缓存插件:
ehcache.jar
commons-logging-1.0.4.jar

2.配置缓存供应商(在hibernate.cfg.xml中):
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

3.配置类缓存和集合缓存(在hibernate.cfg.xml中):
<class-cache class="类全名" usage="read-write"/> //类缓存
<collection-cache collection="类全名.集合属性名" usage="read-write"/>  //集合缓存

4.创建ehcache.xml(配置缓存有效期,ehcache-1.2.3.jar/ehcache-failsafe.xml中有样文件):
<ehcache>
    <diskStore path="java.io.tmpdir"/> //代表系统用户的临时目录
    <defaultCache                      //默认
            maxElementsInMemory="10"   //内存中元素最大值
            eternal="false"            //是否过期,false为不过期,true为过期
            timeToIdleSeconds="120"    //允许空闲时间秒数,超过后缓存失效
            timeToLiveSeconds="120"    //缓存可用有效秒数
            overflowToDisk="true"      //如果内存数据溢出,是否将溢出部分存入硬盘临时目录中
            diskPersistent="false"     //
            diskExpiryThreadIntervalSeconds="120"  //
            memoryStoreEvictionPolicy="LRU"/>      //
</ehcache>
以上操作完全成即能使用二级缓存了

5.开或关二级缓存:
<property name="cache.use_second_level_cache">true或false</property>  //配好时默认是打开的

6.开启查询缓存(在hibernate.cfg.xml中):
(1)<property name="cache.use_query_cache">true</property>
(2)指定查询结果可以存入二级缓存中:
Query q = session.createQuery(hql);
q.setCacheable(true);
q.list();  //下次同样的查询时,会直接查缓存中的结果,但是也要设setCacheable为true
第二次查:
q = session.createQuery(hql);
q.setCacheable(true);  //要设这一句
q.list(); 


初始化属性:
Hibernate.initialize(属性名);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值