初识Hibernate
来源:互联网 发布:体彩开奖网络视频直播 编辑:程序博客网 时间:2024/06/06 01:27
Hibernate
JDBC和Hibernate的异同点
- 相同点
- 两者都是java数据库操作中间件
- 两者对于数据库进行直接操作对象都不是线程安全的,需要及时的关闭
- 两者都可以对数据库的更新操作进行显式的事务处理
- 不同点
- 使用的语言不同,JDBC使用的是Sql语言,而Hibernate是HQL语言
- 操作的对象不一样,JDBC操作的是数据,将数据直接传送到数据库中;而Hibernate操作的是持久化对象,由底层的持久化对象的数据更新到数据库中。
- 数据状态不同:JDBC操作的数据是“瞬时的”,变量的值没法与数据库中的值保持一致;而Hibernate操作的数据是可持久化的,持久化对象的数据和数据库中的数据是保持一致的。
- 对于事务的控制不同,JDBC默认事务是开启的,数据插入修改删除会自动提交;而Hibernate是默认关闭的,在进行插入,修改或者删除时,需要开启事务。
ORM 对象关系映射
ORM(对象-关系映射):完成对象数据到关系型数据映射的机制称为对象-关系映射,简称ORM。
Hibernate中的三种状态
区别三种状态的一个方法是看是否拥有自增的主键,内存中是否有该对象,缓存中是否有该对象,数据库中是否有该对象的信息。
1. 瞬时态(transient)
- ==介绍==:数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器回收,一般是new出来且与session没有关联的对象。
- 对象没有自增主键
- 对象存在内存当中,session缓存和数据库都没有对象信息
2. 持久态(persistent)
- ==介绍==:数据库中有数据与之对应,当前与session有关联,并且相关联的session没有关闭,事务没有提交;持久对象状态发生改变,在事务提交时会影响到数据库(hibernate能检测到)。
- 内存,session缓存和数据库都有对象的信息
- 拥有自增主键
3. 游离态(detached)
- ==介绍==:数据库中有数据与之对应,但当前没有session与之关联;托管对象状态发生改变,hibernate不能检测到。
- 内存当中存在存在对象,session缓存中没有,数据库中有对象记录
- 拥有自增主键
Hibernate中三个重要的类
Configuration
Configuration类负责管理Hibernate的配置信息,它包括如下内容:Hibernate运行的底层信息:数据库的URL、用户名、密码、JDBC驱动类、数据库Dialect(方言),数据库连接池等。
Hibernate映射文件(*.hbm.xml)
从属性文件读取配置:hibernate.properties调用代码:Configuration cfg=new Configuration();从XML文件读取配置:hibernate.cfg.xml调用代码: Configuration cfg=new Configuration().configure();
SessionFactory
应用程序从SessionFactory里获得Session。它在多个应用线程间进行共享。通常情况下,整个应用只有唯一的一个SessionFactory——例如在应用初始化时被创建。然而,如果你使用Hibernate访问多个数据库,你需要对每一个数据库使用一个SessionFactory。
SessionFactory缓存了生成的SQL语句和Hibernate在运行时使用的映射元数据。
SessionFactory factory = cfg.buildSessionFactory();
Session
- session不是线程安全的
- session也称作是持久化管理器
- session通过sessionfactory创建,在所有的工作完成了之后,需要关闭
关于session的几个重要的方法
- save 保存数据。
- delete,删除对象
- update,更新对象,如果数据库中没有记录,会出现异常。
- get,根据ID查,会立刻访问数据库。
- Load,根据ID查,(返回的是代理,不会立即访问数据库)。
- saveOrUpdate, merge(根据ID和version的值来确定是save或update),调用merge你的对象还是脱管的。
- lock(把对象变成持久对象,但不会同步对象的状态)。
session对象的获取
- 通过 new Configuration().configure().buildSessionFactory(),得到SessionFactory对象,然后调用这个对象的openSession方法就可以获取session了
SessionFactory factory = new Configuration().configure().buildSessionFactory();Session session = factory.openSession();
- 通过HibernateSessionFactory.getSession()可以获取到Session对象
Session session = HibernateSessionFactory.getSession();...HibernateSessionFactory.closeSession(); //关闭会话
主键自增native在mysql和oracle中的差异
generator中class如果指定了native,则会根据数据库自动匹配合适的方式来对主键自增
- 因为在mysql中,支持auto_increment,所以generator中class的native会自动递增。
<class name="com.etc.domain.Student" table="STUDENT" schema="SCOTT"> <id name="sid" type="java.lang.Short"> <column name="SID" precision="4" scale="0" /> <generator class="native" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" length="10" /> </property></class>
- 在oracle中,使用的是序列来进行主键的自增,所以当使用了native时,需要在generator中指定你的序列,否则hibernate会自动去寻找hibernate_seq这个序列对象。
<class name="com.etc.domain.Student" table="STUDENT" schema="SCOTT"> <id name="sid" type="java.lang.Short"> <column name="SID" precision="4" scale="0" /> <generator class="native"> <param name="sequence">HSTUD_SEQ</param> //指定了oracle中的序列 </generator> </id> <property name="name" type="java.lang.String"> <column name="NAME" length="10" /> </property></class>
手动添加主键,那么就是assigned
<class name="com.etc.domain.Student" table="STUDENT" schema="SCOTT"> <id name="sid" type="java.lang.Integer"> //这里要记得修改type,否则会一直报类型错误 <column name="SID" precision="4" scale="0" /> <generator class="assigned"></generator> </id> <property name="name" type="java.lang.String"> <column name="NAME" length="10" /> </property></class>
HQL语句
HQL语句操作的是对象,这点一定要记住,而不是数据库中的字段名。
如果Hibernate查询的不是一个完整的对象,而是某几个字段,那么得到的list是List
// 查询不完整的对象 单个属性String hql = "select name from Emp where id<8";List<Object> list = session.createQuery(hql).list();for ( Object o : list) { System.out.println(o);}// 查询多个属性String hql = "select id,name from Emp where id<8";List<Object[]> list = session.createQuery(hql).list();for ( Object[] obj : list) { for ( Object o : obj ) { System.out.println(o); }}// 使用内连接来进行多表的关联查询String hql = "from Emp as e inner join e.dept as d where d.deptName='技术部' ";List<Object[]> list = session.createQuery(hql).list();for ( Object[] obj : list ) { for ( Object o : obj) { System.out.println(o); }}// 隐蔽的关联对象,在使用的时候才执行查询(懒加载) 推荐使用String hql = "from Emp where dept.deptno=10 ";List<Emp> list = session.createQuery(hql).list();for ( Emp e : list ) { System.out.println(e); System.out.println(e.getDept().getDeptName()); //这个时候查找部门}
Hibernate中的增删改查
示例
- 插入
session.beginTransaction(); Student s = new Student("张三", 44); session.save(s); session.getTransaction().commit(); session.close();
- 修改
Student s = new Student("王小二", 77, new Date()); s.setSid(3); session.beginTransaction(); session.saveOrUpdate(s); session.getTransaction().commit();
- 删除
Student s = new Student(); s.setSid(1); //只需要设置主键就可以了 session.beginTransaction(); session.delete(s); session.getTransaction().commit(); //虽然可以这么做,但一般会先查找有没有,再删除 Student s = (Student) session.get(Student.class, 99); if ( s != null) { session.delete(s); }
- 查找单个对象
public static void getById(Session session){ Student s = (Student) session.get(Student.class, 3); //这里比如固定查找id3的学生 System.out.println(s);}
- 查找一系列对象
public static void queryAllStudent(Session session){ Query query = session.createQuery("from Student"); //需要用到HQL语句 List<Student> list = query.list(); for ( Student s : list ){ System.out.println(s); }}
动态查询
hibernate 的动态查询和JDBC中的十分类似,需要设置参数可以使用?来代替
// 使用类似JDBC的方式来进行,?是从0开始,而不是1String hql = "from Emp where id=?";Query query = session.createQuery(hql);query.setInteger(0, 3);List<Emp> list = query.list();for ( Emp e : list ) { System.out.println(e);}// 也可以去使用别名String hql = "from Emp where id=:eid";Query query = session.createQuery(hql);query.setParameter("eid", 3);List<Emp> list = query.list();for ( Emp e : list ) { System.out.println(e);}// 也可以使用关联对象来进行查询String hql = "from Emp where dept=:d";Query query = session.createQuery(hql);Dept d = new Dept();d.setDeptno(40);query.setEntity("d", d);List<Emp> list = query.list();for ( Emp e : list ) { System.out.println(e);}
命名查询
hibernate支持在配置文件中写如HQL语句或者SQL语句,写的位置是你要查询的那个对象的hbm.xml中。如果是HQL的话,节点是query,如果是SQL语句的话,就是sql-query。
配置在class外.
<!-- HQL语句 --><query name="myhql_for_userinfo"> <![CDATA[select id,name from Emp where id=:eid]]> <!-- 这里要注意的是必须要加上!CDATA,否则会按照xml来解析,那么一些符号就会出问题了 --></query><!-- SQL语句 --><sql-query name="myhql_for_userinfo1"> <![CDATA[select uname,uid from Userinfo where uname=:name]]></sql-query>
以下是HQL的查询简单例子
Query query = session.getNamedQuery("myhql_for_userinfo");query.setParameter("eid", 3); // 设置配置文件中的动态参数List<Object[]> list = query.list();for ( Object[] e : list ){ for (Object o : e) { System.out.println(o); }}
以下是SQL的查询 和JDBC中的sql一样
Query query = session.getNamedQuery("myhql_for_userinfo1");query.setParameter("d", 40);List<Object[]> list = query.list();for(Object[] o : list) { for (Object e : o) { System.out.println(e); }}
Criteria查询
QBC(Query By Criteria) 查询方式,QBC更是面向对象的查询方式,不用编写任何的语句,仅仅是对于Restrictions,Order,Projections三个对象来进行设置属性就可以了。
特点
- 完全面向对象,无需任何的语句。
- 支持“链式风格”。
- 支持从离线查询作转换
一般的使用步骤是这样的
首先需要活得Criteria对象,通过session.createCriteria()方法
使用Restrictions设置查询条件,使用Order设置排序条件,Projections来进行统计和分组
- Restrictions类常用的方法(省略了Restrictions前缀)
- Order常用方法
- Projections类(省略了Projections前缀)
例子
Criteria cri = session.createCriteria(Emp.class);cri.add(Restrictions.ge("id", 9)); // 选取id大于9的记录cri.addOrder(Order.desc("id")); //按照id属性进行降序排列cri.add(Restrictions.like("name", "%王")); //找出名字中以王结尾的名List<Emp> list = cri.list();for (Emp e : list) { System.out.println(e);}
如果要使用关联的对象来进行查询也是可以的,方法是创建一个子Criteria,然后按照普通的Criteria设置属性,然后查找的时候,用父Criteria来进行查找。
一个简单的例子如下
Criteria cri = session.createCriteria(Emp.class);Criteria subCri = cri.createCriteria("dept");subCri.add(Restrictions.eq("deptno", 40));List<Emp> list = cri.list();for (Emp e : list) { System.out.println(e);}
Criteria的一个特点之一就是支持离线查询,在没有连接的时候,先都设置好查询条件,当获取连接后,就可以查询得到结果。
DetachedCriteria dc = DetachedCriteria.forClass(Emp.class);dc.add(Restrictions.gt("id", 3));Criteria cri = dc.getExecutableCriteria(session);List<Emp> list = cri.list();for(Emp e : list){ System.out.println(e);}
分页
Hibernate中的分页使用起来十分简单,与具体的数据库无关
Query query = session.createQuery("from Emp");query.setFirstResult(2); // 设置从第几条开始 0 1 2query.setMaxResults(5);List<Emp> list = query.list();for(Emp e : list ) { System.out.println(e);}
Hibernate中的懒加载
在节点上设置的lazy会对load起作用,属于类级别的加载;
在节点上,同样允许使用懒加载,会在访问set中的元素时,执行查询。对于get/load都是有效的。
懒加载中涉及到主控对象和关联对象,简单说,你要先通过查找谁,然后再去找谁。前一个就是主控对象,后一个是关联对象。关闭懒加载会同时查找二者,而懒加载只会先找出主控对象。
Fetch=”select” 表示采用SQL的查询方式,当属性值为join时,会采用1条关联语句,实现两张表的查询。此时即便是设置了懒加载,是不起作用的。
必需同时满足下面三个条件时才能实现懒加载
1. lazy!=false 2)constrained=true 3)fetch=select(主表不能有constrained=true,所以主表没有懒加载)
1. 3.one-to-many (元素)懒加载:1)lazy!=false 2)fetch=select
1. 4.many-to-one (元素) :1)lazy!=false 2)fetch=select
1. 5.many-to-many (元素) :1)lazy!=false 2)fetch=select
Hibernate中的关联
one-to-one
ont-to-many
一对多的情况十分常见,例如一个学生有多门课程,一个公司有多个部门,one-to-many常常和many-to-one一起用的,因为这仅仅是角度的问题。
在myEclipse中,选中一对多的两张表,然后反向工程,自动去生成配置文件,大致的内容如下
// 在学生当中有一个成绩set对象<set name="scores" inverse="true"> <key> <column name="sid" not-null="true" /> </key> <one-to-many class="com.etc.domain.Score" /></set>// 在成绩当中,有一个学生对象<many-to-one name="student" class="com.etc.domain.Student" fetch="select"> <column name="sid" not-null="true" /></many-to-one>
many-to-many
多对多的关系按照中间的联系分为2中情况
- 联系存在额外的数据,称之为不纯洁的的多对多
- 联系不存在额外的数据,称之为纯洁的的多对多
不纯洁的多对多
不纯洁的多对多在myEclipse中的反向工程中,要选定三张表(A,B,以及AB联系表)建立他们的实体。
在使用的时候和一般的一对多关联没有太大的区别,这里主要贴出三个配置文件。两个使用的是一对多的关系,联系表使用的是多对多的关系。
//学生hbm<set name="scores" inverse="true"> <key> <column name="cid" not-null="true" /> </key> <one-to-many class="com.etc.domain.Score" /></set>//课程的hbm<set name="scores" inverse="true"> <key> <column name="sid" not-null="true" /> </key> <one-to-many class="com.etc.domain.Score" /></set>//成绩hbm<many-to-one name="student" class="com.etc.domain.Student" fetch="select"> <column name="sid" not-null="true" /></many-to-one><many-to-one name="course" class="com.etc.domain.Course" fetch="select"> <column name="cid" not-null="true" /></many-to-one>
纯洁的多对多
纯洁的多对多相比于不纯洁的多对多要稍微麻烦一点。
1. 在反向工程中不选择AB联系表
1. 在实体A中,保留Set Bs对象,删除联系表对象。
1. 同理,在实体B中,保留Set As,删除联系表对象。
1. toString() 方法最好不要加入Set集合,可能会有问题
1. 修改A.hbm.xml和B.hbm.xml中的set节点,参考如下
<set name="students" inverse="true" table="stud_role_ralation" lazy="false"> <key> <column name="rid" not-null="true" /> </key> <many-to-many class="com.etc.domain.Student" column="sid"/></set>
name 是实体中拥有的set对象,table是联系表,lazy默认是true,false表示不懒加载。key是本类的主键,节点要从原来的one-to-many
修改为many-to-many
,class为与哪一个类是多对多的关系,column表示关联的字段。
表结构不存在 hbm2ddl.auto
当数据库中不存在表,而我们又需要写入时,可以使用hbm2ddl.auto,这个需要在hibernate.cfg.xml中进行配置。
<property name="hbm2ddl.auto">update</property>
对应实体类的hbm.xml配置文件和普通的POJO一样,这里给一个最基本的。
<class name="com.etc.domain.Animal" table="animal" catalog="mytest" > <id name="aid" type="java.lang.Integer"> <column name="rid" /> <generator class="native" /> </id> <property name="name" type="java.lang.String"> <column name="name" length="20" not-null="true" /> </property></class>
级联增删改
- 增改
在many-to-one的对象中的many-to-one节点,设置cascade=”save-update”属性
<many-to-one name="dept" class="com.etc.domain.Dept" fetch="select" cascade="save-update"> <column name="deptNo" precision="2" scale="0" /></many-to-one>
- 删除
多的一端,hbm.xml的many-to-one里面设置级联为删除,则在删除的时候,会尝试去删除主表中的信息,这个时候如果从表里有其他数据与主表关联,则会删除失败。
以员工和部门为例
<many-to-one name="dept" class="com.etc.domain.Dept" fetch="select" cascade="delete"> <column name="deptNo" precision="2" scale="0" /></many-to-one>
在部门的hbm.xml中的配置
<set name="emps" inverse="true" cascade="delete"> <key> <column name="deptNo" /> </key> <one-to-many class="com.etc.domain.Emp" /></set>
- 级联有一点需要注意的是,如果新增的属性是有自增或者序列的,那么在创建对象的时候,就不要设置属性,会出现异常。
- 关联表的增删改操作,往往需要用到级联属性。
缓存
Hibernate中的缓存分为一级缓存,二级缓存和查询缓存。
- 初识Hibernate
- 初识hibernate
- 初识Hibernate
- hibernate初识
- 初识Hibernate
- Hibernate初识
- 初识hibernate
- 初识Hibernate
- Hibernate初识
- hibernate初识
- hibernate初识
- 初识Hibernate
- Hibernate----初识
- 初识Hibernate
- 初识Hibernate
- 初识Hibernate
- 初识Hibernate
- 初识hibernate
- ViewFs----HDFS跨集群数据合并方案之ViewFileSystem
- android监听虚拟按键的显示与隐藏
- 0068 terra vista 4.0安装包及破解教程
- mac 上自定义脚本命令
- Your password has expired. To log in you must change it using a client that supports expired passwo
- 初识Hibernate
- 解决ROSPY没有spinOnce
- 面试------倒置字符串
- j2ee项目为什么要运行在中间下
- TensorFlow 1.0正式发布
- 神奇的IB_DESIGNABLE和IBInspectable
- mac使用快捷键
- Ubuntu 16.04安装Oracle 11g 简解
- test