hibernate将orm对象的种类分为四种,分别是:java
临时状态sql
临时状态通常来讲就是咱们使用new关键字建立的对象,尚未和session关联上,而且对象的id为null。调用session的save方法、saveorupdate方法、persist方法、merge方法、get方法和load方法均可以使临时状态对象变为持久化状态对象。
数据库
持久化状态编程
持久化状态也被称为托管状态,又session缓存进行托管,持久化对象的id不为空,而且与数据库中的记录相互对应。调用session的evict方法、clear方法和close方法可使持久化状态对象变为游离状态对象。
缓存
游离状态session
游离状态能够理解为对象从session缓存中取出后,session缓存被清空了,或者session被关闭了,又或者调用了evict方法将该对象手动从session缓存中删除了,这时session再也不对该对象进行托管。游离状态与临时状态的一个区别就是,游离状态的对象的id不为空,而且数据库中有可能还保存着这个对象的信息。app
调用session的update方法、saveorupdate方法和merge方法可使游离状态对象变为持久化状态对象。
ide
删除状态测试
调用了session的delete方法后,被delete的对象的状态将变为删除状态。通常来讲删除状态的对象将不会在使用了,当事务commit的时候,数据库中也会将该对象删除。.net
以上就是orm对象在session中的四种状态,接下来测试一下session的经常使用方法。首先是save方法:
@Test public void testSave() { // 建立一个对象,该对象如今为临时状态。 User user = new User(); // 此处设置id的值不会生效 // save方法将调用sql本地生成方式重新为对象id赋值。 user.setId(100); user.setName("Kobe"); user.setBirthday(new Date()); // 调用save方法将对象状态改变为持久化状态,由session缓存托管。 session.save(user); // 持久化后的对象id不容许修改,不然将出现异常。 // org.hibernate.HibernateException: // identifier of an instance of cn.net.bysoft.model.User was altered // from 1 to 13 // user.setId(13); }
上面是save方法的测试,须要注意的就是在save以前,设置对象的id无效,save方法将调用id生成方式生成一个id复制给对象。在save后,不可修改id,不然将会抛出异常。接下来了persist方法:
@Test public void testPersist() { User user = new User(); // 使用persist保存对象,若是设置了id值将会抛出异常。 // user.setId(111); user.setName("Jordan"); user.setBirthday(new Date()); session.persist(user); }
使用persist方法也能够将对象从临时状态改变为持久化状态,而且保存到数据库中。与save方法的区别在于若是,调用save方法前设置的id无效,但不会发生异常,而使用persist方法以前若是设置了id,将会抛出异常。
在看看get方法:
@Test public void testGet() { // 从数据库中得到id=3的记录,加载到User对象中。 // User对象从临时状态改变到持久化状态。 User user = (User) session.get(User.class, 3); System.out.println(user); /** * output: User [id=3, name=Jordan, birthday=2016-03-25 19:56:14.0] * */ // 若是传入的id在数据库中找不到记录,则返回null。 User user2 = (User) session.get(User.class, 44); System.out.println(user2); /** * output: null * */ }
调用get方法后,会发送一条select语句到数据库,查找id对应的记录,若是查找到,则将记录加载到对象中,并把对象的状态改变为持久化状态,若是没用经过id得到记录,则返回null。
get方法以后,看看load方法:
@Test public void testLoad() { // load方法建立了一个user的代理对象,执行load后并不会发送select语句。 User user = (User) session.load(User.class, 3); // 在使用user对象的属性时,才发送select语句查询数据,这种机制叫作延迟加载。 System.out.println(user); /** * output: User [id=3, name=Jordan, birthday=2016-03-25 19:56:14.0] * */ // 若是传入的id在数据库中找不到记录。 User user2 = (User) session.load(User.class, 44); // 在使用该对象时会抛出异常。 System.out.println(user2); }
在执行load方法后,hibernate不会当即去发送select语句查询数据库,而是建立一个代理,等到调用对象的属性时,由代理去发送select语句查询数据。
若load对象使用的id在数据库中不存在,则会抛出异常。
虽然都是从数据库查询数据加载到对象,但两个方法略有不一样,对比一下get方法与load方法:
get方法 |
load方法 |
|
什么时候执行select语句 |
调用get方法后当即执行select语句。 |
调用load方法后不执行select语句,而是建立一个代理。 等到使用对象的属性时再执行select语句。 |
若是id在数据库中不存在 |
调用get方法返回null |
调用load方法后,在使用该对象时会抛出异常。 |
在使用对象前调用session.close |
不会抛出异常 |
会抛出异常 |
以上是get方法与load方法,接下来测试一下update方法:
@Test public void testUpdate(){ // update方法能够将游离对象变为持久化对象。 User user = new User(); user.setId(2); user.setName("Jack"); user.setBirthday(new Date()); // 调用update将上面的游离状态对象变为持久化状态对象。 // 而且更新数据库中的记录。 session.update(user); }
建立一个User对象,这里由于给user设置了id,id不为空的话就不是临时对象,而是游离对象。经过update方法把游离对象的状态改为持久化对象,而且向数据库发送了update语句。
在调用flush的时候,若有必要,hibernate也会发送update语句,这里,数据库中如有触发器,则会频繁出发。这些出发中可能有没必要要的update操做。hibernate提供了select-before-update属性来解决这个问题,将该属性设置成true,在update以前会查询一次数据库,若是对象没有变化则不执行update。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- update以前先进行select,对象与数据库中的记录一致,则不执行update --> <class name="cn.net.bysoft.model.User" table="S_USER" select-before-update="true"> <id name="id" type="integer" column="ID"> <!-- 指定主键的生成方式,native是使用数据库本地的方式 --> <generator class="native"></generator> </id> <property name="name" type="string" column="NAME"></property> <property name="birthday" type="timestamp" column="BIRTHDAY"></property> </class> </hibernate-mapping>
update时,传入的id若是数据库中不存在,则抛出异常。
saveorupdate方法顾名思义是传入一个对象,由hibernate分析是save仍是update。规则是,若是对象id是null就save,若是id不是null就update。
@Test public void testSaveOrUpdate() { User user = new User(); user.setName("Mary"); user.setBirthday(new Date()); // user的id为null,执行insert操做。 session.saveOrUpdate(user); User user2 = new User(); user2.setId(2); user2.setName("Kobe"); user2.setBirthday(new Date()); // user的id为2,数据库中有id等于2的记录,将执行update操做。 session.saveOrUpdate(user2); }
第一个saveorupdate将输出insert语句,由于id is null。第二个将输出update语句,由于id=2,在数据库中存在这条记录。
若在*.hbm.xml的id属性上设置了unsaved-value的值,在作saveorupdate时,id不为null,可是值等于unsaved-value设置的值,也会进行save。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- update以前先进行select,对象与数据库中的记录一致,则不执行update --> <class name="cn.net.bysoft.model.User" table="S_USER" select-before-update="true"> <id name="id" type="integer" column="ID" unsaved-value="11"> <!-- 指定主键的生成方式,native是使用数据库本地的方式 --> <generator class="native"></generator> </id> <property name="name" type="string" column="NAME"></property> <property name="birthday" type="timestamp" column="BIRTHDAY"></property> </class> </hibernate-mapping>
将id节点的设置了一个unsaved-value属性,值是11。
@Test public void testSaveOrUpdate() { User user = new User(); user.setId(11); user.setName("Mark"); user.setBirthday(new Date()); // user的id为null,执行insert操做。 session.saveOrUpdate(user); }
这里设置了user的id等于11,与unsaved-value中的值同样。执行saveorupdate会发送一条insert语句。
可是数据库中的id值不是11,而是自增的id数值。
以上就是saveorupdate的基本应用。还剩下两个方法,一个是delete,一个是evict。先测试一下delete方法:
@Test public void testSaveOrUpdate() { User user = new User(); user.setId(6); session.delete(user); // 调用delete后,对象的状态变为删除状态。 // 在事务commit以前,打印这个对象看看。 System.out.println(user); /** * output: User [id=6, name=null, birthday=null] * */ // 能够看到在commit以前,user对象还有id,那么在commit以前调用save或者update就会出现问题。 // 建议不要删除状态的对象。 }
调用delete方法会把传入方法中的对象的状态改变成删除状态,可是在commit以前,这个对象还能够进行操做。建议不要使用删除状态的对象。
hibernate提供了hibernate.use_identifier_rollback属性,在hibernate.cfg.xml中设置,将属性的值等于true。在调用delete方法时,hibernate会自动将删除的对象的id置空。
<!-- 删除对象时,将对象的id设置成null --> <property name="hibernate.use_identifier_rollback">true</property>
@Test public void testSaveOrUpdate() { User user = new User(); user.setId(5); session.delete(user); System.out.println(user); /** * output:User [id=0, name=null, birthday=null] * */ }
设置了hibernate.use_identifier_rollback=true后,在删除对象能够看到输出的结果,对象的id被设置成了0。
还有就是,若是删除的对象id在数据库中不存在,将会抛出异常。
最后一个方法是evict,这个方法用来送session缓存中移除一个托管对象。也就是说将对象从持久化状态编程游离状态。
@Test public void testSaveOrUpdate() { // 持久化对象。 User user = (User) session.get(User.class, 3); System.out.println(user); // 调用evict方法变成游离对象。 session.evict(user); }
还有一点须要注意的,同一个id的对象在session的缓存中只能有一个。
@Test public void testSaveOrUpdate() { // 持久化对象。 User user = (User) session.get(User.class, 3); System.out.println(user); // 调用evict方法把id为3的user变成游离对象。 // 这是session缓存中已经没有对象了。 session.evict(user); // 把一个新的id为3的user对象放到缓存中。 User user1 = (User) session.get(User.class, 3); // 在尝试把旧的id为3的user对象放到缓存中,会抛出异常。 // 此时session的缓存中已经有一个id为3的user对象了 // org.hibernate.NonUniqueObjectException: // A different object with the same identifier value was already associated with the session : // [cn.net.bysoft.model.User#3] session.update(user); }
以上就是session的经常使用方法。