2016-11-30 78 views
1

假設我有以下DTO類:的MyBatis - 獲取屬性列表的對象列表

class Item { 
    int id; 
    List<Detail> details; 

    @Override 
    public String toString() { 
     return "{id: " + id + ", details: " + details + "}"; 
    } 
} 

class Detail { 
    String name; 
    String value; 

    @Override 
    public String toString() { 
     return "{" + name + ": " + value + "}"; 
    } 
} 

是否有可能寫一個XML映射檢索與正確填寫詳細資料和所有數據的列表會用兩個查詢檢索(第一個項目,第二個細節)。在下面的例子中將會有N + 1個查詢(N個項目)。

完整示例(對於示例模式,測試數據和使用)
Sandbox.java:

import org.apache.ibatis.io.Resources; 
import org.apache.ibatis.session.*; 

import java.sql.*; 
import java.sql.Statement; 
import java.util.List; 

public class Sandbox { 
    public static void main(String... args) throws Throwable { 
     try (Connection connection = DriverManager.getConnection("jdbc:sqlite:sample.db")) { 
      try (Statement statement = connection.createStatement()) { 
       statement.executeUpdate("drop table if exists Item"); 
       statement.executeUpdate("create table Item (id integer)"); 


       statement.executeUpdate("insert into Item values(1)"); 
       statement.executeUpdate("insert into Item values(2)"); 

       statement.executeUpdate("drop table if exists Detail"); 
       statement.executeUpdate("create table Detail (id integer, name string, value string)"); 

       statement.executeUpdate("insert into Detail values(1, 'name', 'foo')"); 
       statement.executeUpdate("insert into Detail values(1, 'purpose', 'test')"); 
       statement.executeUpdate("insert into Detail values(2, 'name', 'bar')"); 
      } 
     } 

     SqlSessionFactory sqlSessionFactory = 
       new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")); 

     try (SqlSession session = sqlSessionFactory.openSession()) { 
      MyMapper mapper = session.getMapper(MyMapper.class); 
      List<Item> items = mapper.selectItems(); 

      System.out.println("items = " + items); 
     } 
    } 
} 

MyMapper.java:

import java.util.List; 

public interface MyMapper { 
    List<Item> selectItems(); 
} 

Mapper.xml:

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper 
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
<mapper namespace="MyMapper"> 
    <resultMap id="ItemMap" type="Item"> 
     <id column="id" property="id"/> 
     <collection column="id" property="details" select="selectDetails"/> 
    </resultMap> 

    <select id="selectItems" resultMap="ItemMap"> 
     select * from Item 
    </select> 

    <select id="selectDetails" parameterType="int" resultType="Detail"> 
     select * from Detail WHERE id=#{id} 
    </select> 
</mapper> 

mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE configuration 
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
     "http://mybatis.org/dtd/mybatis-3-config.dtd"> 
<configuration> 
    <environments default="development"> 
     <environment id="development"> 
      <transactionManager type="JDBC"/> 
      <dataSource type="POOLED"> 
       <property name="driver" value="net.sf.log4jdbc.DriverSpy"/> 
       <property name="url" value="jdbc:log4jdbc:sqlite:sample.db"/> 
      </dataSource> 
     </environment> 
    </environments> 
    <mappers> 
     <mapper resource="Mapper.xml"/> 
    </mappers> 
</configuration> 

的pom.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>ru.urururu</groupId> 
    <artifactId>mybatis-batching</artifactId> 
    <version>1.0-SNAPSHOT</version> 

    <dependencies> 
     <dependency> 
      <groupId>org.mybatis</groupId> 
      <artifactId>mybatis</artifactId> 
      <version>3.4.0</version> 
     </dependency> 

     <dependency> 
      <groupId>org.xerial</groupId> 
      <artifactId>sqlite-jdbc</artifactId> 
      <version>3.15.1</version> 
     </dependency> 

     <dependency> 
      <groupId>com.googlecode.log4jdbc</groupId> 
      <artifactId>log4jdbc</artifactId> 
      <version>1.2</version> 
     </dependency> 

     <dependency> 
      <groupId>org.slf4j</groupId> 
      <artifactId>slf4j-simple</artifactId> 
      <version>1.7.21</version> 
     </dependency> 
    </dependencies> 
    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-compiler-plugin</artifactId> 
       <version>3.6.0</version> 
       <configuration> 
        <source>1.8</source> 
        <target>1.8</target> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

回答

1

如果你看一看部分Multiple ResultSets for Association映射器的參考文檔中解釋的XML

從3.2.3版本開始MyBatis提供了另一種解決N + 1問題的方法。

某些數據庫允許存儲過程返回多個 結果集或一次執行多個語句,併爲每個語句返回 結果集。這可以用來僅擊中數據庫一次 並返回相關數據而不使用連接。

有一個這樣的例子。所以,你會需要查詢的存儲過程:

select * from Item 
select * from Detail WHERE id=#{id} 

然後選擇將調用爲未來的存儲過程:

<select id="selectItems" resultSets="item,details" resultMap="ItemMap"> 
    {call getItemAndDetails(#{id,jdbcType=INTEGER,mode=IN})} 
</select> 

最後的結果映射:

指定的「詳細信息「收集將填寫名爲」詳細信息「的結果集中包含的數據。

在結果地圖10

您的收藏標籤也會是在明年:

<collection property="details" ofType="Detail" resultSet="details" column="id" foreignColumn="foreign_id"> 
+0

這所需要的就是我,但我相信你已經誤認爲與resultType =「項目,詳細信息」,應該是結果集=「項目,細節」。 – okutane

+0

是的,你是對的;) – Pau

+0

你知道如何在2個選擇中做到這一點(如果驅動程序不支持多個結果集)? – okutane