Hibernate是一个流行的Java ORM (对象关系映射)框架,用于将面向对象的Java应用程序与关系型数据库(如MySQL,Oracle)之间建立映射关系。
尽管Hibernate提供了一整套ORM映射解决方案,Hibernate默认的结果集转换仍然无法满足某些特定业务场景的需求。这时候,就需要使用`ResultTransformer`来自定义Hibernate的结果集转换。
在这篇文章中,我们会细致地探讨`ResultTransformer`的相关实现方法和实际应用。
### 什么是ResultTransformer?
在Hibernate中,`ResultTransformer`是一种机制,用于将Hibernate查询返回的标准结果集转换为自定义格式。
`ResultTransformer`位于`org.hibernate`包中,是一个接口,用于转换原生SQL查询及Hibernate Criteria查询的结果,并且支持插入自定义的数据类型。
使用Hibernate提供的默认的结果集转换器会将查询结果转换成Hibernate模型对象或者是一个Object数组(Object[])。
例如,假设我们有一个人员表,包含有id,name,age三个字段,可以使用Hibernate查询API进行如下查询:
```
List result = session.createSQLQuery("select id,name,age from persons").list();
for(Object[] obj : result){
System.out.println("id: "+obj[0]+" name: "+obj[1]+" age: "+obj[2]);
```
这将返回一个Object[]类型的数组,需要手动处理数据。
但是,使用自定义的结果集转换器就可以通过公共的接口以更友好的方式来处理查询结果:
```
List
result = session.createSQLQuery("select id,name,age from persons")
.setResultTransformer(Transformers.aliasToBean(Person.class))
.list();
for (Person p : result) {
System.out.println(p.getId() + " " + p.getName() + " " + p.getAge());
```
在这个示例中,我们使用`aliasToBean`方法制定了Person类型来处理结果集,并且转换后的List包含了已经映射好的Person类的对象。
### ResultTransformer 的工作原理
`ResultTransformer`工作时,将查询到的所有结果封装到一个List中,然后将该List作为参数传入到`ResultTransformer`实现类的构造函数中,最后返回完整的查询结果。
例如,下面是一个简单的`ResultTransformer`实现示例,用于将ResultSet转换为Object[]数组:
```
public class MyResultTransformer implements ResultTransformer {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple;
@Override
public List transformList(List collection) {
return collection;
```
在上面的代码中,我们重载了`transformTuple()`方法和`transformList()`方法。
- `transformTuple()`方法用于将查询结果(每一行记录)转换为自定义格式(如Object[])。它将传入一个Object[](查询结果)和一个String[](此查询返回的列名数组)。做完处理后,返回转换后的结果。
- `transformList()`方法用于将批量查询返回的List集合转换方法自定义格式。
当我们执行查询时,需要传入一个实现了ResultTransformer接口的实例:
```
List result = session.createSQLQuery("select id,name,age from persons")
.setResultTransformer(new MyResultTransformer())
.list();
```
这里,我们将实例化`MyResultTransformer`类,并设置为结果集转换器。
当查询结果返回时,将首先调用`transformTuple()`方法,将原始结果转换为数组,然后将`transformTuple()`的返回值存储到`transformList()`方法中,并将结果集合作为结果返回。
### 深入了解 ResultTransformer
尽管上面的示例已经演示了如何使用`ResultTransformer`接口对查询结果进行转换,但Hibernate提供了许多预定义的变换器(`Transformers`),直接使用预定义的的变换器可大致提高开发效率。
#### Transformers 列表
让我们好好了解一下 Transformers 列表:
- aliasToEntityMap:将查询结果转换为一个Map,并将查询结果中指定的列作为Map的键,查询结果中的整行数据作为Map的值
- aliasToBean:将查询结果转换为一个JavaBean。
- ToList:将查询到的结果转换成List,List中的每个元素均为一个原始查询数据行。
- ToArray:将查询到的结果转换为数组。
- scalar:该变换器支持将原生SQL中查询的每一行结果转换为一个特定的类型。
这些Transformers共同完成了Hibernate的结果列表的转换。
#### aliasToEntityMap
这个变换器将结果组织成一个Map类型的集合,可以使用任意文本作为键,并将此值映射到JPA实体模型的属性上。
让我们看一下示例:
```
List> result = session
.createSQLQuery("select id,name,age from persons")
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
```
这条查询语句返回由三列组成的结果集。我们使用 `Transformers.ALIAS_TO_ENTITY_MAP` 构建参数将结果转换为一个元素类型为Map的列表。
现在,`result`列表的每个元素都是一个条目,包含了一个"ID",一个"name",和一个"age"。
#### aliasToBean
该变换器使用查询结果集中的列名匹配目标类中已定义的属性名,并将结果映射到指定的JavaBean中(属性名需要通过setter或getter方法实现)。
例如:
```
public class Person2 {
private int id;
private String name;
private int age;
public void setId(int id) {
this.id = id;
public void setName(String name) {
this.name = name;
public void setAge(int age) {
this.age = age;
public int getId() {
return id;
public String getName() {
return name;
public int getAge() {
return age;
```
然后,我们可以使用`aliasToBean()`方法将查询结果转换为映射后的Person实例:
```
List
result = session.createSQLQuery("select id,name,age from persons")
.setResultTransformer(Transformers.aliasToBean(Person2.class))
.list();
```
在这里,我们将`result`转换为了`Person`类的List,Hibernate将自动将查询结果中的id,name和age根据属性名映射到Person实例中。
#### scalar
`scalar`变换器可以将原生查询的结果转换为任意Java数据类型,例如String、Integer、Long等。
例如:
```
List result = session.createSQLQuery("select name from persons")
.setResultTransformer(Transformers.scalar(String.class))
.list();
```
这里,我们使用`scalar()`方法将查询转换为List,查询结果中的每一行将自动映射到一个String类型的实例中。这个方法的参数决定了转换后的目标类型。
### 总结
在本文中,我们详细了解了Hibernate中的`ResultTransformer`接口,学习了该接口的工作原理和应用方法。我们还介绍了`Transformers`类提供的预定义结果集变换器,这些变换器可以帮助我们更容易地完成结果集转换和映射操作。
使用自定义的结果集转换器可以大大提高查询结果转换的效率和灵活性,这对于一些特定的业务场景非常有用。如果您在使用Hibernate时遇到了特定的转换需求,同时`ResultTransformer`提供的预定义操作无法满足您的需求,那么自定义实现将是一个非常好的解决方案。