Hibernate Session & Transcation 持久化对象的三种状态 实例

Hibernate Session & Transcation 持久化对象的三种状态 + 实例

Reference : https://blog.youkuaiyun.com/mabixie/article/details/79440652

https://www.qingtingip.com/h_381958.html

https://blog.youkuaiyun.com/confirmAname/article/details/9324633

 

Hibernate的事务( Transaction对象 )通过Session的beginTransaction( )方法显式打开,Hibernate自身并不提供事务控制行为(没有添加任何附加锁定行为),Hibernate底层直接使用JDBC连接、JTA资源或其他资源的事务。

 

Hibernate只是对底层事务进行了抽象,让应用程序可以直接面向Hibernate事务编程,从而将应用程序和JDBC连接、JTA资源或其他事务资源隔离开了。从编程角度来看,Hibernate的事务由Session对象开启;从底层实现来看,Hibernate的事务由 TransactionFactory 的实例来产生。

 

TransactionFactory是一个事务工厂的接口,Hibernate为不同的事务环境提供了不同的实现类。如CMTTransactionFactory是针对容器管理事务环境的实现类、JDBCTransactionFactory是针对JDBC局部事务环境的实现类、JTATransactionFactory是针对JTA全局事务环境的实现类。

 

应用程序编程无须手动操作TransactionFactory产生事务,这是因为SessionFactory底层已经封装了TransactionFactory。

 

SessionFactory对象的创建代价很高,它是线程安全的对象,被设计成可以被所有线程所共享。通常SessionFactory会在应用程序启动时创建,一旦创建了SessionFactory将不会轻易关闭,只有当应用退出时才关闭SessionFactory。

 

Session对象是轻量级的,它是线程不安全的。对于单个业务进程,单个的工作单元而言,Session只被使用一次创建Session时,并不会立即打开与数据库的连接,只有需要进行数据库操作时,Session才会获取JDBC连接。因此打开和关闭Session,并不会对性能造成很大的影响。甚至即使无法确定一个请求是否需要数据访问,也可以打开Session对象,因为如果不进行数据库访问,Session不会获取JDBC连接。

<Hibernate延迟加载机制

https://blog.youkuaiyun.com/qq_20864311/article/details/102688391>

使用hibernate进行增删改是要重新开启事务,使用查询时可以不用重新开启事务!

Hibernate中持久化的对象可以划分为三种状态,分别是瞬持久态脱管态

1、 瞬时态(transient)

瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建、开辟内存空间的对象,不存在持久化标识OID(相当于主键值),尚未与Hibernate Session关联,在数据库中也没有记录,失去引用后将被JVM回收。瞬时状态的对象在内存中是孤立存在的,与数据库中的数据无任何关联,仅是一个信息携带的载体。

2、 持久态(persistent)

 持久态的对象存在持久化标识OID ,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象,需要注意的是,持久态对象是在事务还未提交前变成持久态的

3、 脱管态(detached)

脱管态也称离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭时就变成了脱管态。脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。

how to assign OID?

持久化类要有一个唯一标识OID与表的主键对应。因为Hibernate中需要通过这个唯一标识OID区分在内存中是否是同一个持久化类。在Java中通过地址区分是否是同一个对象的,在关系型数据库的表中是通过主键区分是否同一条记录。那么Hibernate就是通过这个OID来进行区分的。Hibernate是不允许在内存中出现两个OID相同的持久化对象的。

持久化类的编写规则 :

  1. 持久化类需要提供无参数的构造方法。因为在Hibernate的底层需要使用反射生成类的实例。
  2. 持久化类的属性需要私有,对私有的属性提供公有的get和set方法。因为在Hibernate底层会将查询到的数据进行封装。
  3. 持久化类的属性要尽量使用包装类的类型。因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更清晰而基本数据类型不容易描述。
  4. 持久化类尽量不要使用final进行修饰。因为Hibernate中有延迟加载的机制,这个机制中会产生代理对象,Hibernate产生代理对象使用的是字节码的增强技术完成的,其实就是产生了当前类的一个子类对象实现的。如果使用了final修饰持久化类。那么就不能产生子类,从而就不会产生代理对象,那么Hibernate的延迟加载策略(是一种优化手段)就会失效。.】】

Session和线程绑定

在Hibernate中,可以通过代码来操作管理事务,如通过“Transaction tx = session.beginTransaction();”开启一个事务;持久化操作后,通过“tx.commit();”提交事务;如果事务出现异常,又通过“tx.rollback();”操作来撤销事务(事务回滚)。

除了在代码中对事务开启,提交和回滚操作外,还可以在Hibernate的配置文件中对事务进行配置。配置文件中,可以设置事务的隔离级别。其具体的配置方法是在hibernate.cfg.xml文件中的<session-factory>标签元素中进行的。

Reference : https://bbs.youkuaiyun.com/topics/200045119

hibernate要求一个session一个事务吗?

public class UserOperate {

 

    /**This Class is the tool class for Class User

     * @param null

     */

    private Session session = null;

 

    public UserOperate() {

        File file = new File("hibernate.cfg.xml");

        if (file.exists()) {

            Configuration config = new Configuration().configure(file);

            SessionFactory factory = config.buildSessionFactory();

            this.session = factory.openSession();

        else {

            System.out.println("error");

            System.exit(0);

        }

    }//构造函数,应该不会错吧

 

    public void insert(User user) {

        session.getTransaction().begin();

        this.session.save(user);

        session.getTransaction().commit();

        //session.close();                                                            我也不知道什么时候关闭session

    }//插入User数据函数

     

    @SuppressWarnings("unchecked")

    public User queryByName(String name){

        User user=null;

        String hql="FROM User as p where p.name=?";

        Query q=this.session.createQuery(hql);

        q.setString(0,name);

        List<User> userList=q.list();

        Iterator<User> iter=userList.iterator();

        if(iter.hasNext()){

            user=iter.next();

        }

        return user;

    }//按名字查找数据

     

    public void delete(String name){

        String hql="delete User where name=?";

        Query q=this.session.createQuery(hql);

        q.setString(0, name);

        session.getTransaction().begin();

        q.executeUpdate();

        session.getTransaction().commit();

        session.close();

    }//删除数据

     

    @SuppressWarnings("unchecked")

    public List<User> queryAll(){

        List<User> list=null;

        String hql="from User";

        Query q=this.session.createQuery(hql);

        list=q.list();

        return list;

    }//查找所有

     

    @SuppressWarnings("unchecked")

    public List<User> queryNameLike(String content){

        List<User> list=null;

        String hql="from User where name like ?";

        Query q=this.session.createQuery(hql);

        q.setString(0"%"+content+"%");

        list=q.list();

        return list;

    }//模糊查询

     

    public boolean canLogin(String name,String password){

        boolean flag=false;

        User userGet=this.queryByName(name);

        if(userGet!=null){

            password=Md5Encrypt.encrypt(Md5Encrypt.encrypt(password));

            if(userGet.getPassword().equals(password))

                flag=true;

            else

                System.out.println("密码错误");

        }

        else{

            System.out.println("没有该用户存在");

        }

        return flag;

    }//自己写的判断能否登录的函数,其中两次对password加密,可以判断提取出来的密码跟输入的password的一致性

}

我的入口类,经过很多次试验,每对数据库进行一次操作就要new 一个UserOperate对象出来,否则整个程序只能做最后一次分配的操作,帮忙看看:

public class Object {

    public static void main(String[] args) {

        User user=new User();

        UserOperate userop=new UserOperate();

         

        user.setName("Newflypig");

        user.setPassword("8215085");

         

        userop.insert(user);

         

        for(int i=0;i<10;i++){

            user.setName("dingding"+String.valueOf(i));

            user.setPassword("newflypig");

            new UserOperate().insert(user);

        }

     

        List<User> list=new UserOperate().queryAll();

        Iterator<User> iter=list.iterator();

        while(iter.hasNext()){

            System.out.println(iter.next().getName());

        }

 

        System.out.println(new UserOperate().canLogin("dingding0""newfypig"));

 

    }

}

解答:

在你的程序里User user=new User();

此时的user的状态为瞬时状态,即user还未与session进行关联。

你new UserOperate对象同时即声明了一个session。 

当你调用UserOperateUser.insert(user)时,即将此user对象同当前的session进行关联此时的user对象即为持久状态,因此在你循环中不管对此user操作多少次仅是对关联后的user进行修改。

当你在循环中 new UserOperate().insert(user)时你所使用的user对象所关联的是不同session。

因此你成功的插入了10条数据。
如果你使用循环的话建议你对原有程序进行修改
Transaction.begin();
for(int i=0;i<10;i++){
   User user=new User();
   user.setName("dingding"+String.valueOf(i));
   user.setPassword("newflypig");
   session.save(user);
}
Transaction.commit();

Hibernate建议采用每个请求对应一次Session的模式------一次请求通常表示需要执行一个完整的业务功能,这个功能由系列的数据库原子操作组成,而且它们应该是一个逻辑上的整体。

每个请求对应一个Session的模式,不仅可以用于设计操作单元,甚至,很多业务处理流程都需要组合一系列的用户操作,即用户对数据库的交叉访问。

在某些应用架构中,特别是对于那些需要使用Hibernate进行数据访问的代码,以及那些需要在不同应用层和不同进程中使用Hibernate的应用,如何保证Session处于打开状态也是一个问题。通常有两种方法可以解决此问题:

 

① 在一个web应用中,可以利用过滤器Filter,在用户请求结束、页面生成结束时关闭Session。也就是保证在视图显示层一直打开Session,这就是所谓的Open Session in View模式。当然采用这种模式时,必须保证所有异常得到正确处理,在呈现视图界面之前,或在生成视图界面的过程中发生异常时,必须保证可以正确关闭Session,并结束事务。

 

② 使用业务逻辑层来负责准备数据,在业务逻辑层返回数据之前,业务逻辑层对每个所需集合调用Hibernate.initialize()方法,或者使用带fetch子句或FetchMode.JOIN的查询,事先取得所有数据,并将这些数据封装成VO(值对象)集合,然后程序可以关闭Session了。业务逻辑层将VO集传入视图层,让视图层只负责简单的显示逻辑。在这种模式下,可以让视图层和Hibernate API 彻底分离,保证视图层不会出现持久层API,从而提供更好的解耦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值