Hibernate九阴真经

一、导入jar包。

二、创建实体类(javabean)

*hibernate 要求实体类中必须有一个属性是唯一的

*使用hibernate不需要我们自己手动创建数据库表,hibernate会帮我们把表创建

三、配置实体类与数据库表的对应关系(ORM映射 )

1、创建xml格式的配置文件

映射配置文件和名称没有固定要求,建议:实体类所在包里面创建,实体类名称.xml

2、配置是xml格式,在配置文件中首先引入xml约束

学过约束dtd/schema,在hibernate中都是用dtd;

3、配置映射关系

<hibernate-mapping>

       <class name=”实体类全路径”  table=”数据库表名称”>配置表与对象的对应关系

  <id name=”实体类的唯一属性” column=”数据库表中的对应列名”>

  <generator class=”native”></generator>配置自增长属性

</id>

<property name=”实体类属性” column=”数据库表列名”></property>注意属性名与列名要一一对应,必须相同名,column可以省略默认与属性名一样;type=”表中字段类型varchar等不写默认与属性类型相同”;

<property name=”实体类属性” column=”数据库表列名”></property>

……

</class>

</hibernate-mapping>

四、创建hibernate核心配置文件

1、位置:必须在src下

名称:固定hibernate.cfg.xml

2、引入约束

3、hibernate操作过程中,只会加载核心配置文件,其他配置文件不会加载

      (1)配置数据库信息

      (2)配置hibernate信息

      (3)把映射文件放到核心配置文件中

<hibernate-configuration>

       <session-factory>

  配置数据库信息(必须)

<property name=”hibernate.connection.diver.class”>com.mysql.jdbc.Driver</property>

<property name=”hibernate.connection.url”>jdbc:mysql:///hibernate_01</property>

<property name=”hibernate.connection.username”>root</property>

<property name=”hibernate.connection.password”>123</property>

……(配置数据库四大参数)

  配置hibernate信息(可选)

<property name=”hibernate.show_sql”>true</property> 输出底层sql语句

<property name=”hibernate.formate_sql”>true</property>输出sql语句格式

<property name=”hibernate.hbm2ddl.auto”>update</property>自动创建表,update:有则更新,无则创建;

<property name=”hibernate.dialect”>org.hibernate.dialect.MySQLDialect</property>配置数据库方言,例如在mysql中使用limit/oracle中使用rownum进行分页

  把映射文件放到核心配置文件中(必须)

<mapping resource=”映射配置文件的全路径”/>

</session-factory>

</hibernate-configuration>

五、代码逻辑

1、加载配置文件

Configuration conf = new Configuration();

conf.configure();

调用方法后src下hibernate核心配置文件就被加载完成

2、创建SessionFactory(重点)

SessionFactory  sf = conf.buildSessionFactory();

根据核心配置文件,有数据库配置,有映射文件部分,到数据库里面根据映射关系创建表

创建过程特别耗损资源,建议一个项目一般创建一个SessionFactory对象,(静态代码块实现);

private static Confiuration conf  =null;

private static SessionFactory sf =null;

static{

       new Configuration();

       conf.confiure();

       sf = conf.buildSessionFactory();

}

3、得到Session

Session session = sf.openSession();

理解:类似于jsbc中的connection

调用session里面不同的方法实现crud操作:

(1)添加save();

(2)修改update();

(3)删除delete();

(4)按照id查询get(id);

……

session是单线程对象,每个人只能用自己的(ThreadLocal);

4、Transaction 事物

Transaction tx = session.beginTransaction();

主要方法:tx.commit(); tx.rollback();

?解决配置文件没有提示的问题:

1、可以上网,会自动引入提示;

2、把约束文件引入到eclipse中,window-preferences  搜索xml Catalog  点击add 将配置文件路径复制到 URI(要选)下  ,点击file System 寻找到本地约束文件 ,点击OK结束;重启eclipse;

 

六、hibernate主键生成策略:

native:代理主键,自动增长;

uuid:hibernate会自动帮我们生成一个32位16进制字符串;

例:实体类中定义唯一属性 private String uid;

      映射配置文件给uid设置uuid  <generator class=”uuid”></ generator>

七、对实体类的增删改查操作

添加操作:User.setUsername(“xiaoma”); user.setAge(10);  session.save();

根据id查询:

1、调用session中的get方法实现;

2、代码如下:

SessionFactory sf = HibernateUtils.getSessionFactory();

Session session = sessionFactory.openSession();

Transaction tx = session beginTransaction();

User user = session.get(User.class,id值);

tx.commit();

session.close();

sf.close();

修改操作:

1、首先查询;

User user = session.get(User.class,2);

2、修改;

user.setUsername(“李连杰”);

session.update(user); 底层是到对象中找到id 然后根据id进行修改

删除操作

1调用delete方法实现一;

User user = session.get(User.class,1);

session.delete(user);

2、调用delete方式实现二:

User user = new User();

user.setUid(1);    session.delete(user);

八、实体类对象状态(概念)

1瞬时态:对象里面没有id值,跟session没有关联

2持久态:对象里面有di值并且与session有关联

3托管态:对象里面有id值但是对象跟session没有关联

saveOrUpdate方法:

可以实现添加也能实现修改;瞬时态进行添加,托管态进行修改;持久态进行修改;(有id值就行修改,没id就执行添加)

User user = new User();

user.setUsername(“jack”);

user.setUid(4);

session.saveOrUpdate(user);

九、hibernate的一级缓存

什么是缓存?

数据存到数据库里面,数据库本身就是文件系统,java中使用流来操作文件,效率不高。

(1)把数据存到内存里面,不需要使用流方式,可以直接读取内存中数据

(2)把数据放到内存中,提高读取效率;

hibernate缓存

1hibernate框架中提供很多优化方式,hibernate的缓存就是一个优化方式

2hibernate缓存特点:

(1)hibernate的一级缓存

hibernate的一级缓存默认打开的

hibernate的一级缓存使用范围,是session范围

(2)hibernate的二级缓存

目前不使用,替代技术redis;

默认不打开

范围sessionFactory

验证一级缓存存在

1验证方式

(1)首先根据uid=1查询,返回对象,发送sql语句;

(2)再次根据uid查询,直接返回对象,不执行sql语句;

一级缓存特性:

持久态自动更新数据库,

User user = session.get(User.class,1);

user.setUsername(“hansan”);   不调用update方法也会修改数据库

十、hibernate事物代码规范

事物概念:

1什么是事物?一组操作有一个失败都失败

2事物特性:原子性、一致性、隔离性、持久性

3不考虑隔离性的问题?脏读、不可重复读、虚读 

解决办法: 设置事物隔离级别  repeatable read(mysql默认)

事物代码结构:

Transaction tx=null;

try{

tx.beginTransaction();

….操作数据库代码

tx.commit();

}catch(Exception e){

tx.rollBack();

}

十一、Hibernate绑定Session

获取与本地线程绑定的session

1、在hibernate核心配置文件中进行配置:

<property name=”hibernate.current_session_context_class”>thread</property>

2、调用SessionFactory.getCurrentSession();得到与当前线程绑定的session(底层依然是threadlocal)。

3、获取本地线程绑定session,关闭session报错,不需要手动关闭;

十二、查询(所有内容)

api:

Query 对象:

Query q = session.createQuery(“from User”); from+实体类名

List<User> users = q.list();

for(User u:users)(syout(u));

Criteria 对象:              

Criteria c =session.createCriteria(User.class);

List<User>users = c.list();

SQLQuery 对象:

1使用hibernate时候,也可以来调用底层sql来实现,而SQLQuery就能编写sql语句;

SQLQuery sql = session.createSQLQuery(“select * from user”);

List<Object[]> users = sql.list();返回的list每个元素是一个数组;

for(Object[] array : users){Arrays.toString(array)}

修改返回数据中每部分是对象而不是数组;

sql.addEntity(User.class);

List<User> users = sql.list();

for(User user : users){sysout(user)}

 

十三、Hibernate 一对多操作

一对多映射配置:

第一步 创建实体类(例如 商品与分类就是一对多关系)

第二步 让两个实体类之间互相关联  (分类是一的一方,商品是多的一方)

在分类中创建一个set集合,无序、可重复;(Hibernate规定set)

Set<Book> books = new HashSet<Book>();

在商品实体类中 添加

private Category category; 属性以及get /set方法;

第三步 配置映射文件

1、配置好两张表基本的映射关系;

2、映射文件中,配置一对多关系

分类实体类的配置:(分类中表示商品)

<set name=”books”>

       <key column=”外键”></key>

       <one-to-many class=”被关联实体类的全路径”/>

</set>

商品实体类的配置:(商品中表示所属分类)

<many-to-one name=”category” class=”被关联实体类全路径” column=”外键”></ many-to-one>

第四步 创建核心配置文件,把映射文件引入到核心配置文件

要将两个映射文件都引入到核心配置文件中;

一对多级联操作:

简化写法:

第一步

在映射文件中的set标签中 添加cascade=”save-update”

<set name=”set集合名称” cascade=”save-update”>

示例代码:

一个公司有多个联系人, 一个联系人只属于一个公司 

实现方式一:没有配置映射文件cascade=”save-update”

Company comp = new Company();

comp.setCname(“百度”);

comp.setCphone(“13314445555”);

LinkedMan lman = new LinkedMan();

lman.setLname(“李彦宏”);

lman.setLphone(“18845888888”);

comp.getLinkedManSet().add(lman);

lman.setCompany(comp);

session.save(comp);

session.save(lman);

实现方式二:配置完映射文件

Company comp = new Company();

comp.setCname(“百度”);

comp.setCphone(“13314445555”);

LinkedMan lman = new LinkedMan();

lman.setLname(“李彦宏”);

lman.setLphone(“18845888888”);

comp.getLinkedManSet().add(lman);

session.save(comp);

 

一对多修改外键操作:

Company comp =session.get(Compant.class,1);  //id查询

LinkedMan lm = session.get(LinkedMan.class,1);

comp.getLinkedManSet().add(lm);

lm.setCompany(comp);

因为是持久态对象,所以不用保存,也会执行;

inverse属性:因为hibernate双向维护外键,所以会update两次外键,降低了效率,解决办法,让其中的一方(多方维护外键)不维护外键;

在一方的映射文件中添加inverse=”true” ,表示放弃关系维护;

<set name=”set集合名称” inverse=”true” cascade=”save-update”>

十四、Hibernate多对多操作

多对多映射配置

第一步 创建实体类(Role /user)

第二步  让两个实体类互相表示(在实体类中分别创建一个set集合表示多对多关系)

Role{Set<User> setUser = new HashSet<User>();}

User{Set<Role> setRole=new hashSet<Role>();}

第三步  配置映射文件

(1)基本配置()

cn.wyx.User   实体类的配置文件

<class name=”实体类全路径” table=”数据库中表名”>

    <id  name=”id值” colum=”表中列名与实体类属性名必须相同”>

          <generator class=”native”></generator>

</id>

<property name=”username” colum=”username”></property>

……

<set cascade=”save-update” name=”setRole” table=”user-role” >第三张表的名字

         <key colum=”userid”></key>当前实体类在第三张表中的外键

         <many-to-many  class=”cn.wyx.Role” colum=”roleid”></many-yo-many>关联的哪个实体类,以及该类在第三张表中的外键

</set>

</class>

cn.wyx.Role   实体类的配置文件

<class name=”cn.wyx.Role” table=”role”>

    <id  name=”rid” colum=”rid”>

          <generator class=”native”></generator>

</id>

<property name=”rname” colum=”rname”></property>

……

<set name=”setUser” table=”user-role”>第三张表的名字

         <key colum=”rid”></key>当前实体类在第三张表中的外键

         <many-to-many  class=”cn.wyx.User” colum=”uid”></many-yo-many>关联的哪个实体类,以及该类在第三张表中的外键

</set>

</class>

 

(2)配置多对多映射(创建第三张表)

第四步 配置核心配置文件

<mapping resource=””></mapping>

级联添加、删除(操作第三张表)

根据用户保存角色

第一步 在用户配置文件中set标签进行配置,cascade = “save-update”

第二步 代码实现

User user1 = new User();

user1.setUserName(“lucy”);

user1.setPassword(“123”);

 

User user2 = new User();

user2.setUserName(“lucy”);

user2.setPassword(“123”);

 

Role r1 = new Role();

r1.setRname(“总经理”);

 

Role r2 = new Role();

r2.setRname(“CEO”);

Role r3 = new Role();

r3.setRname(“技术总监”);

user1.getSetRole().add(r1);

user1.getSetRole().add(r2);

user2.getSetRole().add(r1);

user2.getSetRole().add(r3);

session.save(user1);

session.save(user2);

级联删除配置:(不参考使用)

set   标签中添加cascade=”delete”

User user=session.get(User.class,1);

session.delete(user);

维护第三张表:(重点)

1、让某个用户有某个角色

第一步:根据id查询出用户和角色

User user = session.get(User.class,1);

Role role = session.get(Role.class,1);

第二步:把角色放到用户里面

user.getSetRole().add(role);

2、让用户没有某个角色

第一步:根据id查询角色和用户

User user = session.get(User.class,1);

Role role = session.get(Role.class,1);

 

第二步:从setRole集合中删除这个角色

user.getSetRole().remove(role);

 

 

十五、查询

对象导航查询:

public void test(){

      SessionFactory sf=null;

      Session session=null;

      Transaction tx=null;

      try{

           sf = HibernateUtils.getSessionFactory();

           session = sf.openSessioin();

           tx = session.beginTransaction();

           Category category = session.get(Category.class,1);

           Category <Book> cset = category.getSetCategory();

           sysout(cset.size());

           tx.commit();

}catch(Exception e){

           tx.rollback();

}

}

OID查询

Category category = session.get(Category.class,1); //就是根据id查询

 

HQL查询

第一步:使用query对象,写hql语句;

第二步:调用query方法得到结果;

例1:查询客户表中所有数据?(查询所有)

Query query = session.createQuery(“from  实体类名称”);

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

for(Customer cut : list){sysout(cut.getName()+cut.getPassword())}

例2:从customer表中查询 cid=1 cusName=”百度”的数据?(where条件查询)

hql语句格式:

from 实体类名 where 实体类属性名 =? and 实体类属性名=?;

from 实体类名 where 实体类属性名 like? and 实体类属性名  like?;(用法同上传递参数可以加%参数名%)

Query query = session.createQuery(“from Customer where cid=? and custName=?”);

query.setParameter(0,1); //参数位置从0开始,第0个参数的cid值为1;

query.setParameter(1,”百度”);

Set<Customer> set = query.llist();

例3:根据cid排序?(排序查询)

hql格式:from  类名 order by  实体类属性名  desc/asc

例4:查询所有数据,从0开始显示3行?(分页查询)

在hql中没有limit,而是用Hibernate中的方法来代替;

Query query = session.createQuery(“from Customer”);

query.setFirstResult(0);//设置开始位置

query.setMaxResult(3);//设置每页记录数

list<Customer>list=query.list();

例5:查询表中指定某一列的值?(投影查询)

hql格式:select 实体类属性名 from 实体类名

Query query = session.createQuery(“select custName  from  Customer”);

List<Object> list = query.lislt();

 

例6:查询表中指定某一列的值?(聚合函数查询)

1、常用聚合函数:count/sum/avg/max/min

hql格式:select count(*) from 实体类名

Query  query = session.createQuery(“select count(*) from Customer”);

Object obj = query.uniqueResult();

//注意不能直接把obj强转成int,要先转换成Long类型,再转成int;

obj = (Long)obj.intValue();

 sysout(obj);

例7:客户与联系人为例(多表查询)

1、内连接

hql格式: from 实体类名  别名  inner join  别名.实体类set集合名

Query query = session.createQuery(“from Customer c inner join c.ManLinkedSet”);

List<Customer> list = query.list();  //集合中每个元素都是一个数组

2、左外连接

hql格式:from Customer c left outer join c.LinkedManSet(返回list元素数组)

3、右外连接

hql格式:from  Customer c inner join c.ManLinkedSet(没有迫切连接只能返回数组元素)

4、迫切内连接

与内连接的实现一样,区别在于返回list的每部分是对象;

hql格式: from  Customer c inner join fetch c.ManLinkedSet

5、迫切左外连接

hql格式:from Customer c left outer join fetch  c.LinkedManSet(返回list元素对象)

 

QBC查询

第一步:创建Criteria;

第二步:调用方法得到结果;

1、查询所有

Criteria criteria = session.createCriteria(Customer.class);

List<Customer>list = criteria.list();

2、条件查询

Criteria criteria = session.createCriteria(Customer.class);

criteria.add(Restrictions.eq(“类中属性名”,值));//添加条件

criteria.add(Restrictions.eq(“cid”,1));

criteria.add(Restrictions.eq(“custName”,”百度”));

List<Customer> list = criteria.list();

3、排序查询

Criteria criteria = session.createCriteria(Customer.class);

//设置对哪个属性进行排序,以及排序规则

criteria.addOrder(Order.asc(“cid”));  升序

List<Customer> list = criteria.list();

4、分页查询

Criteria criteria = session.createCriteria(Customer.class);

criteria.setFirstResult(0);

criteria.setMaxResult(10);

List<Customer> list = criteria.list();

5、统计查询

Criteria criteria = session.createCriteria(Customer.class);

criteria.setProjection(Projections.rowCount());//设置操作

Object obj = criteria.uniqueResult();//调用方法得到结果

int count = (Long)obj.intValue();

6、离线查询

//离线:不用session也可以创建Criteria对象,以及基本操作;

//创建离线对象

DetachedCriteria detachedCriteria = DetachedCriteria.forClass(实体类.class);

//最终执行时候才需要得到session

Criteria criteria = detachedCriteria.getExecutableCriteria(session);

List<Customer> list = criteria.list();

用处:在dao里面使用hibernate框架时候,最终需要调用session里面的方法实现功能,但是查询条件,可以写在servlet中,来传给dao,而servlet 用离线对象维护;

十六、Hibernate 检索策略

第一类   立即查询:根据id查询,调用get()方法立即去查询;

第二类     延迟查询:根据id查询,当调用load方法,不会马上发送语句查询数据,只有得到对象里面的值时候才会发送语句查询数据库;

Customer customer = session.load(Customer.class,1);

调用方法之后,不会发送语句,返回对象里面只有id值,当后面语句得到不是id值的时候才会发送语句;

例如:customer.getCustName();  就会发送语句

延迟查询中又分两类:

(1)类级别延迟:根据id查询返回实体类对象,load方法就是类级别延迟;

(2)关联级别延迟:查询出某个客户,在查询出这个客户的联系人,查询客户所有联系人的过程是否需要延迟,这个过程称为关联级别延迟;(Hibernate默认使用)

关联级别延迟修改:

1、在映射文件中进行配置

2、在set标签上使用属性

(1)fetch:select(默认)

(2)lazy:

true 延迟(默认)

false立即

extra 最延迟(要什么值发送什么语句,效率更好,但是需要发送多次语句效率就会变低)

批量抓取:

1、查询所有的客户,返回list集合,遍历list集合,得到每个用户,得到每个用户联系人;

通常我们操作会发送大量sql语句,采用批量抓取就会优化性能;

在映射文件的set标签中进行配置

添加属性 batch-size=”10”  数值自己定,但是越大发送sql语句越少;