Hibernate实体解析、主键类型以及对象状态
hibernate中的实体规则
实体创建的注意事项
- 持久化类需要提供无参构造方法
- 成员变量私有,提供共有的get / set方法,余姚提供属性(属性跟变量的区别,当变量有了get / set方法后,它就变成了属性)
- 持久化的属性,应尽量使用包装类型,比如 private Integer id; private Charactor c;
- 持久化类需要提供oid与数据库中的主键列对应
- 不要用final修饰持久化类
- hibernate使用cglib代理生成对象,代理对象是继承被代理对象,如果使用final修饰被代理对象,那么代理对象将无法继承被代理对象,则代理对象无法生成
hibernate主键类型
自然主键(少见)
某业务表中,有某列符合必须有,并且不重复的特征时,该列可以叫做自然主键(比如人的身份证必须有而且不重复)
代理主键(常见)
在表的业务中,没有某列符合必须有,不重复的特征,这时需要创建一个没有业务意义的列充当代理主键
主键的生成策略
什么是主键生成策略:hibernate记录每条记录时,主键的生成规则
类型:
类型 | 描述 |
<generator class="identity"></generator> | 主键自增,有数据库来维护主键值,在录入时不需要指定主键 |
<generator class="sequence"></generator> | 序列,oracle独有的主键生成策略 |
<generator class="increment"></generator> | 主键自增,每插入时会先查询表中的最大id值,然后+1作为主键(有线程安全问题,不常用,了解即可) |
<generator class="hilo"></generator> | 主键自增,由hibernate维护,使用高低位算法,开发时不使用 |
<generator class="native"></generator> | 自动三选一策略:hilo + sequence + identity,会根据所使用的数据库自动选择合适的主键生成策略 |
<generator class="uuid"></generator> | 产生随机不重复字符串作为主键,主键的类型必须是String |
<generator class="assigned"></generator> | 自然主键生成策略,hibernate不会管理主键,由开发人员自己录入,比如录入身份证号或者学号等自然主键 |
hibernate中的对象状态
对象分为三种状态
- 瞬时状态:没有id,没有与session进行关联
- 持久化状态:有id,与session进行了关联
- 游离 | 托管状态:有id,没有与session进行关联
三种状态的举例
1 Customer c = new Customer(); // 此时没有id,没有与session关联,瞬时状态 2 3 c.setCust_name("timo"); // 只是设置了名字,没有设置id,所以还是没有id,瞬时状态 4 5 session.save(c); // 有id,跟session进行了关联,持久化状态 6 7 tx.commit(); 8 9 session.close(); // session关闭,有id,没有与sesion关联,游离状态
颠覆认知的时刻,save不是save,update不是update,delete也不是delete!!!
程序在执行session.save(c)等方法时,通过名字很容易认为是将对象保存进了数据库,但其实并不是,诸如save(),update(),delete(),get()等方法都只是为了改变对象的状态,并不是如字面理解意思的那样
save不是save
Customer c = new Customer(); c.setCust_name("timo"); /* save方法其实不能理解为保存,而应理解成将对象从瞬时状态转换成持久化状态, 但是在执行save()方法的时候确实执行了数据库插入语句insert,确实对数据进行了保存, 但那是因为在执行save方法时,为了将对象转换成持久化状态,必须生成id,所以要执行insert语句, 但是如果将主键生成策略更改为 increment 后,由于increment生成主键的策略是先查询出数据库里面的最大id, 然后+1生成当前记录主键,并不需要执行insert语句来生成主键,所以在执行save()方法时就只是执行了查询语句, 并没有执行插入语句,这样看来save()方法就没有起到保存对象的作用,只是关联了session与生成了id, 将原本的瞬时对象转换成了持久化对象,这将save不是save的观点体现的尤为明显 */ session.save(c); tx.commit(); session.close();
持久化状态的对象的任何变化都会同步到数据库中
Customer c = new Customer(); c.setCust_name("timo"); Customer c = session.get(Customer.class, 1L); // 持久化状态 c.setCust_name("Scartlett"); // 由于持久化状态对象的任何变化都会同步到数据库中,所以在commit后会执行update指令,将这条修改了姓名的记录插入到了数据库 // 那既然在上面修改时就已经将数据更新到了数据库,那么这里的update方法有什么用呢?其实这就是为什么说update不是update的原因,这里的update方法本质的作用其实是将对象的游离状态转换成持久化状态 session.update(c); tx.commit(); session.close();
各种方法转换对象状态的关系