在介绍hibernate的更新之前,我们先来看看session的两个方法。load和get方法;这两个方法是获取数据的根据对象的id值;
先看两段代码。load和get的方法都含有两个参数,前者是得到的对象类型。后者是一个可序列化的值,说白了也就是你要获取数据库里面对应的主键的值,你的主键如果是id。你获取的是第一条记录那么则是一,如果你的主键是name。你就写上某个名字。然后获取这个名字对应的数据记录。
当我们执行下面两条语句的时候,我们会发现第一条报错。而第二条是没有什么问题的。
但是如果我们把两个里面的打印语句都写到commit之前的时候。我们发现两个都不会报错了。
@Test public void testload(){ Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.load(Teacher.class, 1); session.getTransaction().commit(); System.out.println(t.getName()); } @Test public void testget(){ Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.get(Teacher.class, 1); session.getTransaction().commit(); System.out.println(t.getName()); }
这里面是有原因的。当用load获取的时候,其实执行load语句只是将对象置入到内存中。而执行get方法的时候。不但将对象放入到了内存而且。对象执行了sql语句。对象的值已经在getName方法执行已经赋值了。而load方法。在执行getName方法的时候才执行sql语句,从数据库里面获取相关的记录。当我们在执行getName方法前后加上时间的时候。我们得到时间差的话我们会发现,我load这种情况下getName费许多的时间。而get这种情况几乎没有费什么时间。
那么为什么在提交之后,load得到getName的方法会出错呢。那是因为提交完之后。当前的session自动关闭了。当然这是getCurrentSession的情况下。而再去调用镀锡的getName方法的时候。session对象关闭了。相等于缓存中没有对应的记录了。只有数据库和内存中有。此时再无获取getname的时候没有中间桥梁session。那么肯定出错。而get方法的话。因为已经在get方法执行的时候将数据赋值给了对象。那么我们获取的时候直接从内存里面拿去好了。用不着经由session去访问数据库。所以不会出错。
下面来具体谈谈更新数据的情况
更新数据我们的第一反应是从数据库里面讲数据拿出来然后改变某些值,然后再调用update的方法完成操作。这种方法是对的。但是不是只有这一种方法的。我们还有不通过调用update方法就可以完成更新。update方法里面传入的对象。一定要有主键的值。并且主键的记录一定可以在数据库里面找得到,这样才不会报错的。所以我们可以先不用从数据库里面拿去对象。而是先定义一个对象。之后再给此对象赋值。然后更新此对象。如果给的值在数据库中含有那么对应的记录也可以然后更新。
1.常规方法先从数据库里面拿取,然后更新
Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.get(Teacher.class, 1); t.setName("wsx"); session.update(t) session.getTransaction().commit();
2.先创建一个对象,然后给其赋值。再更新。
Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=new Teacher(); t.setName("wsx"); session.update(t) session.getTransaction().commit();
以上这两种方法都可以完成更新的操作。
而以下的这种方法也是可以完成更新的。并且没有用到update方法;
Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.get(Teacher.class, 1); t.setName("wsx"); session.getTransaction().commit();
我们仔细瞧下来会发现。它与第一个方法的不同之处就是没有用到update方法。难道这也行吗?嗯。我肯定的告诉你。
接下来我们探究其道理。
当我们执行get方法的时候,其实在内存中,缓存session中,数据库中都有对应的Teacher对象。而当我们改变其内存中对象的名字的时候。我们再提交的话,其实是数据库事务会去检测,内存中的session对象的值和缓存session中的值是否一致,不一致的话,那么则提交更新。
更新数据时遇到的问题。
我们会发现更新数据的时候。如果一个表中有五个字段,而我们只更新一个字段比较说更新年龄字段的时候。那么我们会从打印日志中惊奇的发现我们的其他几个字段也更新了。这种更新方式是很不友好的。代价也很巨大。也许本来你只需更新一个年龄的值。而其他字段里面有一篇文章。那么你只简简单单更新一个年龄却引起一篇文章的更新。
根据这一问题,我们有一些几个解决问题的办法
1.通过annotation在某个不需要更新的字段的get方法之前加上@column(updatable=false);
@Column(updatable=false) ublic String getName() { return name;
这种方法的缺点是这个字段永远不会更新。这个我们一想就感觉很不灵活。也许某一天这个字段需要更新。但是也有永不更新的情况。这个很多。比如一个银行的名字。等待。
2.在xml配置文件里面class加上dynamic——update=true;
Xml代码
<hibernate-mapping> <class name="com.bjsxt.hibernate.Student" dynamic-update="true"> <id name="id" column="id"/> <property name="name" /> <property name="age" /> </class> </hibernate-mapping>
这样就会自动更新。但是我们的自动更新某些需要更新的列的话,我们必须要在同一个session中。不同的session。找不到参考依据的话,那么也会集体更新的。
@Test public void testupdate1(){ Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.get(Teacher.class, 1); t.setName("wsx"); session.update(t); session.getTransaction().commit(); t.setName("wsx1"); Session session1 =null; session1 =sessionFactory.getCurrentSession(); session1.beginTransaction(); session.update(t); session.getTransaction().commit(); }
第一个session的update方法只会更新name。而第二个全部属性都会更新;
3.用hql语句。你需要更新那个列,那么则写成相应的形式;
Java代码 @Test public void testupdate2(){ Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Query q=session.createQuery("update tablename set name='wsx' where id=1 "); q.executeUpdate(); session.getTransaction().commit(); }
我们很多情况下用到第三种方式。 好了更新就讲到这儿。