一、自动创建表
我们可以在hibernate.cfg.xml上配备属性,让hibernate给我们自动创建表。
<!-- 自动生成表,加载hibernate.cfg.xml文件时,就会根据hbm文件在数据库中创建表,如果已经有此表就删除再创建--> <property name="hbm2ddl.auto">create</property>
<!-- 加载hibernate.cfg.xml文件时,就会根据hbm文件在数据库中更新表(如果没表先创建表),即如果hbm文件中有尚未映射过的字段,就往数据库表中再新增此字段,不会删除原有字段--> <property name="hbm2ddl.auto">update</property>
<!-- 加载hibernate.cfg.xml文件时,就会根据hbm文件在数据库中创建表,在显式关闭sessionFactory时,就drop掉此表--> <property name="hbm2ddl.auto">create-drop</property>
<!-- 每次插入数据之前都会验证数据库中的表结构和hbm文件中是否一致--> <property name="hbm2ddl.auto">validate</property>
在开发测试中,配置哪个都可以,但一般生成完数据库就会立即取消此配置。
二、事务回滚
如果在事务中有异常,我们是希望数据能够回滚的(不改变)。
public static void updateEmployee() { //1.获取一个对话 Session session=MySessionFactory.getSessionFactory().openSession(); //2.创建事务 Transaction ts=null; try { ts=session.beginTransaction(); //3.获取要修改的用户,load方法是通过主键属性获取该对象实例 Employee emp=(Employee) session.load(Employee.class, 1); //4.修改信息 emp.setName("小小名"); //5.抛出异常 int i=9/0; //6提交事务. ts.commit(); } catch (Exception e) { // TODO: handle exception if(ts!=null){ ts.rollback();//事务回滚 } //抛出一个运行时异常 throw new RuntimeException(e.getMessage()); }finally{ //7.关闭会话 if(session!=null&&session.isOpen()){ session.close(); } } }
三、configuration和配置文件
如果把hibernate.cfg.xml移到某个包下,并且更换了名字,就应该这样读取:
Configuration configuration=
new Configuration().configure("com/myz/config/hibernate.myz.xml");
可使用hibernate.properties文件来替代hibernate.cfg.xml文件(不建议)。
四、SessionFactory(会话工厂)接口
①缓存sql语句和某些数据
②在应用程序初始化的时候创建,是一个重量级的类(吃内存),一般用单例模式保证一个应用只需要一个SessionFactory实例。
③如果某个应用访问多个数据库,则需要创建多个会话工厂实例。
④通过SessionFactory接口可以获得Session(会话)实例。
五、Session(会话)接口
①Session一个实例代表与数据库的一次操作(当然一次操作可以是crud的组合)
②session是线程不同步的(不安全),因此要保证在同一线程中使用,可以用getCurrentSession。
③Session可以看作是持久化管理器,它是与持久化操作相关的接口。
④openSession与getCurrentSession。
Session session=sessionFactory.openSession();//获取一个全新的session
Session session=sessionFactory.getCurrentSession();//获取和当前线程绑定的session,在同一个线程中,我们获取的session是同一个session,这样利于事务控制。但是使用getCurrentSession需要在hibernate.cfg.xml下配置:
<!-- 能够使用getCurrentSession --> <property name="current_session_context_class">thread</property>
openSession与getCurrentSession还有如下区别:
1.getCurrentSession创建的session会绑定到当前的线程中,而采用openSession创建的session则不会。
2.getCurrentSession创建的session在commit或rollback时会自动关闭,而采用openSession创建的session必须手动关闭
3.getCurrentSession必须做成事务(查询也必须做成事务提交)
4.getCurrentSession需要在hibernate.cfg.xml文件中加入配置:
<!-- 与线程绑定,如果使用的是本地事务(jdbc事务) --> property name="current_session_context_class">thread</property> <!-- 如果使用的是全局事务(跨数据库的事务) --> property name="current_session_context_class">jta</property>
5.
在SessionFactory启动的时候,hibernate会根据配置创建相应的CurrentSessionContext,在getCurrentSession被调用的时候,实际被执行的是:
CurrentSessionContex.currentSession()。在currentSession()执行时,如果当前session为空,currentSession会调用SessionFactory的openSession。
⑤Session接口的几个重要方法
Session一般以对象的形式来操作,这是几个重要方法
1.保存一个对象(记录)--save方法
2.删除一个对象(记录)--delete方法
3.查询一个对象(记录)--get/load方法
4.修改一个对象(记录)--update方法
Get()和Load()的区别
Get()方法直接返回实体类,如果查不到则返回null,load()会返回一个实体代理对象(当前这个对象可以自动转化为实体对象),但当代理对象被调用时,如果数据不存在,则会抛出异常
Load先到缓存(session缓存/二级缓存)中去查,如果没有则返回一个代理对象(不马上到DB中去找,即不发出sql语句),等后面使用这个代理对象操作的时候,才到DB中查询(发出SQL语句),这就是我们常说的load在默认情况下支持延迟加载(lazy)
Get先到缓存(session/二级缓存)中去查,如果没有就到DB中去查(立即发出SQL语句)。总之,如果你确定DB中有这个对象就用load(),不确定就用get()。这样效率高。
举例(查询一个不存在的记录):
Employee emp=(Employee) session.get(Employee.class, 8); //发出了SQL语句 Employee emp=(Employee) session.load(Employee.class, 8); //没发出SQL语句,没抛出异常 Employee emp=(Employee) session.get(Employee.class, 8); System.out.println(emp); //发出了SQL语句,并打出null Employee emp=(Employee) session.load(Employee.class, 8); System.out.println(emp); //发出了SQL语句,之后抛出运行时异常
从上面我们可以看出,load方法是比较懒一些的,我们不使用查询到的对象时,它便不发出SQL语句去查询到底是否有这个对象。
这是因为load在默认情况下是支持延迟懒加载的(lazy),我们可以在Employee.hbm.xml中关闭延迟加载。
<class name="Employee" table="employee" lazy="false">
此时load方法,查询时也会立即发出SQL语句到数据库中查询。
Employee emp=(Employee) session.get(Employee.class, 8); //发出了SQL语句,之后抛出了异常
六、缓存机制详解
注意:二级缓存需配置使用,否则仅有一级缓存。
Load方法查询:先到session缓存里查,如果没有则去二级缓存里查。如果二级缓存还没有查到,则不再往下查,返回一个代理对象。如果之后需要用到查询得到的对象,则直接发出sql语句去数据库里查,并将查询得到的对象存入二级缓存(根据查询次数的增多可能会被移动到一级缓存)。
举例:
Employee emp=(Employee) session.load(Employee.class, 1); System.out.println(emp.getName()); Employee emp2=(Employee) session.load(Employee.class, 1); System.out.println(emp2.getHireDate()); //以上两句查询语句,仅产生了一条SQL语句,因为第二次是从二级缓存中取得的
Get方法查询:先到session缓存里查,如果没有则去二级缓存里查。如果二级缓存还查不到则立即发出SQL语句到数据库查询,并将查询得到的对象存入二级缓存(根据查询次数的增多可能会被移动到一级缓存)。
举例:
Employee emp=(Employee) session.load(Employee.class, 1); System.out.println(emp.getName()); Employee emp3=(Employee) session.get(Employee.class, 1); System.out.println(emp3.getName()); //以上两句查询语句仅产生了一条SQL语句