`
oham_一1一
  • 浏览: 51617 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Hibernate使用——数据查询示例

阅读更多

Criteria Query的使用

 

Criteria 查询表达式

Criteria 本身只是一个查询容器,具体的查询条件需要通过Criteria.add方法加到Criteria实例中。

示例1:

Criteria criteria = session.createCriteria(TPerson.class);
criteria.add(Restrictions.eq("name", "oham"));
criteria.add(Restrictions.eq("address", "earth"));	
criteria.list();

 执行sql:

select
        this_.id as id0_0_,
        this_.name as name0_0_,
        this_.address as address0_0_,
        this_.tel as tel0_0_,
        this_.zipcode as zipcode0_0_ 
    from
        t_person this_ 
    where
        this_.name=? 
        and this_.address=?

 

注意, 1)鄙人使用的Hibernate版本为4.1.4.Final,示例1的中Restrictions是先前版本的Expression的替代,在4.1.4.Final中,Expression已被标记为过期。

            2)针对SQL语法,Restrictions提供了对应的查询机制,可以去看看:http://docs.jboss.org/hibernate/orm/4.1/javadocs/

 

         3)Restriction中的各个方法的属性名参数是指POJO中的属性名,非真实数据库表的字段名。

 

Example类的使用

Example实现了Criteria接口,所以也可以用作Criteria的查询条件。Example的作用是,根据已有的对象,查找属性与之相符的其他对象。一般用于组合查询,如,界面上提供若干查询选项,然后根据用户所选返回符合条件的结果。

示例2:

Criteria criteria = session.createCriteria(TPerson.class);
		
Example example;
example = Example.create(examplePerson);
		
/**
 * 默认的情况下,Hibernate会过滤掉示例对象的Null值属性,可以通过调用
 * excludeNone/excludeZeroes方法进行调整,或则通过excludeProperty将
 * 某个属性排除在外。
 * 1.excludeNone —— 不过滤Null值的属性
 * 2.excludeZeroes —— 过滤值为0 的属性
 * 3.请测测example.excludeNone与example.excludeZeroes,若两者调用,貌似
 * 只用后者起作用。。。
*/
//	example.excludeZeroes();
//	example.excludeNone();
		
//	example.excludeProperty("address");
		
	criteria.add(example);
	criteria.list();

 执行上述的代码的sql:

    select
        this_.id as id0_0_,
        this_.name as name0_0_,
        this_.address as address0_0_,
        this_.tel as tel0_0_,
        this_.zipcode as zipcode0_0_,
        this_.age as age0_0_ 
    from
        t_person this_ 
    where
        (
            this_.name=? 
            and this_.address=? 
            and this_.age=?
        )

 

Criteria复合查询

 现在引入一个一对多的场景:


 执行下面的代码,打印出所有的person以及对应的skill:

Criteria criteria = session.createCriteria(TPerson.class);
List<TPerson> personList = criteria.list();
		
for(TPerson person : personList) {
	System.out.println(person.getName());
			
	Set<TSkill> set = person.getSkills();
	for(TSkill skill : set) {
		System.out.println("\t\t" + skill.getName());
	}
}

 结果:

Hibernate: 
    select
        this_.id as id0_0_,
        this_.name as name0_0_,
        this_.address as address0_0_,
        this_.tel as tel0_0_,
        this_.zipcode as zipcode0_0_,
        this_.age as age0_0_ 
    from
        t_person this_
Hibernate: 
    select
        skills0_.pid as pid0_1_,
        skills0_.id as id1_,
        skills0_.id as id1_0_,
        skills0_.name as name1_0_,
        skills0_.pid as pid1_0_ 
    from
        t_skill skills0_ 
    where
        skills0_.pid=?
Oham
		meditation
		kill

 

如果现在想查出所有具有kill技能的person,可以使用复合查询:

Criteria criteria = session.createCriteria(TPerson.class);
		
//在原有的查询基础上,针对TPerson对象的skills属性构造新的查询过滤条件
Criteria addCriteria = criteria.createCriteria("skills");
addCriteria.add(Restrictions.like("name", "%kill%"));
		
List<TPerson> personList = criteria.list();
		
for(TPerson person : personList) {
	System.out.println(person.getName());
			
	Set<TSkill> set = person.getSkills();
	for(TSkill skill : set) {
		System.out.println("\t\t" + skill.getName());
	}
}

Hibernate会在运行期构造以下的sql:

select
        this_.id as id0_1_,
        this_.name as name0_1_,
        this_.address as address0_1_,
        this_.tel as tel0_1_,
        this_.zipcode as zipcode0_1_,
        this_.age as age0_1_,
        tskill1_.id as id1_0_,
        tskill1_.name as name1_0_,
        tskill1_.pid as pid1_0_ 
    from
        t_person this_ 
    inner join
        t_skill tskill1_ 
            on this_.id=tskill1_.pid 
    where
        tskill1_.name like ?

  

DetachedCriteria

criteria对象生于session,所以其生命周期位于session之内,即虽不同生,必同死。。。这样就很大程度限制了Criteria的重用,对于相同的查询条件,在不同的session实例里需要再实例一个Criteria。

DetachedCriteria是可以脱离Session实例而独立存在的,于是我们可以使用其将某些通用的Criteria查询条件进行抽离,然后使用的时候将其再与当前的session实例绑定。

示例3:

//生成detachedCriteria的实例
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(TPerson.class);
		
		//detachedCriteria的用法与criteria基本类似
		DetachedCriteria addDetachedCriteria = detachedCriteria.createCriteria("skills");
		addDetachedCriteria.add(Restrictions.like("name", "%kill%"));
		
		
		SessionFactory factory = HibernateLocalUtil.getSessionFactory();
		Session session = factory.openSession();
		
		//调用getExecutableCriteria与当前的session实例绑定
		Criteria criteria = addDetachedCriteria.getExecutableCriteria(session);
		
		List<TPerson> personList = criteria.list();
		for(TPerson person : personList) {
			System.out.println(person.getName());
			
			Set<TSkill> set = person.getSkills();
			for(TSkill skill : set) {
				System.out.println("\t\t" + skill.getName());
			}
		}
		
		session.close();

 

 DetachedCriteria也可用于子查询,现在想查询大于平均年龄的所有person。

示例4:

DetachedCriteria avgAge = DetachedCriteria.forClass(TPerson.class);
avgAge.setProjection(Projections.avg("age"));
		
Criteria criteria = session.createCriteria(TPerson.class);
criteria.add(Subqueries.propertyGt("age", avgAge));
		
List<TPerson> list = criteria.list();

生成执行 sql:

    select
        this_.id as id0_0_,
        this_.name as name0_0_,
        this_.address as address0_0_,
        this_.tel as tel0_0_,
        this_.zipcode as zipcode0_0_,
        this_.age as age0_0_ 
    from
        t_person this_ 
    where
        this_.age > (
            select
                avg(this_.age) as y0_ 
            from
                t_person this_
        )

 

Criteria的其他特性辑录

   ——限定返回结果范围:

Criteria criteria = session.createCriteria(TPerson.class);
		
//从100条结果开始的20条记录
criteria.setFirstResult(100);
criteria.setMaxResults(20);

 

   ——排序:

	//按名字(顺序)和地址(逆序)排序
	criteria.addOrder(Order.asc("name"));
	criteria.addOrder(Order.desc("address"));

 

   ——分组与统计:

//对年龄age进行分组
criteria.setProjection(Projections.groupProperty("age"));

 生成sql:

    select
        this_.age as y0_ 
    from
        t_person this_ 
    group by
        this_.age

 

对于多条件组合的分组、统计功能,可以借助ProjectionList,现在统计各个年龄的person数量,

示例5:

	ProjectionList pList = Projections.projectionList();
	pList.add(Projections.groupProperty("age"));
	pList.add(Projections.rowCount());
		
	criteria.setProjection(pList);
	criteria.list();

 生成sql:

    select
        this_.age as y0_,
        count(*) as y1_ 
    from
        t_person this_ 
    group by
        this_.age

 

HQL(Hibernate Query Language)

 Hibernate提供的一套类SQL的查询语言。

具体语法:  [select / update / delete ...]  [from ...] [where ... ] [group by ...] [having ...] [order by ...],用起来与SQL十分类似,但注意好像HQL没有insert之用。

 

注意“

1.若查询或操作一个实体表的数据,from 后面跟的是实体类名,可以采用全路径类名,特别是同名不同包的情况。

 

2.HQL字句本身大小写无关,但其中出现的类名和属性名需要区分大小写。

 

3.若查询的目标实体存在继承关系的判定,例如 TUser 有两个子类TSystemUser和TAdmin,分别做了实体映射, 那么 from TUser 这条HQL返回的记录将包含这两个子类的所有数据,而包含的字段是与父类公有的那些。

 

4.from java.lang.Object  这句将返回数据库所有表的数据。

 

以下示例基于如下表关系:


 

用法举例:

1.获取某个实体的几个属性时可以这样:select u.name, u.age from TUser as u,而此时,list结果集中每个条目是个Object[]类型,不是实体类型,依次包含了所获取的各个属性数据。可以让其返回实体类对象,这样就行了:select new TUser(u.id, u.name) from TUser u,前提是TUser必须有这个构造函数(不好用。。。)。

下面是测试代码:

String hql1 = "from TUser";
String hql2 = "select u.id, u.name from TUser u";
String hql3 = "select new TUser(u.id, u.name) from TUser u";
		
//	List list = session.createQuery(hql1).list();
//	List list = session.createQuery(hql2).list();
List list = session.createQuery(hql3).list();
		
Iterator iterator =  list.iterator();
		
while(iterator.hasNext()) {
			
	//for hql and hql3
	TUser u = (TUser)iterator.next();
	System.out.println(u.getName());
			
	// for hql2
	/*Object[] results = (Object[])iterator.next();
	System.out.println(results[1]);*/
			
}

 

 2.动态的参数绑定:

      (1)使用query接口方法:

String hql = "from TUser u where u.name = ?";
		
Query query = session.createQuery(hql);
query.setString(0, "lulu");
		
List list = query.list();

       (2)使用占位符:

String hql = "from TUser u where u.name = :name";
Query query = session.createQuery(hql);
query.setParameter("name", "Lulu");

 说明动态的参数绑定机制可以使得查询语法与具体的参数值相互独立,这样,对于参数不同,SQL语法相同的查询操作,数据库可以实施性能优化策略。同时避免了参数值对语法本身的影响,也就避免了SQL Injection。

 

3.HQL的引用查询,将HQL语句本身从代码中抽出,写在映射配置文件当中。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TUser" table="t_user">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<property name="name" column="name" type="java.lang.String"/>
	</class>
	
	<query name="TUser.getByName">
		<![CDATA[
			from TUser u where u.name = :name
		]]>
	</query>
	
</hibernate-mapping>

 然后代码中:

Query query = session.getNamedQuery("TUser.getByName");
query.setParameter("name", "Lulu");

 

 4.HQL的联合查询,就是跟SQL的inner join ,left outter, right outer join, full join 差不多的。

注意的是:

 1. 关键字fetch ,看示例代码:

	String hql = "from TUser u join fetch u.addrs";
	Query query = session.createQuery(hql);
		
	List list = query.list();
		
	Iterator it = list.iterator();
		
	while(it.hasNext()) {
		TUser u = (TUser)it.next();
		System.out.print(u.getName() + "----");
		System.out.println(u.getAddrs().size());
	}

上述的HQL对应SQL为: 

    select
       ...
    from
        t_user U
    inner join
        t_address addr
            on uid=addr.uid

(其中因为on uid=addr.uid所描述的对应关系已在映射文件中指定,所以HQL无对应的表现) 

 

这里的fetch表示查出address对象后立刻立刻填充到对应的TUser对象的address集合属性中。若不加fetch,则list当中每个条目是个Object[],其中Object[]包含了一个TUser对象和对应的一个TAddress对象,运行代码:

String hql = "from TUser u join u.addrs";
Query query = session.createQuery(hql);
		
List list = query.list();
		
Iterator it = list.iterator();
		
while(it.hasNext()) {
	Object[] arr = (Object[])it.next();
			
	for(int i=0; i< arr.length; i++) {
		if(arr[i] instanceof TUser) {
			System.out.println( ((TUser)arr[i]).getName() );
		}else if(arr[i] instanceof TAddress) {
			System.out.println( "---" + ((TAddress)arr[i]).getAddr() );
		}
	}
}

 输出结果:

Hibernate: 
    select
        tuser0_.id as id0_0_,
        addrs1_.id as id1_1_,
        tuser0_.name as name0_0_,
        addrs1_.uid as uid1_1_,
        addrs1_.addr as addr1_1_ 
    from
        t_user tuser0_ 
    inner join
        t_address addrs1_ 
            on tuser0_.id=addrs1_.uid
Cancan
---Mars
Oham
---Earth
Lulu
---Moon
Lulu
---Earth
Maomao
---Venus

 

2.fetch 只对inner join 和 left outer join 有效,这是因为想right outer join,full join之类,作为关联对象可能为空,因此Hibernate无法通过fecth 进行集合填充操作。

 

 

数据加载方式

 

 Hibernate中支持以下的数据加载方式:

1.即时加载(Immediate Loading)—— 当实体加载完毕,立即加载其关联的数据。

 

2.延迟加载(Lazy Loading)—— 实体加载时,其关联数据不是立刻获取,而是当关联数据第一次被访问时再进行读取。

 

3.预先加载(Eager Loading)—— 实体及其关联对象同时读取,这与即时加载类似,不过实体及关联数据是通过一条SQL语句(基于外连接[outer join])同时读取。

 

4.批量加载(Batch Loading)—— 对于即时加载和延迟加载,可以采用批量加载方式进行性能上的优化。

 

举例说明,这里引入TUser及其地址的一对多关联。

即时加载,TUser映射中描述关联关系的配置段:

 

<set name="addrs" 
	table="t_address"
	cascade="none"
	lazy="false">
	<key column="uid" />
	<one-to-many class="TAddress" />		
</set>
 注意lazy=“false”。运行代码:

 

 

	Criteria criteria = session.createCriteria(TUser.class);
        criteria.add(Restrictions.eq("name", "lulu"));
	List list = criteria.list();
 输出结果:

 

 

Hibernate: select this_.id as id0_0_, this_.name as name0_0_ from t_user this_ where this_.name=?
Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid=?
 可以看出即时加载的时候,当加载关联主题TUser的时候,Hibernate会自动读取其关联的数据并完成关联属性的填充。

 

 

延迟加载,有时我们只想取得TUser的信息,无需取得其对应的地址信息,即使用延迟加载,相应的关联关系配置段:

 

		<set name="addrs" 
			 table="t_address"
			 lazy="true">
			 <key column="uid" />
			<one-to-many class="TAddress" />		
		</set>
 把lazy设置为“true”就行了。执行代码:

 

 

		Criteria criteria = session.createCriteria(TUser.class);
		criteria.add(Restrictions.eq("name", "lulu"));
		
		List list = criteria.list();
 输出结果:

 

 

Hibernate: select this_.id as id0_0_, this_.name as name0_0_ from t_user this_ where this_.name=?
 可以看出此时只加载了TUser的数据,没有相应的Address信息,若加上读取Address的代码:
Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Restrictions.eq("name", "lulu"));
		
List list = criteria.list();
		
Iterator it = list.iterator();
while(it.hasNext()) {
	TUser user = (TUser)it.next();
	System.out.println(user.getAddrs().size());
	
}
 输出结果:
Hibernate: select this_.id as id0_0_, this_.name as name0_0_ from t_user this_ where this_.name=?
Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid=?
2
 所谓的延迟加载就是当真正需要数据的时候才进行读取操作。

 

 

预先加载,所谓的预先加载就是通过outer-join的方式,以一条SQL完成实体及其关联数据的读取操作,相比即时加载时的若干条SQL读取操作而言,其性能更优。

 

		<set name="addrs" 
			 table="t_address"
			 lazy="true"
			 outer-join="true">
			 <key column="uid" />
			<one-to-many class="TAddress" />		
		</set>
配置中加outer-join=“true” 即可启用预先加载。

 

注意,对于集合类型的关联关系(一对多,多对一,多对多)一般不宜采用预先加载的方式,理由跟即时加载的一样;

特别复杂的关联关系,如多层关联,这样生成的outer-joinSQL可能会过于复杂,因根据情况判断预先加载的可用性,可以通过全局变量(hibernate.max_fetch_depth)限定outer-join的层次(一般设定为5层)。

 

批量加载,即通过批量提交多个限定条件,一次完成多个数据的读取。如对于以下形式的SQL:

 

select  from t_user where id = 1;
select  from t_user where id = 2;
 合并为一条SQL来完成同样的功能:

 

 

select  from t_user where id = 1 or id = 2;
 若使用了批量加载的方式,Hibernate会在进行数据查询之前,自动在当前的Session中寻找是否还有同类型的待加载的数据,如果有则将其查询条件合并到当前的select语句中一并提交。

 

只需在实体映射文件的class节点设定一个batch-size,就行,一般batch-size要设定为合理数值(<10)。

示例说明,还是拿TUser跟TAddress来说,现在TUser的映射中关于TAddress的映射配置如下:

 

<set name="addrs" 
	table="t_address"
	lazy="true">
	<key column="uid" />
	<one-to-many class="TAddress" />		
</set>
 执行代码:

 

 

String hql = "from TUser";
		
Query query = session.createQuery(hql);
		
List<TUser> list = query.list();
		
Iterator<TUser> it = list.iterator();
		
while(it.hasNext()) {
	TUser u = it.next();
	Set<TAddress> addrs = u.getAddrs();
	Iterator<TAddress> it2 = addrs.iterator();
			
	while(it2.hasNext()) {
		System.out.println(it2.next().getAddr());
	}
}		
 输出结果:

 

 

Hibernate: select tuser0_.id as id0_, tuser0_.name as name0_ from t_user tuser0_  --查询TUser的

--下面是对应每个TUser的实体对象分别查一次TAddress对象
Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid=? 
Mars
Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid=?
Earth
Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid=?
Moon
Earth
Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid=?
Venus
 现在映射文件改为如下:

 

 

<set name="addrs" 
	table="t_address"
	lazy="true"
	batch-size="3">
	<key column="uid" />
	<one-to-many class="TAddress" />		
</set>
加了个batch-size=“3”,执行同样的代码,输出结果:

 

 

Hibernate: select tuser0_.id as id0_, tuser0_.name as name0_ from t_user tuser0_ -- 查询TUser对象

-- 对应每个TUser对象实例,查询TAddress对象
Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid in (?, ?, ?)
Mars
Earth
Earth
Moon
Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid=?
Venus
 可以看出,由于设置batch-size=“3”,Hibernate将具有相同类型的待加载数据每3个的合并为一条SQL;如果这里设置为4,则最终只合并为一条,这里我就不试了。
 
SQL查询

 Hibernate的SQL查询接口使用示例:

看代码:

String sql = "select * from t_user usr";
List list = session.createSQLQuery(sql).list();
		
Iterator it = list.iterator();
		
while(it.hasNext()) {
	Object[] props = (Object[])it.next();
			
	System.out.println(props[1]);
}

 如代码中所示,list()返回的是一个Object[],里面依次包含了SQL 中 * 代表的各个column的值,至于其顺序需自知。而关于column的类型问题,请看Hibernate的官网介绍,比我写的强多了:http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch13.html

上述代码输出结果:

Hibernate: select * from t_user usr
Cancan
Oham
Lulu
Maomao

 

使用SQL查询返回实体类型示例

 示例代码:

String sql = "select * from t_user usr";
List list = session.createSQLQuery(sql).addEntity(TUser.class).list();
		
Iterator it = list.iterator();
		
while(it.hasNext()) {
	TUser u = (TUser)it.next();
	System.out.println(u.getName());
	System.out.println(u.getAddrs().size());
}

 调用一下addEntity(Class cls)指定实体类型就可以了。

 

 使用SQL查询返回多个实体类型示例

String sql = "select {u.*}, {addr.*} from t_user u, t_address addr where u.id = addr.uid";
Query query = session.createSQLQuery(sql).addEntity("u", TUser.class)
					.addEntity("addr", TAddress.class);	
		
List list = query.list();
		
Iterator it = list.iterator();
		
while(it.hasNext()) {
	Object[] entitys = (Object[])it.next();
	TUser u = (TUser)entitys[0];
	TAddress addr = (TAddress)entitys[1];
			
	System.out.println(u.getName() + " lives in " + addr.getAddr());
			
}

 

 使用SQL查询返回一个非映射实体bean示例

首先是一个非映射实体bean:

package learnHibernate.bean;

import java.io.Serializable;

public class UserAddrBean implements Serializable{
	private static final long serialVersionUID = -1156337693273177901L;
	
	private int userId;
	private String userName;
	private String address;
	public int getUserId() {
		return userId;
	}
	public void setUserId(int userId) {
		this.userId = userId;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	
	
}

 示例代码:

String sql = "select u.id as userId, u.name as userName, addr.addr as address " +
				"from t_user u, t_address addr where u.id = addr.uid";
Query query = session.createSQLQuery(sql)
		.setResultTransformer(Transformers.aliasToBean(UserAddrBean.class));
		
List list = query.list();
		
Iterator it = list.iterator();
		
while(it.hasNext()) {
	UserAddrBean ud = (UserAddrBean)it.next();
			
	System.out.println(ud.getUserName() + " lives in " + ud.getAddress());
			
}

 

动态参数绑定

与HQL的一样用法,示例:

 

String sql = "select u.id as userId, u.name as userName, addr.addr as address " +
			"from t_user u, t_address addr where u.id = addr.uid and u.name = ?";
Query query = session.createSQLQuery(sql)
		.setResultTransformer(Transformers.aliasToBean(UserAddrBean.class));
		
query.setString(0, "oham");






String sql = "select u.id as userId, u.name as userName, addr.addr as address " +
			"from t_user u, t_address addr where u.id = addr.uid and u.name = :name";
Query query = session.createSQLQuery(sql)
		.setResultTransformer(Transformers.aliasToBean(UserAddrBean.class));
		
query.setParameter("name", "oham");
 

 

引用查询与HQL的差不多用法,现在介绍一种类似于Ibatis风格的resultSet,在映射文件中的一段引用SQL:

 

<resultset name="userAddrRs">
	<return alias="u" class="TUser" />
	<return-join alias="addr" property="u.addrs" />
</resultset>
	
<sql-query name="userAddrSQL" resultset-ref="userAddrRs">
	SELECT
		{u.*}, {addr.*}
	FROM t_user u
	JOIN t_address addr ON addr.uid = u.id
</sql-query>
 注意的是resultSet节点必须写在sql-query,包括query节点之前,测试代码:
Query query = session.getNamedQuery("userAddrSQL");
		
List list = query.list();
		
Iterator it = list.iterator();
		
while(it.hasNext()) {
	Object[] arr = (Object[])it.next();
			
	for(int i=0; i< arr.length; i++) {
		if(arr[i] instanceof TUser) {
			System.out.println( ((TUser)arr[i]).getName() );
		}else if(arr[i] instanceof TAddress) {
			System.out.println( "---" + ((TAddress)arr[i]).getAddr() );
		}
	}
			
}
 可以看出,返回来的list的每个条目是个Object[]。

 

注意:resultSet中明确指定属性可以这样来:

 

<resultset name="userAddrRs">
	<return alias="u" class="TUser" >
		<return-property name="id" column="userId" />
		<return-property name="name" column="userName" />
	</return>
	<return-join alias="addr" property="u.addrs" />
</resultset>
	
<sql-query name="userAddrSQL" resultset-ref="userAddrRs">
	SELECT
		u.id AS userId,
		u.name  AS userName,
		addr.*
	FROM t_user u
	JOIN t_address addr ON addr.uid = u.id
</sql-query>
 为什么SQL在下用addr.* ?,阁下可以试试addr像u那样指定明确列名,然后在return-join里面也写上return-property,会报错,具体原因不知道,在下估计是TUser与TAddress的一对多映射关联没弄好。映射配置如下

 

 

<set name="addrs" 
			 table="t_address"
			 lazy="true"
			 batch-size="4">
			 <key column="uid" />
			<one-to-many class="TAddress" />		
		</set>
还有很多特性的,详情须看看官方文档。

 

 

调用存储过程

创建一个存储过程(在下用的是MySQL):

CREATE PROCEDURE test_pr (in p_name varchar(30))
BEGIN
  select id, name from t_user where name  = p_name;
END

 然后看映射配置文件:

<sql-query name="testProcedure" callable="true">
	<return alias="u" class="TUser">
		<return-property name="id" column="id" />
		<return-property name="name" column="name" />
	</return>
	{ call test_pr(:name) }
</sql-query>

 然后是测试代码:

	Query query = session.getNamedQuery("testProcedure");
	query.setParameter("name", "oham");
		
	List<TUser> list = query.list();
		
	Iterator<TUser> it = list.iterator();
		
	while(it.hasNext()) {
		TUser u = it.next();
		System.out.println(u.getName());
			
	}

 注意的是因为不同的DBMS对存储过程的规范不一样,因此Hibernate对这个的支持也不一样,可以google一下Hibernate如何调用Oracle的存储过程,跟MySQL的是不一样的。

 

自定义持久化实现

 简而言之,就是直接指定用于实体的insert, update, delete操作的SQL语句,而不是Hibernate自动生成的SQL,示例:

在TAddress的映射文件中加入:

 

<sql-insert>
	INSERT INTO t_address (uid, addr) VALUES (?,?)
</sql-insert>
	
<sql-update>
	UPDATE t_address SET addr = ?, uid = ? WHERE id = ?
</sql-update>
	
<sql-delete>
	DELETE FROM t_address WHERE id = ?
</sql-delete>
 然后执行代码:
	Transaction tx = session.beginTransaction();
	TAddress addr = (TAddress)session.get(TAddress.class, 4);
		
	addr.setAddr("Earth_2");
	addr.setuId(1);
		
	tx.commit();
 
 输出如下:

 

 

Hibernate: select taddress0_.id as id1_0_, taddress0_.uid as uid1_0_, taddress0_.addr as addr1_0_ from t_address taddress0_ where taddress0_.id=?
Hibernate: UPDATE t_address SET addr = ?, uid = ? WHERE id = ?
 可以看出,update的时候用了<sql-update>里面的update SQL。要注意的是代码里的set值顺序必须要与update SQL中的一样。

 

若把代码中的set值语句换换位置,运行,输出结果:

 

若把映射中的<sql-update>注释掉,看输出结果如下:

 

org.hibernate.exception.GenericJDBCException: Incorrect integer value: 'Earth_2' for column 'uid' at row 1
 在下的抛了这么个异常,说明Hibernate用上了自定义的update SQL,而代码的set值顺序有误导致动态参数绑定后出现数据类型错误。若此时把映射文件中的<sql-update>注释掉,在运行:
Hibernate: select taddress0_.id as id1_0_, taddress0_.uid as uid1_0_, taddress0_.addr as addr1_0_ from t_address taddress0_ where taddress0_.id=?
Hibernate: update t_address set uid=?, addr=? where id=?
 正常执行了,因为update 的SQL是用了Hibernate自动生成的SQL。
自定义持久化大概是这么个意思,具体可以翻翻官方文档,但其应用场景在下始终还是不明白。。。

 

 

 

 

 

 

 

 

 

  • 大小: 38.2 KB
  • 大小: 6.6 KB
  • 大小: 4.2 KB
分享到:
评论

相关推荐

    Hibernate使用——入门

    **Hibernate使用——入门** Hibernate 是一个强大的开源对象关系映射(ORM)框架,它简化了Java应用程序与数据库之间的交互。这篇博文将引导你入门Hibernate,理解其基本概念和使用方法。 **1. Hibernate概述** ...

    Hibernate总结——课程管理

    在Java开发中,Hibernate是一个非常重要的对象关系映射(ORM)框架,它简化了数据库操作,使得开发者可以使用面向对象的方式来处理数据。本教程将深入探讨如何使用Hibernate来实现一个简单的课程管理系统,涵盖多对...

    Hibernate 4——Hello World

    通过将Java对象与数据库表之间的映射关系进行抽象,Hibernate允许开发者用面向对象的方式处理数据,从而减少了对SQL的直接依赖。 ### Hibernate 4简介 Hibernate 4是Hibernate框架的一个重要版本,它带来了许多改进...

    Hibernate自动创建表结构示例--Oracle

    标题"Hibernate自动创建表结构示例--Oracle"表明我们将使用Hibernate在Oracle数据库中自动生成表结构,这是通过Hibernate的`hibernate.hbm2ddl.auto`配置属性实现的。这个属性可以设置为"create"、"update"、...

    Hibernate逆向工程-oracle示例借鉴.pdf

    本篇将详细介绍如何在Oracle数据库环境下,使用MyEclipse进行Hibernate逆向工程的配置和应用。 首先,确保你的开发环境中已经安装了MyEclipse并配置了Oracle数据库连接。在MyEclipse中,打开Database Explorer视图...

    struts2+hibernate整合例子——新闻管理系统

    总结来说,"struts2+hibernate整合例子——新闻管理系统"是一个典型的Java Web应用示例,展示了如何利用Struts2的MVC模式和Hibernate的ORM能力,实现对新闻数据的CRUD操作及高级查询。这个系统可能包含了Action类、...

    hibernate映射和查询

    这些查询语言提供了面向对象的方式来检索数据,比传统的 SQL 更加灵活和强大。 1. **HQL**:类似于 SQL,但它是面向对象的。例如,以下 HQL 查询语句用于获取所有学生: ```java Session session = ...

    安卓Android源码——Hibernate4.zip

    【标题】"安卓Android源码——Hibernate4.zip" 提供的是关于在Android平台上使用Hibernate4框架的源代码示例。Hibernate4是一个流行的Java对象关系映射(ORM)工具,它允许开发者将数据库操作与Java对象模型相结合,...

    配置使用Hibernate示例程序

    在使用Hibernate进行数据操作时,主要有两种方式:HQL(Hibernate Query Language)和Criteria API。HQL是一种面向对象的查询语言,而Criteria API提供了更动态的查询构建方式。 例如,使用HQL查询所有用户: ```...

    jpa之使用hibernate示例代码

    在"jpa之使用hibernate示例代码"中,我们可能会涉及以下关键知识点: 1. **实体类(Entity)**:在JPA中,实体类是Java类,代表数据库中的表。它需要使用`@Entity`注解标记,并且通常有一个主键字段,用`@Id`注解...

    孙卫琴hibernate source code2

    `chapter5`关注的是Hibernate的查询语言——HQL(Hibernate Query Language)和Criteria API。HQL是一种面向对象的查询语言,允许开发者用类名和属性名来编写查询,极大地提高了代码的可读性。Criteria API提供了一...

    J2EE示例项目——注册

    这个项目可能包括了前端界面、后端业务逻辑以及数据存储层的处理,使用了Struts作为MVC框架,Hibernate作为对象关系映射(ORM)工具,这些都是Java开发中的关键组件。 Struts是Apache软件基金会的Jakarta项目下的一...

    hibernate的_映射、三态、脏数据、Session缓存

    - **二级缓存**:除了Session缓存之外,Hibernate还支持跨Session的缓存机制——二级缓存。通过配置二级缓存插件,可以实现跨Session的数据共享,进一步提高系统的性能。 #### 综合示例解析 以上述部分示例代码为...

    Hibernate SQLQuery 查询Oracle char类型结果为一个字符解决方法

    本文介绍了在使用Hibernate框架查询Oracle数据库时遇到的一个常见问题——char类型字段映射为单个字符,并提供了三种解决方案。首先,可以通过调整Hibernate的映射方式,使用`addScalar`方法显式指定字段的类型;...

    轻量级Java EE企业应用开发实战—光盘——Struts 2+Spring+Hibernate整合开发

    Spring与Hibernate的整合进一步简化了数据访问层的编写,通过Spring的数据访问抽象,如JdbcTemplate或HibernateTemplate,可以实现更优雅的数据库操作。 这个实战教程的压缩包文件包含了多个部分,可能代表教程的...

    基于hiberate的分页小例子

    Hibernate提供了一种灵活的查询方式——Criteria API和HQL(Hibernate Query Language),它们都支持分页查询。在这些查询中,我们可以通过设置`FirstResult`和`MaxResults`参数来实现分页。`FirstResult`表示从结果...

    自己动手模仿Hibernate写数据库框架

    【标题】"自己动手模仿Hibernate写数据库框架"揭示了本次讨论的核心内容——尝试构建一个类似于Hibernate的数据库操作框架。Hibernate是一个流行的Java ORM(对象关系映射)框架,它简化了数据库与Java对象之间的...

    Hibernate5实例程序

    Hibernate提供了自己的查询语言——Hibernate Query Language(HQL),类似于SQL,但更面向对象。此外,还可以使用Criteria API进行动态查询。 6. ** Criteria API** Criteria API是一种更高级的查询方式,允许...

Global site tag (gtag.js) - Google Analytics