Hibernate的基础入门--笔记(二)

1.持久化类的编写规范

  遵从JavaBean的编写规范.

  什么是JavaBean?

    bean:在软件开发领域,Bean表示可重用组件.

      JavaBean就是用Java语言开发的可重用组件.

  JavaBean的编写规范是什么?

    类都是public的

    都有默认无参构造函数

    成员变量都是私有的

    都有公有的get/set方法

    一般都实现Serializable接口

  基本类型和包装类的选择问题?

    包装类可以有null值.所以实际开发中都是用包装类.

2.主键生成策略(native之外的取值) 

  代理主键:不参与程序业务,只是用于区分表中数据的.

  自然主键:参与程序业务.同时也能区分表中数据.

 1 <?xml version="1.0"?>
 2 
 3 <!DOCTYPE hibernate-mapping PUBLIC
 4         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 5         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">          
 6 <hibernate-mapping package="com.mypro.id">
 7     <class name="User" table="user">
 8         <id name="id" column="Id" type="int">
 9             <generator class="navite"></generator>
10         </id>
11         <property name="name" column="name" type="string"></property>
12     </class>
13 </hibernate-mapping>

通过配置可以看到,我们有个实体类User,该类有一个id和name的属性与数据库中user表的id和name字段分别对应。其中

<generator class="navite"></generator>

 定义了主键的生成方式,下面我们将会介绍到我们常用的主键生成方式

  1、assigned      适用于自然主键

主键由外部程序负责生成,在 save() 之前必须指定一个,Hibernate不负责维护主键生成。也就是可以每次指定主键。该方式不推荐

2、increment      适用于代理主键

这种方式在每次插入前,需要通过“select max(主键) from 表名 ”这种方式先查询最大ID,然后通过ID+1来作为新的主键值。这种方式也不推荐,因为这样会出现线程安全问题。

3、identity      适用于代理主键

identity由底层数据库生成标识符。identity是由数据库自己生成的,但这个主键必须设置为自增长,使用identity的前提条件是底层数据库支持自动增长字段类型,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle这类没有自增字段的则不支持。

4、sequence      适用于代理主键

采用数据库提供的sequence机制生成主键,需要数据库支持sequence。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。MySQL这种不支持sequence的数据库则不行

5、hilo

hilo(高低位方式high low)是hibernate中最常用的一种生成方式,需要一张额外的表保存hi的值。保存hi值的表至少有一条记录(只与第一条记录有关),否则会出现错误。可以跨数据库。

6、native      适用于代理主键

native由hibernate根据使用的数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式,灵活性很强。如果能支持identity则使用identity,如果支持sequence则使用sequence。

7、uuid      适用于代理主键

UUID:Universally Unique Identifier,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字,标准的UUID格式为:

  xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)

3.hibernate中的对象标识符

  OID:  Object Identifier  对象标识符

  它就是hibernate用来区分两个对象是否是同一个对象的标识.

 

4.hibernate中的一级缓存

  什么是缓存?

    内存中的临时数据.

  hibernate中的一级缓存?

    它指的是Session的对象的缓存.就是由一些集合组成的.

    当我们在执行查询时,先去缓存中看看有没有数据,如果有的话,就不再去数据库中查询了.如果没有,则直接去数据库中查询.

    从而提高效率.

    当Session对象close了之后,一级缓存就消失了.

 1     /**
 2      * 证明一级缓存确实存在.
 3      * 需求:
 4      *     查询id为2的客户
 5      */
 6     @Test
 7     public void test1(){
 8         Session s = HibernateUtil.openSession();
 9         Transaction tx = s.beginTransaction();
10         //1.查询id为2的客户
11         Customer c1 = s.get(Customer.class, 2L);//先从缓存中找,没找到。去数据库中查询。存入一级缓存中
12         System.out.println(c1);
13         Customer c2 = s.get(Customer.class, 2L);//先从缓存中找,找到了,直接返回了。
14         System.out.println(c2);
15         
16         System.out.println(c1 == c2);
17         tx.commit();
18         s.close();//一级缓存
19     }
20     

  快照机制:

  

session的快照

* 使用id进行查询数据库,将查询得到的结果放置到session一级缓存中,同时复制一份数据,放置到session的快照中

* 当使用tx.commit()的时候,同时清理session的一级缓存(flush)

* 当清理session一级缓存的时候,会使用OID判断一级缓存中对象和快照中的对象进行比对

* 如果2个对象(一级缓存的对象和快照的对象)中的属性发生变化,则执行update语句,此时更新数据库,更新成一级缓存中的数据

* 如果2个对象中的属性不发生变化,此时不执行update语句

目的:确保和数据库中的数据一致   

5.hibernate中的一下方法问题

  hibernate中对象的状态

    明确:学习对象的状态是为了更好的掌握hibernate中操作的方法.

  状态的分类:

    临时状态(瞬时状态):Transient

      没有OID,和Session没有关系.

    持久化状态:Persistent

      有OID,和Session有关系.

    脱管状态(游离状态):Detached

      有OID,和Session没有关系.

    

  常用的方法:

    save和persist方法:   

 1     /**
 2      * save方法:
 3      *     保存一个实体。
 4      * 状态的转变:
 5      *     把临时态对象转成了持久态。
 6      */
 7     @Test
 8     public void test1(){
 9         Customer c = new Customer();
10         c.setCustName("修正save11");
11         c.setCustIndustry("医药");
12         c.setCustSource("网络");
13         c.setCustLevel("VIP客户");
14         c.setCustAddress("昌平区");
15         c.setCustPhone("010-98234832");
16         
17         Session s = HibernateUtil.openSession();
18         //Transaction tx = s.beginTransaction();
19         s.save(c);
20         //tx.commit();
21         s.close();//一级缓存
22     }
23     
24     /**
25      * persist方法:
26      *     保存一个实体
27      * 状态的转变:
28      *     把临时态对象转成了持久态    
29      */
30     @Test
31     public void test2(){
32         Customer c = new Customer();
33         c.setCustName("修正persist");
34         c.setCustIndustry("医药制造");
35         c.setCustSource("网络");
36         c.setCustLevel("VIP客户");
37         c.setCustAddress("昌平区");
38         c.setCustPhone("010-98234832");
39         
40         Session s = HibernateUtil.openSession();
41         //Transaction tx = s.beginTransaction();
42         s.persist(c);
43         //tx.commit();
44         s.close();//一级缓存
45 }

 

    共同点:

      都是把临时态对象转换成持久态.

    区别:

      提供者不一样:

        save方法是hibernate提供的.

        persist方法是JPA规范提供的. (JPA: Java Persistence Api --Java持久化规范)

      在没有事务的情况下:

        save会去数据库中保存,hibernate提供了一个内置的事务来执行.

        persist什么都不会做.

  delete方法:

 1     /**
 2      * delete方法
 3      * 
 4      *         
 5      */
 6     @Test
 7     public void test3(){
 8         
 9         Session s = HibernateUtil.openSession();
10         Transaction tx = s.beginTransaction();
11         //1.查询id为11的客户
12         Customer c = s.get(Customer.class, 11L);
13         //2.删除客户
14         s.delete(c);
15         tx.commit();
16         s.close();
17     }

 

    问题:当我们删除一个实体时,该实体已经被别的程序给删除了,此时会报错。

           <控制台报错>Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

  update方法:

 1     /**
 2      * update方法
 3      * 
 4      * */
 5     @Test
 6     public void test4(){
 7         
 8         Session s = HibernateUtil.openSession();
 9         Transaction tx = s.beginTransaction();
10         //1.查询id为10的客户
11         Customer c10 = s.get(Customer.class, 10L);//持久态
12         tx.commit();
13         s.close();//一级缓存没了
14         
15         //2.修改c10的客户名称
16         c10.setCustName("修正update");//脱管态
17         
18         Session s1 = HibernateUtil.openSession();
19         Transaction tx1 = s1.beginTransaction();
20         //3.查询id为10的客户
21         Customer c = s1.get(Customer.class, 10L);//持久态
22         //4.更新c10客户
23         s1.update(c10);//持久态
24         tx1.commit();
25         s1.close();//一级缓存没了
26     }

 

    

      问题:当我们更新一个脱管态实体时,一级缓存中已经包含了一个相同OID的持久态对象,会报错。

                <控制台报错> A different object with the same identifier value was already associated with the session : [com.itheima.domain.Customer#10]

    

  merge方法: 

    作用: 合并两个实体.永远是用一级缓存外的修改一级缓存内的对象. 

 1 /**
 2      * merge方法
 3      */
 4     @Test
 5     public void test5(){
 6         
 7         Session s = HibernateUtil.openSession();
 8         Transaction tx = s.beginTransaction();
 9         //1.查询id为10的客户
10         Customer c10 = s.get(Customer.class, 10L);//持久态
11         tx.commit();
12         s.close();//一级缓存没了
13         
14         //2.修改c10的客户名称
15         c10.setCustName("修正update");//脱管态
16         
17         Session s1 = HibernateUtil.openSession();
18         Transaction tx1 = s1.beginTransaction();
19         //3.查询id为10的客户
20         Customer c = s1.get(Customer.class, 10L);//持久态
21         //4.更新c10客户
22         s1.merge(c10);//持久态
23         tx1.commit();
24         s1.close();//一级缓存没了
25     }

 

  saveOrUpdate方法:

    作用:保存或更新一个实体.

    到底执行保存还是更新:

      取决于对象的状态:

        如果是临时态对象就是保存 / 如果是脱管态对象就是更新

6.满足Session的使用原则

  在hibernate中的使用数据源(连接池)

    使用步骤:

      1.导入连接池的jar包

       

      2.在hibernate主配置文件中配置

        配置连接池的提供商

1 <!-- 配置连接池的提供商 -->
2         <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

 

 1 /**
 2      * 证明是否使用了连接池
 3      */
 4     @Test
 5     public void test1(){
 6         Session s = HibernateUtil.openSession();
 7         //hibernate中使用原始JDBC对象
 8         s.doWork(new Work() {    
 9             @Override
10             public void execute(Connection conn) throws SQLException {
11                 System.out.println(conn.getClass().getName());
12             }
13         });
14     }

 

 

 配置hibernate中一个线程只能有一个session的方式:

    配置步骤:

      1.在hibernate主配置文件中配置

1 <!-- 把Session绑定到当前线程上 -->
2         <property name="hibernate.current_session_context_class">thread</property>

 

      2.获取Session时使用的方法

 1 /**
 2      * Session的使用原则:
 3      *         一个线程只应该有一个Session对象
 4      */
 5     @Test
 6     public void test2(){
 7         Session s1 = HibernateUtil.getCurrentSession();
 8         Session s2 = HibernateUtil.getCurrentSession();
 9         System.out.println(s1 == s2);
10     }

     细节:

      当我们把Session绑定到当前线程之后,关闭Session就是Hibernate来做的,我们就不需要关了.

 

7.查询对象的使用(入门,讲解在(四))

  Query   <掌握>

 1 /**
 2  * hibernate中的查询对象
 3  *     Query:
 4  *         作用:使用的是HQL语句查询
 5  *         如何获取:
 6  *             session.createQuery(String hql);
 7  *         常用方法:
 8  *             list():获取结果集
 9  *             setXXXX方法():给参数占位符赋值用的。XXXX表示的是数据类型。  比如:setString(int index,String param)  setObject(int index,Object obj)
10  *                          在给参数占位符赋值时,索引位置是从0开始的12  *
13  */
14 public class HibernateDemo4 {
15 
16     /**
17      * 查询所有
18      */
19     @Test
20     public void test1(){
21         Session s = HibernateUtil.getCurrentSession();
22         Transaction tx = s.beginTransaction();
23         //1.获取Query对象
24         Query query = s.createQuery("from Customer");
25         //2.执行list方法获取结果集
26         List list = query.list();
27         tx.commit();
28 
29         
30         for(Object o : list){
31             System.out.println(o);
32         }
33     }
34     
35     /**
36      * 查询客户:
37      *     带有条件:客户级别是VIP客户
38      */
39     @Test
40     public void test2(){
41         Session s = HibernateUtil.getCurrentSession();
42         Transaction tx = s.beginTransaction();
43         //1.获取Query对象
44         Query query = s.createQuery("from Customer where custLevel = ? and custName like ?   ");
45         //2.给参数占位符赋值
46         query.setString(0, "VIP客户");
47         query.setString(1, "%大%");
48         //3.执行list方法获取结果集
49         List list = query.list();
50         tx.commit();
51 
52         
53         for(Object o : list){
54             System.out.println(o);
55         }
56     }
57     
58     /**
59      * 具名查询:
60      *      给参数占位符提供一个具体的名称
61      * 参数名称的写法:
62      *         :名称
63      * 给占位符赋值时:
64      *         注意:不需要写冒号,直接写名称
65      */
66     @Test
67     public void test3(){
68         Session s = HibernateUtil.getCurrentSession();
69         Transaction tx = s.beginTransaction();
70         //1.获取Query对象
71         Query query = s.createQuery("from Customer where custName like :custName  and custLevel = :custLevel ");
72         //2.给参数占位符赋值
73         query.setString("custLevel", "VIP客户");
74         query.setString("custName", "%大%");
75         //3.执行list方法获取结果集
76         List list = query.list();
77         tx.commit();
78 
79         
80         for(Object o : list){
81             System.out.println(o);
82         }
83     }
84 }

 

  Criteria  <逐步掌握>

 1 /**
 2  * hibernate中的查询对象
 3  *     Criteria对象:
 4  *         作用:使用QBC查询。 query by criteria
 5  *             它是一种更加面向对象的查询方式。
 6  *         明确:
 7  *             能用HQL查询的,QBC都能查。反之亦然。
 8  *         hibernate官方推荐的是hql查询
 9  *  如何获取对象
10  *      使用的是session对象的createCriteria(Class clazz);
11  *      参数的含义:要查询的实体类字节码对象13  *
14  */
15 public class HibernateDemo5 {
16 
17     /**
18      * 查询所有
19      */
20     @Test
21     public void test1(){
22         Session s = HibernateUtil.getCurrentSession();
23         Transaction tx = s.beginTransaction();
24         //1.获取Criteria对象
25         Criteria criteria = s.createCriteria(Customer.class);//就相当于HQL语句from Customer
26         //2.调用list获取结果集
27         List list = criteria.list();
28         tx.commit();
29         
30         for(Object obj : list){
31             System.out.println(obj);
32         }
33     }
34     
35     
36     /**
37      * 查询客户:
38      *     带有条件:客户级别是VIP客户
39      *             客户名称包含大字
40      */
41     @Test
42     public void test2(){
43         Session s = HibernateUtil.getCurrentSession();
44         Transaction tx = s.beginTransaction();
45         //1.获取Criteria对象
46         Criteria criteria = s.createCriteria(Customer.class);//就相当于HQL语句from Customer
47         //2.设置查询条件
48         criteria.add(Restrictions.eq("custLevel","VIP客户"));//谁=什么值   谁指的就是属性
49         criteria.add(Restrictions.like("custName", "%大%"));
50         //3.调用list获取结果集
51         List list = criteria.list();
52         tx.commit();
53         
54         for(Object obj : list){
55             System.out.println(obj);
56         }
57     }
58     
59     
60 }

 

  SQLQuery  <了解>

 1 /**
 2  * hibernate中的查询对象
 3  *     SQLQuery
 4  *         作用:使用原始SQL语句查询
 5  *     如何获取
 6  *         session.createSQLQuery(String sql); 
8
* 9 */ 10 public class HibernateDemo6 { 11 12 /** 13 * 查询所有 14 */ 15 @Test 16 public void test1(){ 17 Session s = HibernateUtil.getCurrentSession(); 18 Transaction tx = s.beginTransaction(); 19 //1.获取sqlquery对象 20 SQLQuery sqlquery = s.createSQLQuery(" select * from cst_customer "); 21 //2.给sqlquery添加要转换的实体类 22 sqlquery.addEntity(Customer.class); 23 //3.获取结果集 24 List list = sqlquery.list(); 25 tx.commit(); 26 for(Object o : list ){ 27 System.out.println(o); 28 } 29 } 30 }

 

posted @ 2017-05-31 23:48  细节造就完美  阅读(27)  评论(0)    收藏  举报