复杂类型用以表示在数据库中相互关系为一对一,一对多的数据。
映射文件:
<!--complex type property that defined by user-->
<resultMap id="get-product-complex" class="product">
<result property="id" column="prd_id"/>
<result property="description" column="prd_description"/>
<result property="price" column="prd_price"/>
<result property="category" column="prd_cat_id" select="getCategory-complex"/>
</resultMap>
<resultMap id="get-category-complex" class="category">
<result property="id" column="cat_id"/>
<result property="description" column="cat_description"/>
</resultMap>
<select id="getCategory-complex" resultMap="get-category-complex">
<![CDATA[
select * from t_category where cat_id = #value#
]]>
</select>
<select id="getProduct-complex" resultMap="get-product-complex" parameterClass="java.lang.Integer">
<![CDATA[
select * from t_product where prd_id = #value#
]]>
</select>
<!--END-->
DAO层:
public Product getProductUseComplexType(int id) throws SQLException {
init();
Product product = (Product)sqlMapClient.queryForObject("getProduct-complex", id);
return product;
}
Test类:
/**
* 测试复杂属性类型
* @throws SQLException
*/
public void getProductUseComplexType() throws SQLException{
Product product = productDao.getProductUseComplexType(1);
System.out.println(product);
}
结果:
id:1
description:basketball
price206.99
catId:1
catDescription:sports
上面的例子中,Product对象拥有一个类型为Category的category属性。因为category是复杂类型(用户定义的类型),JDBC不知道如何给它赋值。通过将category属性值和另一个mapped statement联系起来,为SQL Map引擎如何给它赋值提供了足够的信息。通过执行“getProduct”,“get-product-result”Result Map使用PRD_CAT_ID字段的值去调用“getCategory”。“get-category-result”Result Map将初始化一个Category对象并赋值给它。然后整个Category对象将赋值给Product的category属性。
避免N+1 Select(1:1)
上面的方法存在一个问题,就是无论何时加载一个Product,实际上都要执行两个SQL语句(分别加载Product和Category)。只加载一个Product的情况下,这个问题似乎微不足道。但在执行一个获得10个Product的查询时,每得到一个Product都要分别执行一个加载Category的SQL语句。结果共执行了11次查询:一次用于得到一个Product List,每得到一个Product对象都要执行另外一次查询,以获得相应的Category对象(N+1,这个例子是10+1=11)。
解决方法是,使用一个联合查询和嵌套的属性映射来代替两个查询statement。
映射文件:
<!--avoid N+1 select(1:1)-->
<resultMap id="get-product-complex-promotion" class="product">
<result property="id" column="PRD_ID"/>
<result property="description" column="PRD_DESCRIPTION"/>
<result property="price" column="prd_price"/>
<result property="category.id" column="CAT_ID" />
<result property="category.description" column="CAT_DESCRIPTION" />
</resultMap>
<statement id="getProduct-complex-promotion" parameterClass="int" resultMap="get-product-complex-promotion">
<![CDATA[
select * from t_product, t_category
where prd_cat_id=cat_id
and prd_id = #value#
]]>
</statement>
DAO层:
public Product getProductUseComplexTypePromotion(int id)
throws SQLException {
init();
Product product = (Product)sqlMapClient.queryForObject("getProduct-complex-promotion", id);
return product;
}
Test类:
/**
* 测试复杂属性类型的改进(避免N+1 select)
* @throws SQLException
*/
public void getProductUseComplexTypePromotion() throws SQLException{
Product product = productDao.getProductUseComplexType(1);
System.out.println(product);
}
结果和上面的一样。
延迟加载 VS 联合查询(1:1)
必须要声明的是,使用联合查询的方案并不总是最好的。假如很少有必要访问相关的对象(如Product对象的Category属性),则不用联合查询加载所有的Categor属性可能更快。对于牵涉到外部连接或没有索引字段的数据库设计时,更是如此。在这种情况下,使用延迟加载和字节码增强选项的子查询,可能性能会更好。基本的原则是,如果您需要访问相关的对象,则使用联合查询。否则,使用延迟加载和字节码增强选项的子查询。
如果您不知道选择哪种方法,别担心。您可以随时更改选择而不会影响到Java代码。上面两个例子都得到相同的结果,并使用同样的调用方法。唯一要考虑的是,如果您要缓存查询结果,则使用子查询(而不是联合查询)来缓存查询结果。
分享到:
相关推荐
### Ibatis调用Oracle存储过程返回自定义类型 在企业级应用开发中,尤其是在金融、保险等业务场景中,往往需要处理复杂的数据结构与逻辑。本文将深入探讨如何使用Ibatis框架来调用Oracle数据库中的存储过程,并实现...
在Ibatis中,复杂查询通常涉及到多个表的联接、条件动态拼接、子查询以及各种数据类型的处理。文档"Ibatis复杂查询语句.doc"所展示的查询语句就是一个很好的例子,展示了Ibatis如何处理复杂的数据库操作。接下来,...
总结来说,`iBatis`的自定义数据类型机制允许我们在不支持中文的数据库中存储汉字,通过编写自定义的TypeHandler,我们可以灵活地将中文字符串转换为数据库可以接受的格式,然后在读取时恢复原状。这种方式在无法...
ibatis 读取oracle clob类型
在iBatis中,输入输出参数类型的支持非常丰富,几乎涵盖了Java中常见的所有基本数据类型及其封装类,同时也支持自定义JavaBean类型的传递。这使得开发者在处理数据库操作时具有很高的灵活性。 - **基本数据类型**: ...
Ibatis对枚举类型的原生支持可能不如实体类那样直观,但通过一些策略,我们可以实现枚举与数据库字段之间的映射。以下将详细解释如何在Ibatis中处理枚举类型。 首先,我们需要定义枚举类。枚举类通常包含若干枚举...
标题中的“自定义Ibatis生成器”指的是在使用MyBatis框架时,为了解决重复的手动编写SQL映射文件和Mapper接口,开发者可以创建自己的代码生成器,以自动化这个过程。Ibatis生成器(也称为MyBatis Generator)允许...
4. 使用`@TypeHandler`注解:对于实体类的属性,可以直接在字段上使用`@TypeHandler`注解指定对应的类型处理器。 通过深入理解和灵活运用`TypeHandlerCallback`,开发者可以更好地控制数据在Java应用和数据库之间的...
Ibatis提供了多种方式来实现映射,如自动类型匹配、自定义类型处理器、复杂关联映射等。 7. **缓存机制**:Ibatis内置了本地缓存和二级缓存,可以提高数据读取速度。本地缓存作用于单个SqlSession,而二级缓存则...
标题 "ibatis类型" 暗示我们讨论的是关于iBATIS这个持久层框架的一些特定类型或组件。iBATIS是Java开发中的一个流行数据库访问框架,它允许开发者将SQL语句直接集成到XML配置文件中,实现了SQL与Java代码的分离,...
iBatis的插件机制允许用户自定义拦截器,实现对Executor、StatementHandler、ParameterHandler和ResultSetHandler四个关键组件的增强。源码中的`org.apache.ibatis.plugin.Interceptor`和`org.apache.ibatis.plugin....
4. **ResultMap**:定义了结果集如何映射到Java对象,支持复杂的列名到Java属性的映射,如一对一、一对多、多对多的关系映射。 5. **Transaction**:处理数据库事务,提供了开始、提交、回滚等操作。 **二、iBATIS...
### 经典开源插件之ibatis #### 概述 ibatis(现称为MyBatis)是一款优秀的持久层框架,它将SQL语句与Java代码分离,支持自定义SQL查询、存储过程以及高级映射等功能。ibatis的灵活性使得开发者能够通过简单的XML...
同时,它还支持简单类型、复杂类型(如Map或自定义对象)的参数传递。 3. 结果映射:通过`<resultMap>`标签,可以定义如何将查询结果映射到Java对象,包括一对一、一对多、多对一、自定义类型转换等多种映射方式。...
- 支持复杂类型:可以通过自定义类型处理器处理复杂的参数类型。 #### 6. ResultMap - **定义**: 结果映射定义了结果集中列名与对象属性之间的映射关系。 - **作用**: - 自动填充对象属性:根据结果集中的列名...
与Hibernate等其他ORM框架相比,iBATIS 更为简洁,上手速度更快,适合那些不需要复杂功能但又希望简化数据库访问的项目。 在快速入门iBATIS的过程中,首先要理解其基本概念。iBATIS通过XML配置文件来定义SQL语句与...
总结来说,iBatis提供了一种简单但强大的方式来管理数据库操作,通过XML配置文件,我们可以自定义SQL,控制事务,并实现对象与数据库记录之间的映射。这种灵活性使得iBatis成为J2EE开发中一个受欢迎的工具,尤其适用...
ibatIS代码生成插件是一款高效实用的开发工具,它主要应用于Java开发环境中,通过自动化的方式帮助开发者快速生成常见的CRUD(创建、读取、更新、删除)操作代码,极大地提高了开发效率。这款插件基于Abator框架,...
7. **结果映射**:iBATIS能自动将查询结果映射到Java对象,通过结果映射配置,可以指定字段与Java属性之间的映射关系,支持自定义类型处理器以处理复杂类型的映射。 8. **参数映射**:在调用SQL时,iBATIS可以自动...
9. **插件机制**:介绍iBatis的插件功能,如何自定义插件拦截SQL执行过程,实现如日志记录、性能分析等功能。 10. **缓存机制**:解析iBatis的缓存功能,包括本地缓存和二级缓存,如何配置和使用,以及缓存的生命...