数据库I/O可以很好的度量数据库的使用情况,同时也是影响数据库性能的主要瓶颈之一。数据从磁盘到内存或则从内容写到磁盘这种操作时非常耗时。高速缓存能很好的应到到这一问题来提高性能。
N+1问题是由于试图加载和父记录相关的子记录而造成的。当如果你已经获取一个父记录时,若想获得所有的这个父记录的子记录时,你需要多执行N个查询,为了把子记录查询出来。
延迟加载将加载分层了更小的易管理的小过程,只有在需要的时候才会加载额外的数据。这样很好解决了数据库I/O问题,但它导致了N+1问题。数据库I/O和N+1问题两个问题必有其一。这往往要考虑到实际的需要来决定采用哪个策略。
iBATIA延迟加载
Person 可以有多个Address。
package com.min.ibatis.model;
import java.util.List;
public class Person {
private int id;
private String name;
private List<Address> addresses;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Address> getAddresses() {
return addresses;
}
public void setAddresses(List<Address> addresses) {
this.addresses = addresses;
}
}
package com.min.ibatis.model;
public class Address {
private int id;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
iBATIS的sql映射配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>
<typeAlias alias="Person" type="com.min.ibatis.model.Person"/>
<typeAlias alias="Address" type="com.min.ibatis.model.Address"/>
<resultMap class="Person" id="personMap">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="addresses" select="getAddresses" column="id"/>
</resultMap>
<resultMap class="Address" id="addressMap">
<result property="id" column="id"/>
<result property="address" column="address"/>
</resultMap>
<select id="getAddresses" resultMap="addressMap">
select * from address where personId=#value#
</select>
<select id="getPerson" resultMap="personMap">
select * from person where id = #value#
</select>
</sqlMap>
测试类
package com.min.ibatis.model;
import java.io.Reader;
import java.sql.SQLException;
import junit.framework.TestCase;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
public class Test extends TestCase {
private SqlMapClient sqlMap;
@Override
protected void setUp() throws Exception {
String resource = "SqlMapConfig.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
}
public void testLoadLazy(){
int id = 1;
try {
Person person = (Person)sqlMap.queryForObject("getPerson",id);
System.out.println(person.getName());
Address address = person.getAddresses().get(0);
System.out.println(address.getAddress());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
默认情况下,SqlMapConfig.xml中
<settings lazyLoadingEnabled="true" enhancementEnabled="true"/>
enhancementEnabled="true" 说明使用延迟加载cglib增强版。 只需加入cglib.jar包就可以了。
通过debug,我们发现 person的addresses属性引用的是代理类。
避免N+1查询问题
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>
<typeAlias alias="Person" type="com.min.ibatis.model.Person"/>
<typeAlias alias="Address" type="com.min.ibatis.model.Address"/>
<resultMap class="Person" id="personMap" groupBy="id">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="addresses" resultMap="addressMap"/>
</resultMap>
<resultMap class="Address" id="addressMap">
<result property="id" column="id"/>
<result property="address" column="address"/>
</resultMap>
<select id="getPerson" resultMap="personMap">
select * from person join address on person.id = address.personId
</select>
</sqlMap>
延迟加载适用于大型的但并非所有的数据都有用的那些数据集。
避免N+1查询方案使用于小型的或则所有的数据都会被使用的那些数据集。
参考:iBATIS in action
分享到:
相关推荐
"ibatis解决多对一n+1问题"这个主题聚焦于MyBatis框架中如何高效地处理多对一关联查询,避免出现性能瓶颈的“n+1”问题。这个问题通常发生在查询一对多关系时,如果不对查询进行优化,会导致大量的额外数据库访问,...
但是,如果在循环中访问关联数据,延迟加载反而会导致N+1问题,因此需要谨慎使用。 4. **子查询或子集合映射(Subquery or Subcollection Mapping)**: 在映射文件中,可以使用子查询来获取关联数据,这样在原始...
综上所述,解决iBATIS中的N+1选择问题需要结合业务场景和数据库设计,选择合适的策略进行优化。通过合理地使用批处理、联合查询、预加载、缓存等方法,我们可以显著提升系统的性能和响应速度。在实践中,还需要注意...
但 iBATIS 提供了两种方式来处理关联查询:N+1 次查询和新的查询方式。 1. **N+1 次查询** 这种方式在 SQL 映射文件中通过 `select` 属性指定一个单独的查询语句。虽然这种方法会导致额外的数据库读取操作,但可以...
- **避免 N+1 Select(1:M 和 M:N)**:进一步讲解如何优化多对多查询。 - **组合键值或多个复杂参数属性**:当一个参数由多个属性组成时的处理方法。 - **支持 ParameterMap 和 ResultMap 的数据类型**:详细...
6.2.3 避免N+1查询问题 105 6.3 继承 107 6.4 其他用途 109 6.4.1 使用语句类型和DDL 109 6.4.2 处理超大型数据集 109 6.5 小结 115 第7章 事务 116 7.1 事务是什么 116 7.1.1 一个简单的银行转账示例 116 7.1.2 ...
- **避免 N+1 Select**:通过联合查询等方式优化查询性能。 - **延迟加载 VS 联合查询**:选择合适的查询策略以提高效率。 - **复杂类型集合的属性**:处理复杂类型集合的映射。 - **组合键值或多个复杂参数属性**:...
- **避免N+1 Select(1:M和M:N)**:进一步优化多对多关系的查询效率。 - **组合键值或多个复杂参数属性**:支持同时传递多个参数或组合键值。 - **支持ParameterMap和ResultMap的数据类型**:提供了广泛的类型支持...
- **3.4.9 避免N+1查询(一对多或多对多)** - 使用关联查询或子查询来减少查询次数。 - **3.4.10 组合键或多个复杂参数属性** - 可以通过组合多个属性来映射复合主键或复杂参数。 - **3.5 支持的参数映射和...
- **避免 N+1 Select**:通过适当的缓存策略和联合查询优化,减少不必要的数据库查询次数。 - **延迟加载与联合查询**:权衡查询效率与内存消耗,选择合适的加载策略。 #### 六、缓存机制 - **只读与可读写缓存**...
在JavaEE开发中,ORM(Object-Relational Mapping,对象关系映射)框架是...在处理大数据量或复杂业务逻辑时,还需注意优化查询,避免N+1查询问题,以及注意事务隔离级别和并发控制,确保系统的稳定性和数据的一致性。
- **load**:延迟加载对象,如果找不到记录,则返回null。 ##### Hibernate、Ibatis、Jdbc三者的区别 - **Hibernate**:全ORM解决方案,自动管理对象的生命周期。 - **MyBatis (原Ibatis)**:半ORM框架,提供动态...
1. 属性配置文件(如`sqlMapConfig.xml`),用于设置全局属性,如延迟加载(lazyLoadingEnabled)等。 2. DAO配置文件(映射文件),定义SQL语句、参数类型和返回结果映射。这包括一对一、一对多和多对多的关联映射...