22-Java-Hibernate框架(二)
Hibernate的了解、Hibernate的搭建、Hibernate的基本使用流程等内容请阅读21-Java-Hibernate框架(一)
五、Hibernate的Query查询接口(重中之重)
1.HQL语言了解:Hibernate Query Language(HQL),是hibernate的查询语言,和SQL语句结构一样,不同点注意点如下:
(1)HQL是面向对象查询,SQL是面向结构查询
(2)在HQL使用类名和属性名,替代了原有的表名和字段名
(3)在HQL语句中类型名和属性名大小写敏感
(4)如果需要select * 查询所有字段的值,在HQL语句中可以省略select *语句。例如:from User;
(5)如果需要join...on表连接,需要建立关联映射关系使用,不支持on子句
(6)不要使用数据库提供的字符串函数、日期函数和一些特有的函数。一些基础的函数可以使用,例如:max(),min(),sum(),avg(),count()等。
(7)若只查询字体类中某几个字段,返回的结果是泛型,值的集合
2.具体Query常用的相关接口看代码演示
1 package com.hibernatetest.test; 2 3 import java.util.List; 4 5 import org.hibernate.Query; 6 import org.hibernate.Session; 7 import com.hibernatetest.entity.User; 8 import HibernatenateUtils.hibernateUtils; 9 /* 10 * Query接口的常用方法: 11 * 1.setXXX():用于设置HQL语句中问号或变量的值 12 * 2.uniqueResult():得到单个对象(返回Object类型),在已知查询结果中只有一个或零个才能用此函数,若有多个满足条件的结果则报异常 13 * 3.executeUpdate():执行更新和删除语句(返回int型作为操作成功的次数) 14 * 4.分页查询 15 * 5.list():获取结果集(返回List类型) 16 * 6.iterate():获取结果集(返回Iterator类型) 17 * */ 18 public class QueryTest { 19 public static void main(String[] args) { 20 //第一步:Query对象是通过Session获取的,所以先要通过之前写hibernate工具类获取Session对象 21 Session session = hibernateUtils.getSession(); 22 23 //第二步:CreateQuery("HQL语句"):用于创建Query对象。 24 Query query = session.createQuery("from User where uname='zhangsan'"); 25 26 /*查询参数设值setXXX(): (两种方式) 27 * 1.问号设值 28 * Query query = session.createQuery("from User where uid between ? and ?"); 29 * query.setInteger(0,5);//给第一个问号处赋值5 30 * query.setInteger(1,10);//给第一个问号处赋值10 31 * 32 * 2.变量设值 33 * Query query = session.createQuery("from User where uname=:name"); 34 * query.setString(name,"zhangsan");//给name变量赋值 35 * 36 * 3.模糊查询 37 * Query query = session.createQuery("from User where uname likt %?%");错!!!!! 38 * Query query = session.createQuery("from User where uname like ?");对!!!! 39 * query.setString(0,"%" +"zhang"+ "%"); 40 * 41 * 4.分页查询 42 * Query query = session.createQuery("from User where uname='zhangsan'"); 43 * query.setFirstResult(0);从满足条件的数据中的第一条数据开始抓取 44 * query.setMaxResult(2);从满足条件的数据中只抓取前两条数据 45 * 46 * 5.获取单个对象 47 * Query query = session.createQuery("select count(*) from User where uname='zhangsan'"); 48 * Object object = query.uniqueResult(); 49 * 50 * 6.构造查询 51 * Query query = session.createQuery("select new User(5,"zhangsan") from User where uname='zhangsan'"); 52 * Object object = query.uniqueResult(); 53 * */ 54 55 /*数据库更新和删除操作executeUpdate() 56 * 1.删除 57 * Query query = session.createQuery("delete from User where uid in(1,6)");//删除id为1和6的数据,即使数据库中没有符合条件的数据也不会报错 58 * int execute = query.executeUpdate();//返回成功操作的次数 59 * */ 60 61 //第三步:Query获取结果集 62 //1.list()获取 63 List<?> list = query.list(); 64 for(Object u:list){ 65 User user = (User)u; 66 System.out.println(user); 67 } 68 /*2.iterate()获取 69 * Iterator<?> iterator = query.iterate(); 70 * while(iterator.hasNext()){ 71 * User user = (User)iterator.next(); 72 * System.out.println(user); 73 * } 74 * */ 75 /*面试要考:list()和iterate()获取结果集的区别: 76 * list():一次把所有数据从数据库中取出来 77 * iterate():先从数据库中查询满足条件的id,如果缓存中包含全部要查询的id的数据,就无需再查数据库,直接从缓存中取数据,否则,根据id从数据库中取 78 * */ 79 80 //第四步:记得将Session关闭 81 session.close(); 82 } 83 }
六、Hibernate的三个状态
对象(持久化类的实例)处于session对象的管理中才能与数据库发生联系。在Hibernate框架应用中,我们依据对象对象与session对象的关系不同情况,
把对象的状态分为人的三种:瞬时状态、游离状态、持久状态。
Transient(瞬时状态|临时状态):在new之后,save()之前,数据库没有应用的数据
如果对象未与session对象关联过,我们称该对象处于瞬时状态
Persistent(持久状态):在save()之后,在session关闭之前,数据库有相对应的数据
如果对象与session关联起来了,且该对象对应到数据库记录,则称该对象处于持久状态
三状态结构图:
三状态转换关系:
1.瞬时状态转换为持久状态:
使用session的save()或saveOrUpdate()方法保存对象后,该对象的状态由瞬时状态转换为持久状态
使用session的get()或load()方法获取对象后,该对象的状态为持久状态
2.持久状态转换为瞬时状态
执行session对象的delete()方法后,对象由原来的持久状态变为瞬时状态,因此该对象没有与任何的数据库数据有关联
3.持久状态变为游离状态
执行session对象的evict()、clear()、close()方法,对象由原来的持久状态变为游离状态。
4.游离状态变为持久状态
重新获取对象session对象,执行session对象的update()或saveOrUpdate方法,由游离状态转换为持久状态,该对象再次与session关联
5.游离状态转换为瞬时状态
执行session的delete()方法,对象有游离状态变为瞬时状态
对瞬时状态或游离状态的对象不再被其他对象引用时,会被Java虚拟机按照垃圾回收机制处理
七、Hibernate根据实体自动构建生成表
第一步:在hibernate.cfg.xml中添加<property name="hibernate.hbm2ddl.auto">update</property>,设置自动生成表
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 5 6 <hibernate-configuration> 7 8 <session-factory> 9 <!--hibernate 方言 区分身份 --> 10 <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 11 <!-- 数据库连接信息 --> 12 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 13 <property name="connection.url">jdbc:mysql://127.0.0.1:3306/hibernatetest</property> 14 <property name="connection.username">root</property> 15 <property name="connection.password">root</property> 16 17 <!-- hibernate自动生成表 update:如果数据库不存在这张表自动创建一张表,如果存在不创建--> 18 <property name="hibernate.hbm2ddl.auto">update</property> 19 <!-- hibernate在控制台显示SQL语句 --> 20 <property name="show_sql">true</property> 21 <!-- hibernate格式化SQL,控制台看起来更整齐 --> 22 <property name="format_sql">true</property> 23 <!-- 设置自动提交 --> 24 <property name="connection.autocommit">true</property> 25 26 <!-- <property name="connection.characterEncoding">UTF-8</property> --> 27 <!--加载hibernate映射 --> 28 <mapping resource="com/hibernatetest/entity/Entity.hbm.xml" /> 29 </session-factory> 30 31 </hibernate-configuration>
第二步:编写实体类
第三步:配置映射文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping> 5 <!-- name:对应的实体类的权限定名称,table:对应数据库表名称 --> 6 <class name="com.hibernatetest.entity.Entity" table="hibernateEntity"> 7 <!-- id标签用于配置主键属性 8 name属性:对应实体类中属性名称 9 type属性:可以省略,如果省略默认实体类中属性的对应类型 10 --> 11 <id name="userid" type="java.lang.Integer"> 12 <!-- column用于设置对应数据库表中字段名。不写column标签,数据库中的字段名则和Entity类中的属性名一致 13 name:数据库表中的字段名 14 length:设置字段长度 15 --> 16 <column name="userid"></column> 17 <!-- generator用于设置主键生成策略 18 native:数据库本地生成策略,适用于多个数据库 19 sequence:序列(Oracle使用) 20 imcrement:主要mysql数据库使用,适用于所有数据库,先查询出最大的id,在此基础上+1,有可能出现并发的问题 21 uuid:生成32位,不会重复的主键,可以达到真正的跨数据库 22 foreign:通常在一对一关联的时候使用 23 自增长:identity,适用于mysql,db2,sql server。 24 --> 25 <generator class="native"></generator> 26 </id> 27 28 <!-- property标签用于配置其他属性 29 name:对应实体类中属性名称 30 type:可以省略,如果省略默认实体类中属性的对应类型 31 --> 32 <property name="username" type="java.lang.String"> 33 <column name="username" length="32"></column> 34 </property> 35 <property name="password" type="java.lang.String" > 36 <column name="password" length="32"></column> 37 </property> 38 39 </class> 40 41 </hibernate-mapping>
第四步:编写测试类测试
控制台显示hibernate在数据库没找到hibernateEntity表
于是它便会在数据库自动生成一张表
八、Hibernate的关联映射
实体与实体之间有一对一、多对一、多对多的关系,Hibernate也因此需要对表与表之间进行关联映射配置。
假设:有一张表为Entity,表中有userid,username,password三个字段,另一张表Grade,表中有gradeid,userid,grade。
我现在通过userid查询对应另一张表中的grade(此处可以理解为多对一)。步骤如下:
第一步:搭建Hibernate,配置hibernate.cfg.xml,此处由于我们有两张表,所以需要加载两个映射文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 5 6 <hibernate-configuration> 7 8 <session-factory> 9 <!--hibernate 方言 区分身份 --> 10 <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 11 <!-- 数据库连接信息 --> 12 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 13 <property name="connection.url">jdbc:mysql://127.0.0.1:3306/hibernatetest</property> 14 <property name="connection.username">root</property> 15 <property name="connection.password">root</property> 16 17 <!-- hibernate自动生成表 update:如果数据库不存在这张表自动创建一张表,如果存在不创建--> 18 <property name="hibernate.hbm2ddl.auto">update</property> 19 <!-- hibernate在控制台显示SQL语句 --> 20 <property name="show_sql">true</property> 21 <!-- hibernate格式化SQL,控制台看起来更整齐 --> 22 <property name="format_sql">true</property> 23 <!-- 设置自动提交 --> 24 <property name="connection.autocommit">true</property> 25 26 <!-- <property name="connection.characterEncoding">UTF-8</property> --> 27 28 <!--加载hibernate映射文件 --> 29 <mapping resource="com/hibernatetest/entity/Entity.hbm.xml" /> 30 <mapping resource="com/hibernate/grade/Grade.hbm.xml" /> 31 </session-factory> 32 33 </hibernate-configuration>
第二步:配置两张表对应的映射文件
Entity.hbm.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping> 5 <!-- name:对应的实体类的权限定名称,table:对应数据库表名称 --> 6 <class name="com.hibernatetest.entity.Entity" table="hibernateEntity"> 7 <!-- id标签用于配置主键属性 8 name属性:对应实体类中属性名称 9 type属性:可以省略,如果省略默认实体类中属性的对应类型 10 --> 11 <id name="userid" type="java.lang.Integer"> 12 <!-- column用于设置对应数据库表中字段名。不写column标签,数据库中的字段名则和Entity类中的属性名一致 13 name:数据库表中的字段名 14 length:设置字段长度 15 --> 16 <column name="userid"></column> 17 <!-- generator用于设置主键生成策略 18 native:数据库本地生成策略,适用于多个数据库 19 sequence:序列(Oracle使用) 20 imcrement:主要mysql数据库使用,适用于所有数据库,先查询出最大的id,在此基础上+1,有可能出现并发的问题 21 uuid:生成32位,不会重复的主键,可以达到真正的跨数据库 22 foreign:通常在一对一关联的时候使用 23 自增长:identity,适用于mysql,db2,sql server。 24 --> 25 <generator class="native"></generator> 26 </id> 27 28 <!-- property标签用于配置其他属性 29 name:对应实体类中属性名称 30 type:可以省略,如果省略默认实体类中属性的对应类型 31 --> 32 <property name="username" type="java.lang.String"> 33 <column name="username" length="32"></column> 34 </property> 35 <property name="password" type="java.lang.String" > 36 <column name="password" length="32"></column> 37 </property> 38 </class> 39 40 </hibernate-mapping>
Grade.hbm.xml:(此处需要加入对grade表的多对一的映射关系)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping> 5 <!-- name:对应的实体类的权限定名称,table:对应数据库表名称 --> 6 <class name="com.hibernate.grade.Grade" table="hibernateGrade"> 7 <!-- id标签用于配置主键属性 8 name属性:对应实体类中属性名称 9 type属性:可以省略,如果省略默认实体类中属性的对应类型 10 --> 11 <id name="gradeid" type="java.lang.Integer"> 12 <!-- column用于设置对应数据库表中字段名。不写column标签,数据库中的字段名则和Entity类中的属性名一致 13 name:数据库表中的字段名 14 length:设置字段长度 15 --> 16 <column name="gradeid"></column> 17 <!-- generator用于设置主键生成策略 18 native:数据库本地生成策略,适用于多个数据库 19 sequence:序列(Oracle使用) 20 imcrement:主要mysql数据库使用,适用于所有数据库,先查询出最大的id,在此基础上+1,有可能出现并发的问题 21 uuid:生成32位,不会重复的主键,可以达到真正的跨数据库 22 foreign:通常在一对一关联的时候使用 23 自增长:identity,适用于mysql,db2,sql server。 24 --> 25 <generator class="native"></generator> 26 </id> 27 28 <!-- property标签用于配置其他属性 29 name:对应实体类中属性名称 30 type:可以省略,如果省略默认实体类中属性的对应类型 31 --> 32 33 <!-- 多对一映射关系 --> 34 <!-- name:当前Grade类的Entity属性 35 column:Grade类的外键 36 fetch:有join和select.默认为select 37 select:查了当前表之后,再查外键所在的那张表 38 join:在多对一将原本需要两条sql语句以left outer join(左外连接)方式用一条语句解决 39 cascade:级联操作关联表:慎用 40 save-update:在添加或操作的时候使用级联操作关联表 41 delete:在删除的时候使用级联操作关联表 42 all:在所有操作的时候使用级联操作关联表 43 none:任何时候都不使用 44 --> 45 <many-to-one name="entity" column="userid" fetch="join"></many-to-one> 46 47 <property name="grade" type="java.lang.Double" > 48 <column name="grade"></column> 49 </property> 50 </class> 51 52 </hibernate-mapping>
第三步:编写两张表对应的实体类
Entity类:
1 package com.hibernatetest.entity; 2 3 public class Entity { 4 private Integer userid; 5 private String username; 6 private String password; 7 public Entity() { 8 super(); 9 // TODO Auto-generated constructor stub 10 } 11 public Entity(Integer userid, String username, String password) { 12 super(); 13 this.userid = userid; 14 this.username = username; 15 this.password = password; 16 } 17 public Integer getUserid() { 18 return userid; 19 } 20 public void setUserid(Integer userid) { 21 this.userid = userid; 22 } 23 public String getUsername() { 24 return username; 25 } 26 public void setUsername(String username) { 27 this.username = username; 28 } 29 public String getPassword() { 30 return password; 31 } 32 public void setPassword(String password) { 33 this.password = password; 34 } 35 @Override 36 public int hashCode() { 37 final int prime = 31; 38 int result = 1; 39 result = prime * result 40 + ((password == null) ? 0 : password.hashCode()); 41 result = prime * result + ((userid == null) ? 0 : userid.hashCode()); 42 result = prime * result 43 + ((username == null) ? 0 : username.hashCode()); 44 return result; 45 } 46 @Override 47 public boolean equals(Object obj) { 48 if (this == obj) 49 return true; 50 if (obj == null) 51 return false; 52 if (getClass() != obj.getClass()) 53 return false; 54 Entity other = (Entity) obj; 55 if (password == null) { 56 if (other.password != null) 57 return false; 58 } else if (!password.equals(other.password)) 59 return false; 60 if (userid == null) { 61 if (other.userid != null) 62 return false; 63 } else if (!userid.equals(other.userid)) 64 return false; 65 if (username == null) { 66 if (other.username != null) 67 return false; 68 } else if (!username.equals(other.username)) 69 return false; 70 return true; 71 } 72 @Override 73 public String toString() { 74 return "Entity [userid=" + userid + ", username=" + username 75 + ", password=" + password + "]"; 76 } 77 78 }
Grade类:
1 package com.hibernate.grade; 2 3 import com.hibernatetest.entity.Entity; 4 5 public class Grade { 6 private Integer gradeid; 7 private Entity entity; 8 private Double grade; 9 public Grade() { 10 super(); 11 // TODO Auto-generated constructor stub 12 } 13 public Grade(Integer gradeid, Entity entity, Double grade) { 14 super(); 15 this.gradeid = gradeid; 16 this.entity = entity; 17 this.grade = grade; 18 } 19 public Integer getGradeid() { 20 return gradeid; 21 } 22 public void setGradeid(Integer gradeid) { 23 this.gradeid = gradeid; 24 } 25 public Entity getEntity() { 26 return entity; 27 } 28 public void setEntity(Entity entity) { 29 this.entity = entity; 30 } 31 public Double getGrade() { 32 return grade; 33 } 34 public void setGrade(Double grade) { 35 this.grade = grade; 36 } 37 @Override 38 public int hashCode() { 39 final int prime = 31; 40 int result = 1; 41 result = prime * result + ((entity == null) ? 0 : entity.hashCode()); 42 result = prime * result + ((grade == null) ? 0 : grade.hashCode()); 43 result = prime * result + ((gradeid == null) ? 0 : gradeid.hashCode()); 44 return result; 45 } 46 @Override 47 public boolean equals(Object obj) { 48 if (this == obj) 49 return true; 50 if (obj == null) 51 return false; 52 if (getClass() != obj.getClass()) 53 return false; 54 Grade other = (Grade) obj; 55 if (entity == null) { 56 if (other.entity != null) 57 return false; 58 } else if (!entity.equals(other.entity)) 59 return false; 60 if (grade == null) { 61 if (other.grade != null) 62 return false; 63 } else if (!grade.equals(other.grade)) 64 return false; 65 if (gradeid == null) { 66 if (other.gradeid != null) 67 return false; 68 } else if (!gradeid.equals(other.gradeid)) 69 return false; 70 return true; 71 } 72 @Override 73 public String toString() { 74 return "Grade [gradeid=" + gradeid + ", entity=" + entity + ", grade=" 75 + grade + "]"; 76 } 77 78 }
第四步:编写HibernateUtils工具类和测试类
测试类:
1 package Hibernatetest; 4 5 import org.hibernate.Query; 6 import org.hibernate.Session; 7 import org.hibernate.Transaction; 8 9 import com.hibernate.grade.Grade; 10 import com.hibernatetest.entity.Entity; 11 12 import HibernatenateUtils.hibernateUtils; 13 14 public class annotationtest { 15 16 public void test(){ 17 18 } 19 public static void main(String[] args) { 20 Session session = hibernateUtils.getSession(); 21 22 //先制造两条记录在数据库中 23 Transaction transaction = session.beginTransaction(); 24 Entity user1 = new Entity(null,"zhangsan","1111"); 25 Grade grade1 = new Grade(null,user1,Double.valueOf(85)); 26 session.save(user1); 27 session.save(grade1); 28 transaction.commit(); 29 30 transaction = session.beginTransaction(); 31 Entity user2 = new Entity(null,"lisi","2222"); 32 Grade grade2 = new Grade(null,user2,Double.valueOf(100)); 33 session.save(user2); 34 session.save(grade2); 35 transaction.commit(); 36 37 //查询测试 38 Grade grade = session.get(Grade.class,1); 39 System.out.println(grade); 40 session.close(); 41 } 42 }
运行结果: