美文网首页hibernate学习
2.session基本操作

2.session基本操作

作者: 棱锋 | 来源:发表于2019-11-10 20:27 被阅读0次

    session与线程安全

    Session不是线程安全的。Session中包含了数 据库操作相关的状态信息,那么说如果多个线程同时使用一个Session实例进行CRUD,就很有可能导致数据存取的混乱。每个线程/事务应该从一个SessionFactory获取自己的session实例,才能在新线程中使用事务和延迟加载等功能,否则会曝出no session异常。

    获取session方式

    1.sessionFactory.openSession

    此方法每次都是新开一个session。并且在完成后需要手动close

    2.sessionFactory.getCurrentSession

    当hibernate.cfg.xml中配置了session线程绑定

    <property name="current_session_context_class">thread</property>
    

    getCurrentSession方法创建的Session实例会被绑定到当前线程中,它在提交或回滚操作时会自动关闭,若没有配置线程绑定,此方法报错

    org.hibernate.HibernateException: No CurrentSessionContext configured!

    事务Transaction

    事务隔离级别配置

        <!--
        事务隔离级别
        hibernate.connection.isolation = 4(默认值)
        1—Read uncommitted isolation
        2—Read committed isolation
        4—Repeatable read isolation
        8—Serializable isolation
        -->
        <property name="hibernate.connection.isolation">4</property>
    

    1.如果不手动获取事务,则每次session的curd操作都会自动提交。

    2.session.beginTransaction等同于session.getTransaction().begin;

    3.一个session只允许同时存在一个begin的session.

    4.当transaction.commit后,不能再次begin改事务实例,可以重新beginTransaction.

    基本curd

    save

            Customer customer = new Customer();
            customer.setCustName("测试保存");
            Session session = HibernateUtil.openSession();
            Transaction tx = session.beginTransaction();
            session.save(customer);//此处虽然已经打印出insert语句,但是实际并未插入,事务未提交
            tx.commit();
            session.close();
    

    get

            Session session = HibernateUtil.openSession();
            Transaction tx = session.beginTransaction();
            Customer customer = session.get(Customer.class, 1L);
            System.out.println(customer);
            tx.commit();
            session.close();
    

    get方法只能根据id去查询,所以事实上很少使用

    update

            Session session = HibernateUtil.openSession();
            Transaction tx = session.beginTransaction();
    //        Customer customer = session.get(Customer.class, 1L);
            Customer customer = new Customer();
            customer.setCustId(95L);
            customer.setCustName("啊啊啊");
            session.update(customer);
            tx.commit();
            session.close();
    

    update方法同样需要指定id,如果不存在,则会报错

    delete

            Session session = HibernateUtil.openSession();
            Transaction tx = session.beginTransaction();
            Customer customer = new Customer();
            customer.setCustId(7L);
            session.delete(customer); //虽然delete方法需要entity做参数,但只需要指定entity的id就好
            tx.commit();
            session.close();
    

    delete方法如果找不到此id,同样会报错。

    load

            Session session = HibernateUtil.openSession();
            Transaction tx = session.beginTransaction();
            Customer customer = session.load(Customer.class, 4L); //此处并不会有sql语句打印,说明还未查询数据库
            Thread.sleep(5000);
            System.out.println(customer); //此处才会查询数据库,有打印语句
            tx.commit();
            session.close();
    

    load方法和get方法相似,都是查询一个值
    区别在于
    1.查询时机不一样
    get方法任何时候都是立即加载(立即查询数据库)
    load方法默认是延迟加载,在真正用到对象的非ID字段时才加载
    load可以通过配置立即加载
    2.返回结果不一样
    get返回实体对象
    load如果是延迟加载时,返回的是实体对象的代理

    通过class标签上的load属性来设置是否延迟加载,默认是true

    持久化类规范

    除去一般javaBean要求的,私有属性,get/set方法,无参构造器外,hibernate的持久化类还有如下规则:

    1. 持久化类的属性要尽量使用包装类的类型。因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更清晰而基本数据类型不容易描述。举个例子:

      假设表中有一列员工工资,如果使用double类型,如果这个员工工资忘记录入到系统中,系统会将默认值0存入到数据库,如果这个员工工资被扣完了,也会向系统中存入0.那么这个0就有了多重含义,而如果使用包装类类型就会避免以上情况,如果使用Double类型,忘记录入工资就会存入null,而这个员工工资被扣完了,就会存入0,不会产生歧义。

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

    3. 持久化类尽量不要使用final进行修饰。因为Hibernate中有延迟加载的机制,这个机制中会产生代理对象,Hibernate产生代理对象使用的是字节码的增强技术完成的,其实就是产生了当前类的一个子类对象实现的。如果使用了final修饰持久化类。那么就不能产生子类,从而就不会产生代理对象,那么Hibernate的延迟加载策略(是一种优化手段)就会失效。

    主键生成策略

    先区分自然主键和代理主键

    自然主键

    把具有业务含义的字段作为主键,称之为自然主键。例如在customer表中,如果把name字段作为主键,其前提条件必须是:每一个客户的姓名不允许为null,不允许客户重名,并且不允许修改客户姓名。维护和拓展性很差

    代理主键

    把不具备业务含义的字段作为主键,称之为代理主键。该字段一般取名为“ID”,通常为整数类型,因为整数类型比字符串类型要节省更多的数据库空间

    规则 描述
    increment 用于int,long,short型,由hibernate自增生成id,当没有其他进程往数据库插入时才可用,故集群下不可用。用于代理主键
    identity 由底层数据库本身提供的主键生成id,前提是数据库支持自增长,db2,mysql,sqlserver均支持
    sequence 根据数据库序列生成id,前提是数据库支持序列,mysql不支持
    naive 根据数据库对自动生成符的能力来选择,identity,sequence,hilo。因此具有跨数据库能力,常用
    hilo 使用高低算法生成 shortintlong 类型的 id。需要一张额外的表保存 hi 的值。保存 hi 值的表至少有一条记录(只与第一条记录有关),否则会出现错
    uuid 采用128位的uui算法生成标志符,被编码成32位的16进制字符串。不流行,因为字符串类型比整数类型占更多空间
    assigned 程序必须手动指定id,否则报错,默认就是此策略

    相关文章

      网友评论

        本文标题:2.session基本操作

        本文链接:https://www.haomeiwen.com/subject/sawlvctx.html