跳至主要內容

Hibernate知识点

zzz大约 2 分钟

Hibernate知识点

结果转换器(Map)

使用hibernate时通过设置ResultTransformer为Transformers.ALIAS_TO_ENTITY_MAP将查询出来的行记录转换为HashMap存储

String selectAddressSql = "select t.area_no as code  ,t.name ,t.parent_no as parent_code ,t.type as levels from const_area t order by t.seq_no";
            list = session.createSQLQuery(selectAddressSql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();

先看下Transformers.ALIAS_TO_ENTITY_MAP实现的核心代码

// AliasToEntityMapResultTransformer中转换的核心代码
@Override
	public Object transformTuple(Object[] tuple, String[] aliases) {
		Map result = new HashMap(tuple.length);
		for ( int i=0; i<tuple.length; i++ ) {
			String alias = aliases[i];
			if ( alias!=null ) {
				result.put( alias, tuple[i] );
			}
		}
		return result;
	}

其实就是按照传入的参数aliases(别名)将结果数据依次放入HashMap中,aliases中存放的值就作为key。

从这里引发出两个问题:

  1. 什么时候调用AliasToEntityMapResultTransformer.transformTuple方法
  2. aliases数组从何获取?

何时调用transformTuple方法?

直接上代码!

image-20211231140614598
image-20211231140614598

HolderInstantiator的instantiate方法完成了转换工作,HolderInstantiator中保存了我们自定义ResultTransformer和别名数组,别名数组存放在queryReturnAliases中。

从下面的代码可以发现别名是从内部方法getReturnAliasesForTransformer中通过返回当前类CustomLoader的成员变量transformerAliases保存的。

HolderInstantiator holderInstantiator = HolderInstantiator.getHolderInstantiator((ResultTransformer)null, resultTransformer, this.getReturnAliasesForTransformer());

从何获取aliases数组?

先做一个猜想,应该是具体数据库驱动中控制。

  • 执行查询的过程获取ResultSet中会调用JDBC进行数据库查询,其中statement中包含了数据的元信息。
image-20211231141637667
image-20211231141637667
image-20211231142330389
image-20211231142330389
  • 获取ResultSet之后会对结果集进行进一步的处理
image-20211231142515904
image-20211231142515904
image-20211231142730860
image-20211231142730860

这里就是CustomLoader的成员变量transformerAliases的初始化时机的位置,其实就是从JDBC获取ResultSet时创建的元数据中存放的statement中的accessors中对应的COLUMN_NAME

上述的resultProcessor.performDiscovery(metadata, types, aliases)

public void performDiscovery(JdbcResultMetadata metadata, List<Type> types, List<String> aliases) throws SQLException {
        if (this.alias == null) {
            // 从元数据中获取到别名,这里的元数据也就是之前提到的JDBC驱动中获取ResultSet时创建的
          	// 这行代码最终就是从statement中获取到accessors中对应的COLUMN_NAME
            this.alias = metadata.getColumnName(this.position);
        } else if (this.position < 0) {
            this.position = metadata.resolveColumnPosition(this.alias);
        }

        if (this.type == null) {
            this.type = metadata.getHibernateType(this.position);
        }

        types.add(this.type);
        aliases.add(this.alias);
    }