Hibernate对象的CRUD操作
1. Hibernate对象的CRUD操作
1.1. 对象的三种状态
瞬时(Transient) - 由new操作符创建,且尚未与HibernateSession 关联的对象被认定为瞬时(Transient)的。瞬时(Transient)对象不会被持久化到数据库中,也不会被赋予持久化标识(identifier)。如果瞬时(Transient)对象在程序中没有被引用,它会被垃圾回收器(garbage collector)销毁。使用Hibernate Session可以将其变为持久(Persistent)状态。(Hibernate会自动执行必要的SQL语句)
持久(Persistent) - 持久(Persistent)的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。持久(Persistent)的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义,它存在于相关联的Session作用范围内。 Hibernate会检测到处于持久(Persistent)状态的对象的任何改动,在当前操作单元(unit of work)执行完毕时将对象数据(state)与数据库同步(synchronize)。开发者不需要手动执行UPDATE。将对象从持久(Persistent)状态变成瞬时(Transient)状态同样也不需要手动执行DELETE语句。
脱管(Detached) – 与持久(Persistent)对象关联的Session被关闭后,对象就变为脱管(Detached)的。 对脱管(Detached)对象的引用依然有效,对象可继续被修改。脱管(Detached)对象如果重新关联到某个新的Session上,会再次转变为持久(Persistent)的(在Detached其间的改动将被持久化到数据库)。这个功能使得一种编程模型,即中间会给用户思考时间(user think-time)的长时间运行的操作单元(unit of work)的编程模型成为可能。我们称之为应用程序事务,即从用户观点看是一个操作单元(unit of work)。
// 读取配置文件,得到Configuration对象 Configuration config = new Configuration().configure();
// 获得会话工厂 SessionFactory sf =
config.
Session session = sf.openSession();
sf.getCurrentSession();
// session.
Transaction tx = null;
try {
// 开始事务 tx = session.beginTransaction();
UserModel userModel = new UserModel("003", "morris", 22); // 此时userModel为瞬时态
// 保存对象 session.save(userModel); // 此时userModel持久态
// 提交事务 tx.commit(); } catch (Exception e) { e.printStackTrace(); if (tx != null) { tx.rollback(); } } finally { session.close(); } // 此时userModel脱管态 |
1.2. 增加持久对象
? persist() 使一个临时实例持久化。然而,它不保证立即把标识符值分配给持久性实例,这会发生在flush的时候。persist() 也保证它在事务边界外调用时不会执行 INSERT 语句。这对于长期运行的带有扩展会话/持久化上下文的会话是很有用的。
? save() 保证返回一个标识符。如果需要运行 INSERT 来获取标识符(如 "identity" 而非"sequence" 生成器),这个 INSERT 将立即执行,不管你是否在事务内部还是外部。这对于长期运行的带有扩展会话/持久化上下文的会话来说会出现问题。
1.3. 删除持久对象
? delete() 用来删除一个对象,参数为一个对象,并不是一个主键,执行delete方法的时候首先会去数据库中查找有有没有对象的主键所对应的记录,如果有就会执行删除操作;
如果没有,不会报错。
Hibernate: select usermodel_.userId, usermodel_.userName as userName2_0_, usermodel_.userAge as userAge3_0_ from userInfo usermodel_ where usermodel_.userId=? Hibernate: delete from userInfo where userId=? |
1.4. 修改持久对象
? update
Hibernate: update userInfo set userName=?, userAge=? where userId=? |
? merger
l 如果数据库中的数据与对象的数据一致,执行下面的sql语句
Hibernate: select usermodel0_.userId as userId1_0_0_, usermodel0_.userName as userName2_0_0_, usermodel0_.userAge as userAge3_0_0_ from userInfo usermodel0_ where usermodel0_.userId=? |
l 如果数据库的数据与对象的数据不一致,就会执行下面的sql语句
Hibernate: select usermodel0_.userId as userId1_0_0_, usermodel0_.userName as userName2_0_0_, usermodel0_.userAge as userAge3_0_0_ from userInfo usermodel0_ where usermodel0_.userId=? Hibernate: update userInfo set userName=?, userAge=? where userId=? |
l 如果数据库中不存在这条记录,则添加
Hibernate: select usermodel0_.userId as userId1_0_0_, usermodel0_.userName as userName2_0_0_, usermodel0_.userAge as userAge3_0_0_ from userInfo usermodel0_ where usermodel0_.userId=? Hibernate: insert into userInfo (userName, userAge, userId) values (?, ?, ?) |
1) 如果session中存在相同持久化标识的实例,用用户给出的对象的状态覆盖旧有的持久实例
2) 如果session中没有相应的持久实例,则尝试从数据库中加载,或创建新的持久化实例
3) 最后返回该持久实例
4) 用户给出的这个对象没有被关联到 session 上,它依旧是脱管的
? saveOrUpdate 自动检测,如果是新的记录就添加,如果是修改记录,就修改
1) 如果对象已经在本session中持久化了,不做任何事
2) 如果另一个与本session关联的对象拥有相同的持久化标识,抛出一个异常
3) 如果对象没有持久化标识属性,对其调用save()
4) 如果对象的持久标识表明其是一个新实例化的对象,对其调用save()。
1.4.1. update和merge方法的区别
1) 如果数据库里面存在你要修改的记录,update每次是直接执行修改语句;而merge是先在缓存中查找,缓存中没有相应数据,就到数据库去查询,然后再合并数据,如果数据是一样的,那么merge方法不会去做修改,如果数据有不一样的地方,merge才真正修改数据库。
2) 如果数据库中不存在你要修改的记录,update是报错;而merge方法是当作一条新增的值,向数据库中新增一条数据。
3) update后,传入的TO对象就是PO的了,而merge还是TO的。
4) 如果你确定当前session没有包含与之具有相同持久化标识的持久实例,使用update()。如果想随时合并改动而不考虑session的状态,使用 merge()。换句话说,在一个新 session中通常第一个调用的是update()方法,以保证重新关联脱管对象的操作首先被执行。
5) 请注意:使用update来把一个TO变成PO,那么不管是否修改了对象,都是要执行update sql语句的。
1.4.2. 使用update() 或saveOrUpdate()的场景
1) 程序在第一个 session 中加载对象
2) 该对象被传递到表现层
3) 对象发生了一些改动
4) 该对象被返回到业务逻辑层
5) 程序调用第二个session的update()方法持久这些改动
1.5. 按主键查询持久对象
1) load方法:load的时候首先查询一级缓存,没有就创建并返回一个代理对象,等到使用的时候,才查二级缓存,如果二级缓存中没有数据就查数据库,如果数据库中没有,就抛例外
2) get方法:先查缓存,如果缓存中没有这条具体的数据,就查数据库,如果数据库没有值,就返回null,总之get方法不管用不用,都要拿到真实的数据
1.5.1. get和load的区别
1) get()方法直接返回实体类,如果查不到数据则返回null。load()会返回一个实体代理对象(当前这个对象可以自动转化为实体对象),但当代理对象被调用时,如果没有数据不存在,就会抛出个org.hibernate.ObjectNotFoundException异常
2) load先到缓存(session缓存/二级缓存)中去查,如果没有则返回一个代理对象(不马上到DB中去找),等后面使用这个代理对象操作的时候,才到DB中查询,这就是我们常说的 load在默认情况下支持延迟加载(lazy)
3. get先到缓存(session缓存/二级缓存)中去查,如果没有就到DB中去查(即马上发出sql)。总之,如果你确定DB中有这个对象就用load(),不确定就用get()(这样效率高)
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。