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

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

  实体类的编写规则:由于对应的是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. C#代码实现在控制台输入密码显示星号

    在控制台输入的内容C#默认按照字符串进行处理,如果直接让用户一次输入完毕就很难实现 显示星号的功能.但是如果让用户一次只能输入一个字符就,在将用户输入的字符替换为星号就可以实现了! 首先,C#中能让用 ...

  2. A B C D类网络地址

    A类网络地址(红色为网络地址,黑色为主机地址): 下限:0000 0001.0000 0000.0000 0000.0000 0000(1.0.0.0) 上限:0111 1110.1111 1111. ...

  3. 导出AD用户所属组,查询AD用户(aduser)

    $ous="admin","bladmin","af","dd"for($i=0;$i -lt 2;$i++) { $o ...

  4. Java通过Shell执行Sqoop命令没日志的问题

    修改执行部分的代码,改成用InputStream.read(byte[])的方法从流中读取数据 package com.example.demo.utils; import java.io.*; pu ...

  5. 记Git报错-Everything up-to-date

    文:铁乐与猫 今天git push 到github远程仓库的时候,出现报错"Everything up-to-date",严格来说也不算报错,它只是在告诉你,提交区所有的东西都是最 ...

  6. css3实现border渐变色

    案例1 .box{ width: 100px; height: 100px; border:10px solid #ddd; border-image: -webkit-linear-gradient ...

  7. 1. 安装Oracle,配置环境 2. 实现查询From子句 3. 实现查询where子句 4. 实现查询order by子句

    一.环境安装1. 登录:以管理员身份登录 sqlplus 登录名/密码 管理员身份登录:sqlplus system/1234562. 登录后,导入案例.下载scott.sql文件,执行下面一行的命令 ...

  8. codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(启发式合并)

    codeforces 741D Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...

  9. Linux新建用户没有设置密码

    只要你能登陆root账户就行 登陆root账户 输入  echo "密码“ | passwd --stdin 用户名

  10. MySQL知识总结(二)基本语句总结

    1. 数据库 查看数据库 show databases; 使用数据库 use [数据库名] 如:use mysql 创建数据库 CREATE DATABASE bruce DEFAULT CHARAC ...