第二天,我们先来了解一下框架里的一个重要概念:实体类

  实体类:把数据表或其它持久化数据的格式映射成的类,就是实体类。

  实体类的编写规则:由于对应的是javabean,因而也遵循javabean的一些规范
    定义私有的成员变量
    通过set/get方法对成员变量进行读写操作
    实体类独有的特性:有属性值作为唯一值(一般为id)
    建议不要使用基本数据类型而是使用它们的包装类,理由是例如要区分0分与没有参加考试,int类型难以区分,
    而包装类Integer可以使用0与Null进行区分

    讲到实体类,我们再对第一天中的配置文件主键生成策略稍作细入  

      实体类的主键生成策略(请使用程序生成主键而非人为输入!):
      主要我们知道两个:
      <id name="uid" column="uid">
      <!-- 设置id增长策略 -->
       <generator class="native"></generator>
      </id>
      一个是我们第一天使用的native
      native :自动选择identity等,自动根据底层
      uuid :32为十六进制字符串,自动利用UUID的算法生成32位的唯一

       increment:(存在线程安全问题),可以为 int long ,甚至是 string
      使用UUID生成策略时,id类型必须为String类型,配置生成策略:
      <generator class="uuid"></generator>

      这里推荐一篇不错的主键生成策略讲解:http://www.cnblogs.com/hoobey/p/5508992.html

      更新简明版:http://blog.csdn.net/caiwenfeng_for_23/article/details/43644573/

      这里提取出一句小结:

      Hibernate中唯一一种最简单通用的主键生成器就是uuid。虽然是个32位难读的长字符串,但是它没有跨数据库的问题,

      将来切换数据库极其简单方便,推荐使用!

      接下来,我们来实际操作一下CRUD操作:

对实体类的操作:(CRUD操作)
  添加操作:day01已做

    数据库添加操作会返回id值Serilizable id
  查询操作:根据id进行查询
   调用get()方法查询(结果一条记录(即一个对象))

@Test
public void testGet(){
//都是先查后该
//得到工厂
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
//得到session
Session session = sessionFactory.openSession();
//开启事务
Transaction tx = session.beginTransaction(); //进行操作,第一个参数为.class对象,第二个为主键值
User user = session.get(User.class, 1);
System.out.println(user); //提交事务
tx.commit();
//关闭资源
session.close();
sessionFactory.close();
}

  修改记录:修改都是先查再改
  调用update()方法进行修改

@Test
public void testUpdate(){
//得到工厂
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
//得到session
Session session = sessionFactory.openSession();
//开启事务
Transaction tx = session.beginTransaction(); //进行操作
User user = session.get(User.class, 2);
user.setUsername("LuLu");
session.update(user);
System.out.println(user); //提交事务
tx.commit();
//关闭资源
session.close();
sessionFactory.close();
}

  删除记录:调用delete()方法
  可以先根据id查询到该条记录,再传入对象进行删除

@Test
public void testDelete(){
    //都是先查后该
     //得到工厂
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
//得到session
Session session = sessionFactory.openSession();
//开启事务
Transaction tx = session.beginTransaction(); //进行操作
User user = session.get(User.class, 2);
session.delete(user); //提交事务
tx.commit();
//关闭资源
session.close();
sessionFactory.close();
}

  做完了基本的CRUD操作,我们试着再引入实体类状态的概念:

实体类的状态(作了解)

1.瞬时态(Transient):对象里面没有id值,和session也没有关联,例如添加之前的状态,故瞬时态一般
用来保存,即这个对象只是一个保存临时数据的内存区域,与数据库没有任何关系

  例如:

   User u=new User();

u.setName("z");

2.持久态(Persistent:对象里面有id值,和session有关联,例如通过id查询出来的值(session查出来的又有id)

          持久态对象的实例在数据库中有对应的记录,并拥有一个持久化标识(ID)

  例如:

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

3.脱管态(游离态)(Detached,也就是离线的意思了):对象有id值,但是和sessio没有关联(用的少),

          实体对象从持久态变成游离态,对象虽然拥有持久和与数据库对应记录一致的标识值,

          但是因为对象已经从会话中清除掉,对象不在持久化管理之内,所以处于游离态(也叫脱管态)。

          游离态的对象与临时状态对象是十分相似的,只是它还含有持久化标识。

  例如:

  User u=new User();

  u.setId(1);

这里就引出一个方法:

saveOrUpdate()方法:根据不同的状态来执行不同的操作。
    1状态时执行 插入操作 insert
    2状态时执行 修改操作 update
    3状态时执行 修改操作 update

  到这里,有必要引入稍微标准一点的事务写法了,之后后面的例子都将使用尽量标准的写法

/**
* 事务的标准写法(无本地线程的绑定)
* 单元测试时可以使用,不然session一直不关闭的状态
*/
public void Demo01(){
//请将声明放在try之外
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
//得到工厂
sessionFactory = HibernateUtils.getSessionFactory();
//得到session
session = sessionFactory.openSession();
//开启事务
tx = session.beginTransaction(); //开始CRUD等操作
User user = new User();
user.setUsername("小李");
user.setPassword("10000");
user.setAddress("上海");
//调用session方法,也可以使用saveOrUpdate()
session.save(user); //提交事务
tx.commit(); }catch(Exception e){
e.printStackTrace();
//事务回滚
tx.rollback();
}finally{
//关闭资源
session.close();//使用openSession()需要手动关闭
sessionFactory.close();
}
}

  处理多线程的场景时,我们可以使用与本地线程绑定的 session

    /**
* 使用与本地线程绑定的session的区别
*/
public void Demo02(){
//请将声明放在try之外
//SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
//得到工厂
//sessionFactory = HibernateUtils.getSessionFactory();
//得到session
session = HibernateUtils.getSessionObject();
//开启事务
tx = session.beginTransaction(); //开始CRUD等操作
User user = new User();
user.setUsername("小李");
user.setPassword("10000");
user.setAddress("上海");
//调用session方法,也可以使用saveOrUpdate()
session.save(user); //提交事务
tx.commit(); }catch(Exception e){
e.printStackTrace();
//事务回滚
tx.rollback();
}finally{
//关闭资源
//与本地线程绑定的session不需要手动关闭
//session.close();
//sessionFactory.close();
}
}

于是,我们引出与本地线程绑定的HibernateUtils的更新

package cn.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration; public class HibernateUtils { private static final Configuration cfg ;
private static final SessionFactory sessionFactory;
//静态代码块实现
static {
cfg = new Configuration();
cfg.configure();
sessionFactory = cfg.buildSessionFactory();
}
//提供静态方法返回sessionFactory
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
//返回本地线程绑定的session
public static Session getSessionObject(){
return sessionFactory.getCurrentSession();
}
}

接下来我们来引入持久化框架的一个重要优化机制:缓存机制

我们先来看看网络上对缓存的概述:

  Hibernate是一个持久层框架,经常访问物理数据库。

  为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。

  缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据

  也就是说,把数据存到内存中,叫缓存。

Hibernate中存在两种缓存:

  一级缓存:
    三个特点:
      默认是打开的
      使用的范围是session的范围,也就是session的开启到关闭之间 =====故也被称为 session 的缓存
      存储的数据必须是持久态的数据
  二级缓存:已经不使用了,而是使用替代技术:redis
      默认不是打开的
      使用范围是整个的项目的范围(sessionFactory的范围,也就是类似servletContext) =====故也被称为 sesssionFactory 的缓存

接下来先来验证一级缓存的存在再来概述一级缓存的执行过程:

    验证出一级缓存的存在:
      1.第一次查id=1,返回一个对象
      2.再次查id=1,就不去查数据库,而是查以及缓存

  

/**
* 验证一级缓存的存在
*
*/
@Test
public void testCache(){ SessionFactory sessionFactory = HibernateUtils.getSessionFactory(); //使用工厂创建session
Session session = sessionFactory.openSession(); //开启事务
Transaction tx = session.beginTransaction(); //完成CRUD操作,验证一级缓存的,看看查询了几次
User user1 = session.get(User.class, 1);
System.out.println(user1);
User user2 = session.get(User.class, 1);
System.out.println(user2); //提交事务
tx.commit(); //关闭资源
session.close();
sessionFactory.close();
}

可以看到,两次相同的查询,只发送了一次SQL语句去查询.

  接下来大致执行过程

  一级缓存的大致执行过程:
    接到查询代码,先去查一级缓存,发现里面没有数据,
    再去查数据库,返回一个持久态的对象user1,再把持久态的user1放到一级缓存中
    第二次发现一级缓存里面有,就直接拿了。

  一级缓存里面存的不是整个对象,而是存对象里面的一些值(比如 id = 1,username = "张三")
      第二次查到的user2其实和user1不是同一个对象,而是把一级缓存的一些值拿过来组成user2

  一级缓存特性:持久态会更新数据库
    例子:
    User user = session.get(User.class, 2);
    user.setUsername("LuLu");
    //session.update(user);
    其中user为持久态的数据,所以update()方法可以省略
    持久态的数据会自动更新

  特点:创建session时,会创建一级缓存,同时还会出现一个
  快照区(也就是副本)

  执行user.setUsername("LuLu");时,修改一级缓存中的值
  但不会修改快照区的值
  提交事务的时候,Hibernate会比较一级缓存的内容和快照区的内容相同
  不相同则更新一级缓存内容到数据库,相同则不用更新到数据库

在正式引入查询之前,先引入几个查询的API,进行简单的查询,具体的操作会在第四天作详细的介绍

  Hibernate API
    查询的对象:
      Query 对象
        不需要写SQL语句,但需要些HQL(Hibernate查询语言)
        HQL与SQL很相似;
        不同点:
          SQL操作的是数据库的表和字段
          HQL操作的是实体类和属性

        查询所有:
          from 实体类类名

/**
* 使用Query对象
*/
@Test
public void Demo01(){
//请将声明放在try之外
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
//得到工厂
sessionFactory = HibernateUtils.getSessionFactory();
//得到session
session = sessionFactory.openSession();
//开启事务
tx = session.beginTransaction(); //得到Query对象
Query query = session.createQuery("from User");
//得到结果集
List<User> list = query.list();
//遍历结果集
for (User user : list) {
System.out.println(user);
}
//提交事务
tx.commit(); }catch(Exception e){
e.printStackTrace();
//事务回滚
tx.rollback();
}finally{
//关闭资源
session.close();//使用openSession()需要手动关闭
sessionFactory.close();
}
}

     Criteria 对象
      步骤差不多,详见代码

  

/**
* 使用Criteria对象
*/
@Test
public void Demo02(){
//请将声明放在try之外
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
//得到工厂
sessionFactory = HibernateUtils.getSessionFactory();
//得到session
session = sessionFactory.openSession();
//开启事务
tx = session.beginTransaction(); //得到Criteria对象
Criteria criteria = session.createCriteria(User.class);
//调用方法,得到list结果集
List<User> list = criteria.list();
for (User user : list) {
System.out.println(user);
} //提交事务
tx.commit(); }catch(Exception e){
e.printStackTrace();
//事务回滚
tx.rollback();
}finally{
//关闭资源
session.close();//使用openSession()需要手动关闭
sessionFactory.close();
}
}

     SQLQuery 对象(使用较少)
        可以调用底层SQL(用的不多)
        步骤都是创建对象
        调用方法

/**
* 使用SQLQuery对象
*/
@Test
public void Demo03(){
//请将声明放在try之外
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
//得到工厂
sessionFactory = HibernateUtils.getSessionFactory();
//得到session
session = sessionFactory.openSession();
//开启事务
tx = session.beginTransaction(); //得到SQLQuery对象
SQLQuery sqlQuery = session.createSQLQuery("select * from t_user2");
//List<Object[]> list = sqlQuery.list();
//list中每部分是个数组
/*for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}*/
//设置数据放到实体类
sqlQuery.addEntity(User.class);
//这样list中每部分都是User
List<User> list = sqlQuery.list();
//提交事务
tx.commit(); }catch(Exception e){
e.printStackTrace();
//事务回滚
tx.rollback();
}finally{
//关闭资源
session.close();//使用openSession()需要手动关闭
sessionFactory.close();
}
}

以上都是查询所有的简单Demo,基本的过程都差不多,得到相关的对象后进行相应的操作

可能是版本迭代问题,出现较多过时的地方,待解决!

  detachedcriteria离线的criteria

  其中离线的criteria待更新!

Hibernate第二天——实体类 与缓存机制的更多相关文章

  1. hibernate 非xml实体类配置方法!

    hibernate 非xml实体类配置方法! 这个是hibernate.cfg.xml配置文件 <?xml version='1.0' encoding='UTF-8'?> <!DO ...

  2. 在Intellij IDEA下通过Hibernate逆向生成实体类

    前言:在IDEA中,通过相关插件,可以利用Hibernate逆向生成数据表对应的实体类.具体操作及注意事项见本篇随笔. 1.创建一个基于maven的hibernate工程.并在工程中添夹hiberna ...

  3. hibernate 反向生实体类 and 为什么老是多一个id

    hibernate 反向生实体类 and 为什么老是多一个id 2017年04月01日 20:32:51 阅读数:548

  4. Integer类的缓存机制

    一.Integer类的缓存机制 我们查看Integer的源码,就会发现里面有个静态内部类. public static Integer valueOf(int i) { assert IntegerC ...

  5. Hibernate正向工程(实体类-->数据库)

    1,新建实体类News.java package com.hanqi.dao; import java.util.Date; public class News { private Integer i ...

  6. Hibernate自动生成实体类注解(转)

    常用的hibernate annotation标签如下: @Entity --注释声明该类为持久类.将一个Javabean类声明为一 个实体的数据库表映射类,最好实现序列化.此时,默认情况下,所有的类 ...

  7. Snail—Hibernate反向生成实体类及配置文件

    今天学习了Hibernate的反向生成类文件 第一步.打开myeclipse中的database视图,找到对应的表,选中后右键单击. watermark/2/text/aHR0cDovL2Jsb2cu ...

  8. idea hibernate jpa 生成实体类

    0,添加mysql数据库连接 1,生成个hibernate.cfg.xml 2,打开Persisitence 3,Import Databases Schema 4,选择表生成实体类

  9. Hibernate 配置文件与实体类

    今天在配置Hibernate的时候碰到了这样的错误: MappingException: Unknown entity 仔细想了一下,应该是因为我在开始时使用了 Configuration confi ...

随机推荐

  1. 【Java】操作mysql数据库

    package bd; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; im ...

  2. Ionic step by step (1)

    刚接触 ionic,一步一步学习,有错误的,望大家指出. 公式 Ionic = Cordova + Angular2 + ionic CSS Cordova: 提供了使用 JavaScript 调用 ...

  3. scrapy实战--爬取最新美剧

    现在写一个利用scrapy爬虫框架爬取最新美剧的项目. 准备工作: 目标地址:http://www.meijutt.com/new100.html 爬取项目:美剧名称.状态.电视台.更新时间 1.创建 ...

  4. Oracle EBS 配置文件取值

    SELECT op.profile_option_id, tl.profile_option_name, tl.user_profile_option_name, lv.level_id, lv.文件 ...

  5. 关于Tomcat端口出现的问题

    =Several ports (8005, 8080, 8009) required by Tomcat v7.0 Server at localhost are already in use. Th ...

  6. yii 验证码功能的实现

    首先知晓我们在使用验证码的时候通常是和我们的表单小部件配合使用首先我们创建model层 新建一个php文件 名字叫做Verifycode.php 要在我们的model层 创建我们的验证码的验证规则,我 ...

  7. 低级终端IO

    低级终端IO 程序会需要对输入输出进行比简单的文件操作更为精确的控制.POSX提供了一套接口允许程序控制终端驱动程序的行为,这套接口称为通用终端接口(GIT). 需要改变终端设置的例子 标准输入输出, ...

  8. dev richEditControl控件 设置文字 字体 大小

    Document doc = NoticeContentRichEditControl.Document; doc.BeginUpdate(); doc.Text = "需要设置格式的文字& ...

  9. 关于strip(切割)和 split(分开) 的区别

    plit(), 以括号里的东西为标准,把字符串分开成一个列表 strip(), "删除",括号里出现的东西,从两头开始往中间删除,直到遇到阻碍.中间就算有,也不会受影响 s10 = ...

  10. npm install --save 和 --save-dev的区别

    --save 会把依赖包名称添加到 package.json 文件 "dependencies" 键下--save-dev 则添加到 package.json 文件 "d ...