第二节 hibernate session介绍以及session常用方法介绍


原创地址:http://www.cnblogs.com/binyulan/p/5628579.html  

 

  Session是java应用程序和hibernate框架之间的一个主要接口。它是从持久化服务中剥离出来的一个非常重要的API接口。

  Session的主要功能是为映射的实体类的实例提供增删改查操作(User.class 为被映射的实体类,new User()即为实例)。这些实例可能是以下三种状态之一:

  1) transient: 从没有被持久化,不在Session缓存中
  2) persistent: 在Session的缓存中。
  3) detached: 曾经是persistent状态,现在不在Session缓存中。

  transient 实例通过调用save(), persist() or saveOrUpdate()可以变成persistent实例。persistent实例通过调用delete可以变成transient实例。任何通过get()或者load()方法获取的实例都是persistent实例。detached实例通过调用update(), saveOrUpdate(), lock() or replicate()可以变成persistent实例。transient或者detached实例通过调用merge()方法可以生成一个新的persistent实例,但是并不是他们自己,这个persistent实例是merge方法自己创建的。

  save() 和 persist() 生成SQL insert。delete() 生成SQL delete。update() 和 merge()生成SQL update。对persistent实例的修改在flush时会生成SQL update。saveOrUpdate() 和 replicate()生成insert或者update。

  Session接口的实现类并没有专门设计为线程安全的。相反,每个线程或者事务都应该通过SessionFactory获取自己的实例。

  一个典型的事务应该使用如下的形式:

 Session sess = factory.openSession();
 Transaction tx;
 try {
     tx = sess.beginTransaction();
     //do some work
     ...
     tx.commit();
 }
 catch (Exception e) {
     if (tx!=null) tx.rollback();
     throw e;
 }
 finally {
     sess.close();
 }

  如果Session抛出异常,事务必须回滚。同时Session被弃用,因为Session内部状态和数据库可能会不一致。

1 保存对象到数据库 session.save(Object user); //参数user为transient实例,返回值为新生成的主键id

持久化transient实例。返回值为生成的主键id。

按照第一节的配置,主键的生成策略为native(数据库自动生成主键),由于数据库使用的是mysql 5,所以是自增的主键生成方式。保存对象时并不需要设置id属性。

    @Test
    public void testSave() {
        try {
            User user = new User();
            user.setBirthday(new java.sql.Date(0));
            user.setName("binyulan");
            session.save(user);
        } catch (HibernateException e) {
            if (transaction != null) {
                transaction.rollback();
            }
            throw e;
        }
    }

2 保存对象到数据库 session.persist(Object user); //参数user为transient实例

持久化transient实例。这个方法和session.save()方法一样,都是保存对象到数据库。但是不能设置id属性,否则抛出异常。

    @Test
    public void testPersist() {
        try {
            User user = new User();
            user.setBirthday(new java.sql.Date(0));
            user.setName("binyulan");
            user.setId(13);
            session.persist(user);
        } catch (HibernateException e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            throw e;
        }
    }

 执行testPersist后抛出异常,如下:

org.hibernate.PersistentObjectException: detached entity passed to persist: com.binyulan.domain.User
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)

user创建出来为transient实例,但是异常显示是detached实例。所以我认为只要给对象设置了id属性,即使没有持久化过,也可以看做detached实例。

persist()方法的参数为transient实例,即不带主键id的实例。save()方法参数也为transient实例,但是也可以给此实例设置id属性,即detached实例,

只不过此id属性不起作用(native生成方式下)。结论如下:

save()和persist()方法参数虽然都说明为transient实例,但是也可以传detached实例,也可以传persistent实例。但是没有理由传非transient实例,因为这些方法都是设计为传transient实例的,虽然传其他实例也可以,但是不推荐,谁知道100年后hibernate90.10.9会不会改变save()或persist()方法传入非transient实例的行为呢。

3 合并对象到数据库 session.merge(Object user); //参数user为detached实例,其属性将被copy到persistent实例。并且返回此persistent实例

拷贝user到持久化对象。如果没有persistent对象在session缓存中,则加载数据到persistent对象并且返回此persistent对象。

如果user在数据库中没有对应记录,则拷贝user到一个副本作为persistent对象并且返回这个persistent对象。user不会被保存到session缓存中



1) 保存未设置id属性的User对象,执行insert把User对象保存到数据库中,同时返回保存后的User对象。

    @Test
    public void testMerge() {
        try {
            User user = new User();
            user.setBirthday(new java.sql.Date(0));
            user.setName("binyulan2");
            User user1 = (User) session.merge(user); //把user属性拷贝到新建的user1对象,执行insert插入数据库,并且返回新建的user1对象,user1包含id,在session缓存中
            System.out.println(user1 == user); //返回false。user为新建的对象,并没有放入session缓存。user1为新建的持久化对象,并且在session的缓存中。
        } catch (HibernateException e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            throw e;
        }
    }

2) 保存设置id属性的User对象,首先执行select查询数据库。若数据库中存在此id的记录,并且与数据库中记录不一致,则执行update操作,

若不存在此记录,否则执行insert操作。

    @Test
    public void testMerge1() {
        try {
            User user = new User();
            user.setBirthday(new java.sql.Date(0));
            user.setName("binyulan123");
            user.setId(20);
            /**
             * 把user属性拷贝到新建的User对象,并且执行select查询数据库。
             * 假设数据库中存在id为20的记录,且user对象与数据库中记录不一致,执行update
             */
            User user1 = (User) session.merge(user); 
            System.out.println(user1 == user); //返回false。user为参数,不在session缓存中,user1为新建的持久化对象,并且在session的缓存中。
            
            /**
             * 把user属性拷贝到新建的User对象,并且执行select查询数据库。
             * 假设数据库中不存在id为123456789的记录,执行insert
             */
            user.setId(123456789L);
            User user2 = (User) session.merge(user); 
            System.out.println(user2 == user); //返回false。user为参数,不再session缓存中,user2为新建的持久化对象,并且在session的缓存中。
        } catch (HibernateException e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            throw e;
        }
    }

4 数据更新,session.update(Object user);// 参数为一个detached实例。

使用user更新数据库中记录,并且把user对象变为persistent实例。

    @Test
    public void testUpdate() {
        User user = new User();
        user.setName(null);
        user.setBirthday(null);
        user.setId(20);
        session.update(user);
    }

 

5 更新或者保存,session.saveOrUpdate(Object  user);

    @Test
    public void testSaveOrUpdate() {
        User user = new User();
        user.setName(null);
        user.setBirthday(null);
        session.saveOrUpdate(user); //insert操作
        
        User user1 = new User();
        user1.setName(null);
        user1.setBirthday(null);
        user1.setId(9);
        session.saveOrUpdate(user1);//update操作
    }

6 删除操作,session.delete(Object user);

从session缓存中删除一个persistent实例。参数为一个Session缓存中的实例或者一个带id的transient实例

    @Test
    public void testDelete() {
        User user = new User();
        user.setId(9);
        session.delete(user);
    }

7 查询操作,session.get(Class clazz, Serializable id);

根据给定的Class对象和主键id返回persistent实例,如果数据库中没有此记录,则返回null。

    @Test
    public void testGet() {
        User user = (User) session.get(User.class, 1L);
        System.out.println(user);
    }

8 查询操作,session.load(Class theClass, Serializable id);

返回一个代理对象,并在访问非主键id属性时会初始化这个代理对象。不能使用这个方法判断是否一个实例存在。即使数据库中没有相应记录,也会返回代理对象,但是在使用此代理对象是就会报错。

@Test
    public void testLoad() {
        User user = (User) session.load(User.class, 1L); //返回的user为代理对象
        user.getName(); //访问name属性时向数据库发送SQL select
        System.out.println(user.getClass()); //代理对象类
    }

9 复制操作,replicate(Object object, ReplicationMode replicationMode);

    @Test
    public void testReplicate() {
        User user = new User();
        user.setId(48);// 假定数据库中存在id为48的记录
        user.setBirthday(new java.sql.Date(0));
        user.setName("binyulan1");
        /**
         * 可以选择复制的模式,OVERWRITE模式为如果存在此记录,则覆盖
         * 执行SQL select
         */
        session.replicate(user, ReplicationMode.OVERWRITE);
        session.flush();// 执行SQL update
        
        User user1 = new User();
        user1.setId(48);
        user1.setBirthday(new java.sql.Date(0));
        user1.setName("binyulan2");
        /**
         * 可以选择复制的模式,IGNORE模式为如果存在此记录,则不进行更新
         * 执行SQL select
         */
        session.replicate(user1, ReplicationMode.IGNORE);
        session.flush();// 记录存在,所以忽略掉,不会执行SQL update
        
        User user3 = new User();
        user3.setId(48);
        user3.setBirthday(new java.sql.Date(0));
        user3.setName("binyulan3");
        /**
         * 可以选择复制的模式,EXCEPTION模式为如果存在此记录,则抛异常
         * 此语句执行SQL insert,ReplicationMode.EXCEPTION 始终都会执行SQL insert。
         * 使用数据库自身约束抛出异常,因为使用的是native主键生成方式,所以此处不抛异常,会插入成功
         */
        session.replicate(user3, ReplicationMode.EXCEPTION);
    }

 10 强制同步数据到数据库,session.flush();

可以设置FlushMode, 如果设置为NERVER,且不手动执行session.flush(), 提交事务也不会执行SQL update。

System.out.println(session.getFlushMode()); //默认模式为AUTO

    @Test
    public void testFlush() {
        User user = new User();
        user.setId(1); //假设id为1的记录存在
        user.setBirthday(new java.sql.Date(0));
        user.setName("binyulan3");
        session.update(user);
        session.flush(); //强制执行SQL update
    }

11 同步数据库中数据到java对象,session.refresh(Object user); //参数为persistent实例或者detached实例

 重新读取数据库记录到user,不建议在跨多个业务长时间运行的session中使用。在以下特定场景中使用

  1) 触发器出发了一个insert或者update
  2) 执行一大堆sql后
  3) 插入一个Blob或Clob后

@Test
    public void testRefresh() {
        User user = (User) session.get(User.class, 1L);
        user.setName("original");
        session.refresh(user); //重新同步数据库中记录到user,此时user的name不是original
        System.out.println(user.getName()); // 输出binyulan
    }

 

 

请勿转载,谢谢合作

原创地址:http://www.cnblogs.com/binyulan/p/5628579.html  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM