一、  hibernate的实体类有一定的规则,类似于mybatis的逆向工程导出的实体类。具体的规则以及原因如下:

1.持久化类需要提供无参的构造方法。

  因为hibernate底层采用反射机制创建对象,采用class.newInstance()创建对象,此方法默认调用无参构造方法创建对象。如果我们只写一个带参数的构造函数在查询的时候会报错误 org.hibernate.InstantiationException

例如:我们重写一个类的无参构造方法:

public class User {
private Long user_id;
private String user_name;
private Character user_state;
private Set<Role> roles = new HashSet<>(); public User() {
System.out.println("user创建对象");
}
...

测试:

    public static void main(String[] args) {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction(); User user = session.get(User.class, 1l);
System.out.println(user);
}

结果:

user创建对象
Hibernate:
select
user0_.user_id as user_id1_3_0_,
user0_.user_name as user_nam2_3_0_,
user0_.user_state as user_sta3_3_0_
from
sys_user user0_
where
user0_.user_id=?
user创建对象
cn.qlq.domain.User@2ddc7eba

2.成员变量私有,提供共有get/set方法访问.需提供属性

  hibernate底层将查询到的数据采用set方法进行设置。

  此处声明一个常识,一个类下声明的变量是成员变量不能说是属性,而属性说的是get/setter建造器,一个类有几个属性看这个类有几个getter/setter建造器。

3.持久化类中的属性,应尽量使用包装类型

  例如int采用Integer,long采用Long。原因如下:

  (1)有可能我们对一些值不需要设值,比如null,但是我们如果用int这样的基本数据类型将不能存储null,比如我们想用成绩为null表示缺考,成绩为0表示考试了但是获得 的成绩为0.

  (2)数据库中的null如果映射到基本数据类型会报错误,采用包装类型可以避免这些问题。

4.持久化类需要提供oid(Object Identifier,对象标识符).与数据库中的主键列对应

  注意如果没有主键的表hibernate是不能进行操作的。

  数据库中的表采用ID进行区分,每条唯一的是一条记录;Java中通过内存地址区分两个对象是否是相同对象,而hibernate通过 OID进行区分,hibernate不允许在内存中出现两个相同OID的对象。

5.不要用final修饰class

 hibernate使用cglib代理生成代理对象.代理对象是继承被代理对象.如果被final修饰.将无法生成代理。JDK代理采用实现接口的方式,而cgib采用继承的方式实现代理。

二、hibernate主键类型

1.  自然主键(少见)

   表的业务列中,有某业务列符合,必须有,并且不重复的特征时,该列可以作为主键使用.比如用户表有身份证号字段,身份证号不能为空而且能唯一区分一条记录,则可以将身份证号作为主键。

2.代理主键(常见)

  表的业务列中,没有某业务列符合,必须有,并且不重复的特征时,创建一个没有业务意义的列作为主键。(这也是设计数据库的一条常用规则,每个表都有一个与业务无关的主键)

三、hibernate主键生成策略

  由hibernate维护的数据库主键生成策略开发时不用,了解即可。increment(自增)和hilo(高低位算法)。开发一般用native或者UUID,对于int型(对应java的Integer)或者bigint(对应Java的Long型)型的数据可以用

native就会ui自动支持mysql或者oracle,如果开发采用的主键是varchar(对应Java的String)型的可以采用uuid生成32位唯一的16进制字符串。

  自然主键有6中,代理主键就一种(assigned)-------开发人员自己确保主键唯一。  

1.  数据库自己托管   identity

  identity : 主键自增.由数据库来维护主键值.录入时不需要指定主键.

测试:

        <id name="cust_id"  >
<!-- generator:主键生成策略 -->
<!--identity : 主键自增.由数据库来维护主键值.录入时不需要指定主键. -->
<generator class="identity"></generator>
</id>

执行保存的时候查看SQL语句:(未插入主键)

Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?)

2.自增主键  increment  (hibernate维护,并发访问会有问题)----开发不用

  increment:自然主键生成策略. hibernate不会管理主键值.由开发人员自己录入.每次插入的时候先查询当前最大值,下次加一。

Hibernate:
select
max(cust_id)
from
cst_customer
Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile, cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?)

3.sequence   用于oracle数据库的序列主键生成策略

4.hilo:高低位算法---一种算法名称  (hibernate维护,开发时不用)

5.native  hibernate根据方言(数据库类型)三(hilo+sequence+identify)选一策略  -----------一般用这个

  如果是mysql就采用identify,如果是oracle采用sequence类型。

6.  uuid  生成一个32位不重复的UUID,注意主键必须是String类型(也常用)

        <id name="cust_id"  >
<!-- generator:主键生成策略 -->
<generator class="uuid"></generator>
</id>

测试如下:

User.java

package cn.qlq.domain;

/**
*
* @author Administrator
*
*/
public class User {
private String userId;
private String userName;
private Integer age; public String getUserId() {
return userId;
} public void setUserId(String userId) {
this.userId = userId;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
}
}

User.hbm.xml:

<?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">
<!-- 配置表与实体对象的关系 -->
<!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="cn.qlq.domain" >
<!--
class元素: 配置实体与表的对应关系的
name: 完整类名
table:数据库表名
-->
<class name="User" table="t_user">
<!-- id元素:配置主键映射的属性
name: 填写主键对应属性名
column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<id name="userId" column="userid" >
<!-- generator:主键生成策略 -->
<generator class="uuid"></generator>
</id>
<!-- property元素:除id之外的普通属性映射
name: 填写属性名
column(可选): 填写列名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<property name="userName" column="username"></property>
<property name="age" column="age"></property>
</class>
</hibernate-mapping>

测试类:

    @Test
//session的新增
public void fun2(){
//1 创建,调用空参构造
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
//3 获得session
Session session = sf.openSession();
//4 session获得操作事务的Transaction对象
//获得操作事务的tx对象
//Transaction tx = session.getTransaction();
//开启事务并获得操作事务的tx对象(建议使用)
Transaction tx2 = session.beginTransaction();
//----------------------------------------------
User user = new User();
user.setUserName("张三"); session.save(user);
//----------------------------------------------
tx2.commit();//提交事务
session.close();//释放资源
sf.close();//释放资源
}

数据库结果:

查看表结构发现采用的是数据库默认的最大长度,太浪费内存,我们可以在映射的时候指定长度:

mysql> desc t_user;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| userid | varchar(255) | NO | PRI | NULL | |
| username | varchar(255) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

解决办法:修改xml映射文件同时将数据库表名和列名都设位缺省值,也就是与Java种类名属性名相同。数据库表名列名使用缺省值,指定varchar长度,设置不为空

<?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">
<!-- 配置表与实体对象的关系 -->
<!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="cn.qlq.domain" >
<!--
class元素: 配置实体与表的对应关系的
name: 完整类名
table:数据库表名
-->
<class name="User">
<!-- id元素:配置主键映射的属性
name: 填写主键对应属性名
column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<id name="userId" length="32">
<!-- generator:主键生成策略 -->
<generator class="uuid"></generator>
</id>
<!-- property元素:除id之外的普通属性映射
name: 填写属性名
column(可选): 填写列名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<property name="userName" length="10" not-null="true"></property>
<property name="age"></property>
</class>
</hibernate-mapping>

结果:

mysql> desc user;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| userId | varchar(32) | NO | PRI | NULL | |
| userName | varchar(10) | NO | | NULL | |
| age | int(11) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

7. assigned:     自然主键生成策略. hibernate不会管理主键值.由开发人员自己录入.

     也就是主键必须自己设置唯一值,由开发人员维护。

四、 Hibernate的对象状态

1.三种状态的解释

对象分为三种状态:瞬时状态、持久化状态、游离状态.其实我们调用session.save或者session.update或者session.saveOrUpdate只是为了将对象的状态改变为持久态。

(1)瞬时状态  没有在session缓存中

  也称为临时态或自由态,只是new 出来的在开辟内存空间的对象,不存在OID(对象标识)、也没有与hibernate的session建立关联,在JVM中没有与之对应的数据库记录,失去引用后将会被JVM垃圾回收。瞬时状态的对象在内存中是孤立存在的,在数据库没有与之关联的记录。只是作为信息的载体。

(2)持久化状态    有id,在session缓存(hibernate的一级缓存)中.(处于持久态的对象的变化会影响到数据库)

  持久态的对象存在OID,也存在session中(session没有close),在数据库中有对应的记录。每条记录只对应一条唯一的持久态对象,需要注意的是持久态的对象是在事务还未提交前变成持久态的,而且处于持久态的对象的变化hinernate会检测到且同步到数据库中。

(3)游离|托管状态   有id,没有在session缓存中。有ID指的是数据库种有与之对应的ID,如果简单的new 了一个对象且设置了一个ID,但是数据库种没有与之对应的ID还是处于瞬时状态。

  游离状态的对象存在OID,只是没有与之关联的session或者说与之关联的Session已经关闭,处于游离态的对象的变化hibernate监测不到。

2.区分对象的三种状态

    @Test
//三种状态特点
//save方法: 其实不能理解成保存.理解成将瞬时状态转换成持久状态的方法
//主键自增 : 执行save方法时,为了将对象转换为持久化状态.必须生成id值.所以需要执行insert语句生成.
//increment: 执行save方法,为了生成id.会执行查询id最大值的sql语句.
public void fun2(){
//1 获得session
Session session = HibernateUtil.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
Customer c = new Customer(); // 没有id, 没有与session关联 => 瞬时状态 c.setCust_name("联想"); // 瞬时状态 session.save(c); // 持久化状态, 有id,有关联 //4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联 }

3.三种状态的状态转换关系

下面是对三种状态的转换图(两个图均可以理解):

  其实我们调用session.save或者session.update或者session.saveOrUpdate只是为了将对象的状态改变为持久态。

4.持久态对象的变化能够自动更新到数据库

    @Test
//三种状态特点
// 持久化状态特点: 持久化状态对象的任何变化都会自动同步到数据库中.
public void fun3(){
//1 获得session
Session session = HibernateUtil.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作 Customer c = session.get(Customer.class, 1l);//持久化状态对象 c.setCust_name("XXXXXXXXXX"); //4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联 }

测试日志:

Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_linkman as cust_lin6_0_0_,
customer0_.cust_phone as cust_pho7_0_0_,
customer0_.cust_mobile as cust_mob8_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
Hibernate:
update
cst_customer
set
cust_name=?,
cust_source=?,
cust_industry=?,
cust_level=?,
cust_linkman=?,
cust_phone=?,
cust_mobile=?
where
cust_id=?

  结论:我们在上面的代码中并没有手动调用update方法,Hibernate就可以将数据自动更新了。我们调用get方法查询到的对象处于持久态,我们调用set方法改变属性的实施hibernate会自动检测其变化并更新数据

库,持久化状态的对象有这一特性,其实这一特性依赖于hibernate的一级缓存。

    

总结:

一.hibernate中的实体创建规则
  1>对象必须有oid.
  2>对象中的属性,尽量使用包装类型
  3>不使用final修饰类
  4>提供get/set方法....
二.hibernate主键生成策略(7种)
  increment: 查询最大值.再加1
  identity: 主键自增.
  sequence:Oracle使用的
  hilo: hibernate自己实现自增算法
  native: 根据所选数据库三选一
  uuid: 随机字符串
  assigned: 自然主键.
三.对象的三种状态
  瞬时状态
    没有id,没有在session缓存中.
  持久化状态
    有id,再session缓存中。
  托管|游离状态
    有id,不在session缓存中.

持久化: 持久化状态的对象,会在事务提交时,自动同步到数据库中.
我们使用hibernate的原则.就是将对象转换为持久化状态.

Hibernate的实体规则、主键生成策略、对象状态的更多相关文章

  1. Hibernate之:各种主键生成策略与配置详解

    1.assigned 主键由外部程序负责生成,在 save() 之前必须指定一个.Hibernate不负责维护主键生成.与Hibernate和底层数据库都无关,可以跨数据库.在存储对象前,必须要使用主 ...

  2. Hibernate框架笔记02_主键生成策略_一级缓存_事务管理

    目录 0. 结构图 1. 持久化类的编写规则 1.1 持久化和持久化类 1.2 持久化类的编写规则 2. 主键生成策略 2.1 主键的分类 2.2 主键生成策略 3. 持久化类的三种状态[了解] 3. ...

  3. Hibernate(4)——主键生成策略、CRUD 基础API区别的总结 和 注解的使用

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: hibernate的主键生成策略 UUID 配置的补充:hbm2ddl.auto属性用法 注解还是配置文件 h ...

  4. hibernate(二)主键生成策略

    hibernate主键生成策略主要指的是在实体类orm的配置 <id name=""> <generator class="native"&g ...

  5. java框架之Hibernate(2)-持久化类&主键生成策略&缓存&事务&查询

    持久化类 概述 持久化:将内存中的对象持久化到数据库中的过程就是持久化.Hibernate 就是用来进行持久化的框架. 持久化类:一个 Java 对象与数据库的表建立了映射关系,那么这个类在 Hibe ...

  6. (转) Hibernate持久化类与主键生成策略

    http://blog.csdn.net/yerenyuan_pku/article/details/65462930 Hibernate持久化类 什么是持久化类呢?在Hibernate中持久化类的英 ...

  7. Hibernate的几种主键生成策略

    主键类型: 业务主键(natural key):业务主键的值是来源于一个业务数据. 代理主键(surrogate key):代理主键需要采用一种方式来生成某个唯一值. 代理主键的生成策略: 1.hib ...

  8. Hibernate遇到oracle之主键生成策略

    一直用Hibernate+mysql,感觉Hibernate很好用,也出过什么大问题:这周,公司的产品要部署到Orecle,虽然产品号称支持Oracle但是我自己知道,这个产品压根儿就没在Oracle ...

  9. (二)JPA实体类主键生成策略

    在JPA中,配置实体类的主键的生成策略使用 @GeneratedValue @Id @Column(name = "id") @GeneratedValue(strategy = ...

  10. hibernate框架学习之主键生成策略generator

    1)手工控制 assigned(不限制类型) 2)数据库自动生成 uuid(字符串类型) increment(整型数值类型) identity (整型数值类型) sequence (整型数值类型) n ...

随机推荐

  1. Android中应用contentprovider来创建数据库的一些步骤

    http://blog.csdn.net/xiaodongvtion/article/details/7865669 1:首先创建一个xxprovider的class,它是extendscontent ...

  2. Beta阶段冲刺四

    Beta阶段冲刺四 Task1:团队TSP 团队任务 预估时间 实际时间 完成日期 新增其他学院的爬虫 180 130 11.30 新增其他学院的数据库字段修改 180 160 12.1 新增其他学院 ...

  3. [阮一峰]Linux 守护进程的启动方法

    "守护进程"(daemon)就是一直在后台运行的进程(daemon). 本文介绍如何将一个 Web 应用,启动为守护进程. 一.问题的由来 Web应用写好后,下一件事就是启动,让它 ...

  4. OneZero第二周第三次站立会议(2016.3.30)

    会议时间:2016年3月30日  13:00~13:20 会议成员:冉华,张敏,王巍,夏一鸣. 会议目的:汇报前一天工作,全体成员评论,确定会后修改内容或分配下一步任务. 会议内容: 1.前端,完成功 ...

  5. Java进阶之路

    Java进阶之路——从初级程序员到架构师,从小工到专家. 怎样学习才能从一名Java初级程序员成长为一名合格的架构师,或者说一名合格的架构师应该有怎样的技术知识体系,这是不仅一个刚刚踏入职场的初级程序 ...

  6. Java 8新特性之接口改善(八恶人-1)

    Daisy Donergue 多莫歌·黛西 “By woman, you mean her?” 她也能叫女人? Java 8在13年9月发布,写这篇博文的时间已经是17年12月份了.来的有点晚,但是有 ...

  7. poj 1511 Invitation Cards(最短路中等题)

    In the age of television, not many people attend theater performances. Antique Comedians of Malidine ...

  8. clazz.isArray()

    boolean isArray() 判断类型是不是数组 Class clazz = int[].class; System.out.println(clazz.isArray());

  9. c# winform 为按钮动态背景图片

    参考自:http://www.cnblogs.com/sufei/archive/2012/11/15/2771299.html 第一种,使用Properties.Resources类,这种方法需要你 ...

  10. MySQL -- 主从复制的可靠性与可用性

    主库A执行完成一个事务, 写入binlog ,记为 T1 然后传给从库B,从库B 接收该binlog ,记为 T2 从库B执行完成这个事务,记为 T3 同步延时: T3-T1 同一个事务,在 从库执行 ...