hibernate 知识点

一、入门

1、对于持久化类的唯一标识,我们通常不会操作,因此它的setter方法的访问级别应该声明private,当对象被保存的时候,只有hibernate可以分它分配值。

2、持久化类都要求有无参的构造器,hibernate必须使用java反射机制来创建对象。构造器的访问级别可以是private,然后当生成运行时代理的时候则要求使用至少是package级别的访问控制,这样在没有字节码指令的情况下,从持久化类里获取数据会更有效率。

3、generator指定了标识符生成策略,指定native表示根据已配置的数据库自动选择最佳的标识符生成策略。hibernate支持由数据库生成,全局唯一性和应用程序指定这些策略来生成标识符。

4、hibernate映射类型,能把Java数据类型转换到SQL数据类型,反之亦然。如果没有设置type属性,hibernate会试着去确定正确的转换类型和它的映射类型。在某些情况下这个自动检测机制不会产生你所期待或需要的缺省值。比如date属性,hibernate无法知道这个属性应该被映射成: Sql date或timestamp, 还是time字段。

5、session在第一次被做的时候,即第一次调用sessionFactory.getCurrentSession()的时候,生命周期就开始。然后它被hibernate绑定到当前线程。当事务结束的时候,不管是提交还是回滚,hibernate会自动把session从当前线程剥离,并且关闭它。

6、自动脏检查:没有显示的update()或save(),hibernate也会自动检测到集合已经被修改并需要更新回数据库;

7、只要处于持久化状态,就是被绑定到某个hibernate的session(被加载或者保存)上,修改对象属性,hibernate会监视任何修改并在后台隐式写的方式执行sql.

8、清理缓存flushing:在单元操作结束的时候,同步内存状态和数据库的过程。

9、可以在session以外修改不是处在持久化状态下的对象(脱管状态,以前曾经被持久化),然后可以重新持久化,对它所做的任何修改都会被保存到数据库里。

10、inverse映射属性:hibernate没有足够的信息去正确地执行insert和update语句,inverse设置将告诉hibernate忽略关联的这一端,把这端看成是另外一端的一个镜像。在一对多关联中它必须代表多的那端,而在多对多关联中,你可以任意选取一端,因为两端之间没有区别。

二、配置

 

1、Configuration实例被设计成启动期间对象,一旦SessionFactory创建完成,它就会被丢弃。

Configuration cfg = new Configuration()
    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class)
    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
    .setProperty("hibernate.order_updates", "true");

2、SessionFactory:  当所有映射定义被Configuration解析后,应用程序必须获得一个用于构造Session实例的工厂。这个工厂被应用程序的所有线程共享,hibernate允许应用程序创建多个SessionFactory实例,这对使用多个数据库的应用来说很有用。

SessionFactory sessions = cfg.buildSessionFactory();

3、hibernate.order_updates: 强制Hibernate按照被更新数据的主键,为SQL更新排序。这么做将减少在高并发系统中事务的死锁。取值 true | false

4、hibernate.generate_statistics:如果开启, Hibernate将收集有助于性能调节的统计数据.取值 true | false

三、事务和并发

1、Hibernate直接使用JDBC连接和JTA资源,不添加任何附加锁定行为。

2、Hibernate不锁定内存中的对象,应用程序会按照数据库事务的隔离级别规定的那样操作。有了Session,使得hibernate通过标识符查找,和实体查询提供了可重复的读取功能,Session同时也是事务范围内的缓存。

3、除了对自动乐观并发控制提供版本管理,针对行级悲观锁定,hibernate也提供辅助API,它使用了SELECT FOR UPDATE的sql语法。

4、数据库事务应该尽可能的短,降低数据库中的锁争用。 数据库长事务会阻止你的应用程序扩展到高的并发负载。

5、Session 缓存了处于持久化状态的每个对象(Hibernate会监视和检查脏数据)。Session载入过多的数据,占用的内存会一直增长,直到抛出OutOfMemoryException,一个解决办法是调用clear()和evict()来管理Session的缓存,如果需要大批量数据操作,最好考虑使用存储过程。

6、结束session四个阶段:同步session(flush,刷出到磁盘),提交事务,关闭session,处理异常

7、悲观锁定:类LockMode 定义了Hibernate所需的不同的锁定级别。

当hibernate更新或者插入一行记录的时候,锁定级别自动设置为LockMode.WRITE;

当用户显示 的使用数据库支持的sql格式select for update执行sql,锁定级别设置为LockMode.UPGRADE;

当用户显示 的使用数据库支持的sql格式select for update nawait执行sql,锁定级别设置为LockMode.UPGRADE_NOWAIT;

当hibernate在可重得读或者是序列化数据库隔离级别下读取数据的时候,锁定模式自动设置为LockMode.READ,这种模式也可以通过用户显示指定进行设置

LockMode.NONE代表无需锁定。在Transaction结束时,所有的对象都切换到该模式。与session相关联的对象通过调用update()或者是saveOrUpdate()脱离该模式。

8、显示指定LockMode:  调用session.load()时候可指定;调用Session.lock();调用Query.setLockMode().

9、如果在UPGRADE或者UPGRADE_NOWAIT锁定模式下调 用Session.load(),并且要读取的对象尚未被session载入过,那么对象 通过SELECT ... FOR UPDATE这样的SQL语句被载入。如果为一个对象调用 load()方法时,该对象已经在另一个较少限制的锁定模式下被载入了,那 么Hibernate就对该对象调用lock() 方法。

四、批量插入

1、批量插入

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
   
for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size //20,与JDBC批量设置相同
        //flush a batch of inserts and release memory:
        //将本批插入的对象立即写入数据库并释放内存
        session.flush();
        session.clear();
    }
}
   
tx.commit();
session.close();

2、批量更新,使用 scroll() 方法以便充分利用服务器端游标所带来的好处

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
   
ScrollableResults customers = session.getNamedQuery("GetCustomers")
    .setCacheMode(CacheMode.IGNORE)
    .scroll(ScrollMode.FORWARD_ONLY);
int count=0;
while ( customers.next() ) {
    Customer customer = (Customer) customers.get(0);
    customer.updateStuff(...);
    if ( ++count % 20 == 0 ) {
        //flush a batch of updates and release memory:
        session.flush();
        session.clear();
    }
}
   
tx.commit();
session.close();

3、StatelessSession (无状态session)接口

作为选择,Hibernate提供了基于命令的API,可以用detached object的形式把数据以流的方法加入到数据库,或从数据库输出。StatelessSession没有持久化上下文,也不提供多少高层的生命周期语义。特别是,无状态session不实现第一级cache,也不和第二级缓存,或者查询缓存交互。它不实现事务化写,也不实现脏数据检查。用stateless session进行的操作甚至不级联到关联实例。stateless session忽略集合类(Collections)。通过stateless session进行的操作不触发Hibernate的事件模型和拦截器。无状态session对数据的混淆现象免疫,因为它没有第一级缓存。无状态session是低层的抽象,和低层JDBC相当接近。

StatelessSession session = sessionFactory.openStatelessSession();
Transaction tx = session.beginTransaction();
   
ScrollableResults customers = session.getNamedQuery("GetCustomers")
    .scroll(ScrollMode.FORWARD_ONLY);
while ( customers.next() ) {
    Customer customer = (Customer) customers.get(0);
    customer.updateStuff(...);
    session.update(customer);
}
   
tx.commit();
session.close();
注意在上面的例子中,查询返回的Customer实例立即被脱管(detach)。它们与任何持久化上下文都没有关系。StateessSession 接口定义的insert(), update() 和 delete()操作是直接的数据库行级别操作,其结果是立刻执行一条INSERT, UPDATE 或 DELETE 语句。

---学习来源https://hibernate.net.cn/

上一篇:java面试题_简单说明hibernate、Struts2、Spring、springMVC、mybatis的执行流程或者原理_3_Spring


下一篇:HIBERNATE执行SQL的三种方式