Hibernate

1:Hibernate是什么?

Hibernate是对JDBC进行轻量级封装的ORM框架,在项目中处于持久层的位置;即便不是在web项目中,java application程序也可以使用;也可以使用Hibernate,它跟Struts2不一样,Struts2是基于MVC的web层框架,必须用在web项目中

 

ORM解释:object relationship mapping(java程序中都是对象,数据库是关系类型的,两者类型不匹配,要想把对象存进关系数据库,就得出现一种新技术,把对象转换为关系型数据,存进数据库,Hibernate只是ORM技术的一种,还有iBatis)

 

PO类:persistent Objects 持久化类

 

持久化:就是将数据保存起来,要么存在文件中,要么存在数据库中;Hibernate的持久化就是将java对象保存到数据库中;

 

2:为什么要使用Hibernate?

如果现在没有Hibernate,那么之前的项目要更换数据库(从mysql-àOracle),那么业务逻辑层的代码就得重新编写SQL语句,另外JDBC使用PreparedStatement来预编译SQL语句,其中参数用?表示,然后set,这样字段多的话,比较麻烦;第三点:一般的程序员希望只关心业务逻辑层,而不去关心你的项目中到底使用了什么类型的数据库

现在出现了Hibernate的好处:

(1)   使用HQL语句代替SQL语句

(2)   使用QueryByParams()方法,将要操作的字段存放在String[]params中,操作更方便

(3)   分层更清晰,使得程序的耦合性更低

(4)   使程序员专注于业务流程,不用考虑底层的数据库

(5)   将关系数据库转化为java对象,让程序员将更多的经历放在面向对象的研究上

(6)   使用Hibernate之后,即便项目想更换数据库,那么只需要修改配置文件中5个属性,DriverClassName,Url,user,password,Dialect即可

 

**hibernate虽然与数据库无关,但是切换数据库的时候,DriverClassName url user password ,Dialect都得在配置文件中进行修改

 

3:如何使用(学习)Hibernate?

(1)   Hibernate的两个配置文件

hibernate.cfg.xml---àhibernate连接数据库的配置文件

user.xml  -àhibernate的对象关系映射文件

 

hibernate.properties也是一种配置文件,但是现在常用的还是xml文件

 

(2)   PO类的编写

 

(3)   处于DAO层的6个接口与类

Configuration---Class

sessionRegistry  ----Interface

sessionFactory   ---Interface

session           --Interface

Transaction   ---interface

Query            --Interface

 

 

 

       4:Hibernate的创建步骤

(1)   先写PO类(domain类,javabean,POJO)-àmapping文件-àDB

(2)   先创建DB,用工具生成PO类跟Mapping文件;

小项目使用第一种就可以,大项目,一定得先设计好数据库

 

5:使用Hibernate的9个核心组件

(1)   导入Hibernate的jar包

(2)   编写PO类

(3)   写Hibernate.cfg.xml文件跟use.xml文件

(4)   编写测试类,使用6个接口跟类

 

 

 

(1)      先写PO类,User.java

Po类的条件

(a)   要 implements Serializable接口

(b)   类名跟表名一致,首字母大写

(c)   表中的字段要跟类中的成员属性想对应,且都是private的,id要用Integer类型,或者Long类型(大项目中的,小项目就有Integer就行)

(d)   无参的构造函数

(e)   Setter getter 方法

 

 

import java.io.Serializable;

 

@SuppressWarnings("serial")

publicclass User implements Serializable {

 

    private Integer id;

    private String username;

    private String password;

 

    public User() {

 

    }

 

    public User(Integer id, String username, String password) {

       super();

       this.id = id;

       this.username = username;

       this.password = password;

    }

 

    Settergetter略。。。。。。。

 

}

 

 

hibernate.cfg.xml文件【用来配置连接数据库的参数,以及配置映射文件】(Hibernate默认的文件名,也可以另取它名,单是在Configurationconfiguration = new Configuration().configure();)中的configure()必须指定

 

 

<?xml version="1.0"encoding="utf-8"?>

<!DOCTYPE hibernate-configuration PUBLIC

    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

       <!--连接mysql的配置文件,这里使用mysql-->

       <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

       <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

       <property name="hibernate.connection.url">jdbc:mysql:///hibernate_test</property>

       <property name="hibernate.connection.user">root</property>

       <property name="hibernate.connection.password">system</property>

      

       <!-- 连接Oracle的配置属性-->

       <!--

       <propertyname="dialect">org.hibernate.dialect.OracleDialect</property>

       <propertyname="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orclhsp</property>

       <propertyname="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

       <property name="connection.username">scott</property>

       <propertyname="connection.password">tiger</property>

       -->

      

      

       <!-- 在控制台输出sql语句-->

       <property name="hibernate.show_sql">true</property>

       <!--格式化sql语句-->

       <property name="hibernate.format_sql">true</property>

 

<!--自动建表,有uapdate,create等属性,

Create:创建并替换原有的表

Update:不替换原有的表,只更新数据

Crate-drop:在sessionFactory关闭的时候,表也会被删除

Validate:验证数据库表结构跟mapping文件的结构是否一致

-->

       <property name="hibernate.hbm2ddl.auto">update</property>

      

       <mapping resource="user.xml"/>

    </session-factory>

</hibernate-configuration> 

 

 

User.xml文件【对象关系的映射文件,指定java对象跟数据库的映射关系】

 

<?xml version="1.0"encoding="utf-8"?>

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

   

<hibernate-mapping package="test.entity">

    <class name="User" ><!--类名与表名一致,不需要再指定table属性-->

       <id name="id">

    <!--主键生成策略,此处使用native通用的,还有序列、自增等其他类型 -->

           <generator class="native"/>

       </id>

       <property name="username"/>

       <property name="password"length="32" />

    </class>

</hibernate-mapping>   

 

 

Test.java文件

 

publicclass Test {

 

    publicstaticvoid main(String[] args) {

      

       //读取hibernate.cfg.xml的配置文件,并完成初始化

       Configuration configuration = new Configuration().configure();

       //创建serviceRegistry对象

       ServiceRegistry serviceRegistry = newServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();

       //创建sessionFactory,比较耗费资源,应该设计成单例模式

       SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);

       //创建session,用来操作saveupdatedelete

       //在后面的SSH框架整合中,session的创建使用sessionFactory.getCurrentSession()来创建,原因:

       //openSession()打开session,需要手动关闭,getCurrentSession()自动关闭,不需要手动关闭

       Session session = sessionFactory.openSession();

       //开始一个事务,Hibernate的事务是需要自动commit的,一执行beginTransaction(),就会调用JDBCsetAutoCommit(false)方法    Transaction transaction =session.beginTransaction();

 

       User user = new User(null, "张三", "123");

      

       session.save(user);

       transaction.commit();

      

       session.close();

       //sessionFactory.close();不应该关闭,每次打开耗费资源

      

    }

   

}

 

 

*******在最后的项目中,使用的是Annotation的方式来替代Hibernate的两个配置文件

Hibernate.cfg.xml文件内容放在application.xml文件中,对象映射文件User.xml则删除,在

PO类中用Annotation代替;

 

 

(1)      hibernate.cfg.xml:配置与数据库的连接参数跟对象关系文件的映射

(2)      user.xml指定PO类与表的对应关系

(3)      PO类含义,上面提到过

(4)      Configurationà读取hibernate.cfg.xml的配置信息,以及加载驱动,连接数据库

(5)      ServiceRegistry()configuration一起创建sessionFactory

 

 

(6)      sessionFactory

(用来生产session,一个session实例代表与数据库的一次操作;一个DB对应一个sessionFactory,要设计成单例)

 

  (a) sessionFactory可以缓存SQL语句

(b) sessionFactory获取session的两种方式,openSession(),getCurrentSession();两者区别

 

1.      通过 getCurrentSession() 获取的session在事务提交后,会自动关闭,通过openSession()获取的session则必须手动关闭,session.commit();

2.      openSession() 是获取一个新的session;getCurrentSession () 获取的是在同一个线程中的session,这样可以利于事务控制;SSH整合中的声明式事务处理,用到的就是getCurrentSession();

3.      对数据库进行查询,openSession()方式不需要提交事务,getCurrentSession()进行数据查询必须得开启事务,而且需要transaction.commit();

4. Session是线程不同步的(不安全),因此要保证在同一线程中使用,就需要用getCurrentSessiong()。

 

 

 

(7)      Session接口

(a)   Session一个实例代表与数据库的一次操作(crud)

(b)   Session是持久化管理器,与持久化操作相关的接口(save,delete,update,get/load);

 

*******session.get()跟session.load()的区别

(1)   如果查询不到数据,get 会返回 null,但是不会报错, load 如果查询不到数据,则报错ObjectNotFoundException;

(2)   使用load()去查询数据,先去一级缓存跟二级缓存中去查询,如果查询到了,则返回一个实体类的代理对象;如果在缓存中没有查询到数据,而用户也不去使用数据,那么load()方法也不会去DB中查询,就这样等着,如果用户要使用这个对象了,load()方法再去DB查询(这时会发select语句),并将数据保存在缓存中;这样的方式称之为lazy懒加载的方式;

****(取消lazy的方式,在配置文件中将值设为false)*********

(3)   使用get()方式去查询,也是先到一级缓存,二级缓存中查询,如果有,就返回实体对象;没有的话,就立即向DB发送select语句去查询,查询到了,返回给用户,没有查询到,则返回NULL;

 

 

 

(8)   Transaction-à接口【悲观锁,乐观锁(见后面)】

Hibernate的事务是由session跟Transaction接口完成的

Transactiontx=session.beginTransaction();

       Tx.commit();

       Tx.rollback();

 

更改上面的Test.java文件

 

public classTest {

 

       @SuppressWarnings("unchecked")

       publicstatic void main(String[] args) {

             

              //读取hibernate.cfg.xml的配置文件,并完成初始化

              Configurationconfiguration = new Configuration().configure();

              //创建serviceRegistry对象

              ServiceRegistryserviceRegistry = newServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();

             

              SessionFactorysessionFactory=null;

              Sessionsession=null;

              Transactiontransaction=null;

              try{

                     sessionFactory=configuration.buildSessionFactory(serviceRegistry);

                      session=sessionFactory.getCurrentSession();

                      transaction=session.beginTransaction();

                     //增强for循环取

Query query=session.createQuery("from User");

                     List<User>list=query.list();

                     for(Useruser:list){

                            System.out.println(user.getUsername());

                     }

                     //迭代器取

                     Iterator<User>iterator=query.iterate();

                     while(iterator.hasNext()){

                            Useruser=iterator.next();

                            System.out.println(user.getUsername());

                     }

                    

                     transaction.commit();

                    

              }catch (Exception e) {

                     e.printStackTrace();

                     if(transaction!=null) {

                            transaction.rollback();

                     }

                     thrownew RuntimeException(e.getMessage());

              }finally{

                     if(session!=null && session.isOpen()) {

                            session.close();

                     }

              }

             

             

             

       }

      

}

 

 

 

 

(9) Query --à接口【HQL语句-à实体对象关联映射(见后面)】

Queryquery=session.createQuery(“HQL语句”);

      

query.list();query.iterator()区别

       session,get(),session.load()的区别;后者根据id进行查询

      

 

HQL语句

 

(A) 查询某个实体对象的全部属性HQL--àfrom User

//增强for循环方式

          List<User> list=session.createQuery("from User").list();

          for (User user : list) {

            System.out.println(user.getUsername());

         }

          //Iterator方式

          Iterator<User>iterator=session.createQuery("fromUser").iterate();

          while(iterator.hasNext()){

             User user=iterator.next();

             System.out.println(user.getUsername());

          }

 

 

 

(B)  查询某个实体对象的部分属性【投影查询】 

HQL-àselect username,useraddr from User;

 

//下面的代码会报错,username,userid,不能转换成一个User对象

            List<User> list2=session.createQuery("select username,userid from User").list();

            for (User user:list) {

              System.out.println(user.getUsername());

           }

            

            //下面的可以

           List list3=session.createQuery("select usernameuseraddr from User").list();

           for (int i = 0; i <list3.size(); i++) {

              //将数据封装成对象数组,此时的list3中存放的都是object[]对象。

              Object[] objs=(Object[]) list3.get(i);

              System.out.println(objs[0].toString());

           }

           //要将数据进行二次封装才可以使用,没有第一种方式好;尤其在实体对象关联查询的时候,应当将全部属性都查出;

       

 

对象的三种状态

 

主要的依据是:

1. 看该对象是否处于session的管理之下

2, 看在数据库中有没有对应的记录

瞬时态: 没有session管理,同时数据库没有对应记录

持久态: 有session管理,同时在数据库中有记录

脱管态/游离态: 没有session管理,但是在数据库中有记录.

 

 

 

 

 

 

 

 

实体对象

 

单向一对多

class Channel{

@onetomany

@joincolumn(name=”channel_id”)

private set<Article> articles=new HashSet<Aritcle>();   

}

 

单向多对一【韩顺平第一讲,多对一没有set<>集合,get()方法取出的只是多端中的普通成员属性值,而关联的另一个实体对象的值是无法取到的,若想取到关联的那一端,必须关闭lazy】

class Aricle{

private Channel channel;

}

 

双向一对多【韩顺平第二讲,两个实体类都关联了对应的entity,只要根据id就可以查询出全部】

Class Channel{

       Privateset<Article> articles=new HashSet<Article>();

}

class Article{

       privateChannel channel;

       privateAdmin admin;

}

 

 

基于主键的一对一关系

 

 

基于外键的一对一关系(外键要unique)

 

 

多对多关系【分解成一对多跟多对一的关系】

 

级联操作

 

 

 

 

 

(10)缓存与优化

1:懒加载:---àload()方法中,单向多对一中:代理机制

 

2:缓存:一级缓存(session),二级缓存(sessionFactory),查询缓存

缓存的好处:减少对数据库的访问???

 

一级缓存(session缓存)

 

get()获取数据的时候,先到一级缓存中查找,如果有的话,就返回给客户,没有的话,就会发出select语句,去查询DB,并将结果放进一级缓存中;

 

save()方法为什么还有缓存呢?因为以后的程序可能会用带save()保存的对象,所以为了方便就放进一级缓存中,然后transaction.commit();事务提交的时候,才会把数据添加到数据库中

----à什么样的操作会向一级缓存放入数据?

Save(),upadate(),saveorUpdate(),list(),iterator(),get(),load()

----à什么样的操作会向一级缓存取出数据?get load list uniqueResult

get load会从数据库中取出数据

list(),uniqueResult()不会从缓存中取出数据

证明方法:show_sql,查看select语句

 

Session缓存的生命周期

getCurrentSession()或者openSession()开始,到session.close()结束

 

       session缓存的清除

session.evict(对象名)

session.clear();

 

 

 

二级缓存(sessionFactory)

 

为什么要有二级缓存?

一级缓存的内存有限以及生命周期短,使用二级缓存来拟补这个问题

 

二级缓存生命周期长,可以存在于内存中,也可以存在于硬盘上

 

二级缓存的配置(hibernate.cfg.xml文件中配置)

       <!-- 启动二级缓存 -->

       <propertyname="cache.use_second_level_cache">true</property>

       <!-- 指定使用哪种二级缓存 -->

       <propertyname="cache.provider_class">org.hibernate.cache.OSCacheProvider</property>

 

特别说明二级缓存策略:

       1. read-only

       2. read-write

       3. nonstrict-read-write

       4. transcational

       -->

       <class-cacheclass="com.hsp.domain.Student" usage="read-write"/>

 

 

主键增长策略

increment 自增

identity 自增

sequence (Oracle)

native 通用的

foreign 外键 

uuid(主键只能是String类型)

assigned

 

 

什么情况下不适合使用Hibernate??

在大型项目中,数据访问量大的情况下不适用

对Hibernate不熟悉的情况下不适用

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值