上一篇中,我写了mybatis框架,以及基础用法,不了解的可以转至:mybatis基础
这篇我们继续上篇进行配置文件的详细讲解
XML的配置
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
> configuration(配置)
>> properties(属性)--重点
>> settings(设置)
>> typeAliases(类型别名)--重点
>> typeHandlers(类型处理器)
>> objectFactory(对象⼯⼚)
>> plugins(插件)
>> environments(环境配置)--重点
>>> environment(环境变量)
>>>> transactionManager(事务管理器)
>>>> dataSource(数据源)
>> databaseIdProvider(数据库⼚商标识)
>> mappers(映射器)
上面>
代表层次结构,我们再书写顺序时一定要遵循上面结构进行。
属性(properties)
properties可从配置⽂件或是properties标签中读取需要的参数,使得配置⽂件各个部分更加独⽴
内部properties标签
在mybatis-config.xml可以写属性标签,把一些需要更改的放在标签中即可,之前的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>
<!-- 定义的属性-->
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatisdb?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
<environments default="development">
<!-- 可配置多个环境 并指定默认使⽤的环境-->
<environment id="development">
<!-- 指定事务管理器-->
<transactionManager type="JDBC"/>
<!-- 指定数据源 就是数据来⾃哪⾥ 这⾥默认使⽤MyBatis⾃带的连接池-->
<dataSource type="POOLED">
<!--从属性里面取值用${}-->
<property name="driver" value="${driver}"/>
<!-- //表示本机localhost &==& xml中&需要转译-->
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 指定要加载的映射⽂件-->
<mappers>
<mapper resource="mapper/ProductsMapper.xml"/></mappers>
</configuration>
外部标签:
对于我们之前mybatis的mybatis-config.xml的文件,我们是把jdbc直接配置到xml文件中了,但是如果配置文件很多的话,在xml文件中就比较麻烦,对此我们可以建一个单独的文件,进行存储,使用属性标签从文件取值。
在resources下创建一个jdbc.properties
driver = com.mysql.jdbc.Driver
url = jdbc:mysql:///mybatisdb?characterEncoding=utf8
username = root
password = 123456
上面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>
<!-- 内部标签定义的属性-->
<!-- <properties>-->
<!-- <property name="driver" value="com.mysql.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql:///mybatisdb?characterEncoding=utf8"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="123456"/>-->
<!-- </properties>-->
<!-- 外部标签关联属性文件-->
<properties resource="jdbc.properties" />
<environments default="development">
<!-- 可配置多个环境 并指定默认使⽤的环境-->
<environment id="development">
<!-- 指定事务管理器-->
<transactionManager type="JDBC"/>
<!-- 指定数据源 就是数据来⾃哪⾥ 这⾥默认使⽤MyBatis⾃带的连接池-->
<dataSource type="POOLED">
<!--从属性里面取值用${}-->
<property name="driver" value="${driver}"/>
<!-- //表示本机localhost &==& xml中&需要转译-->
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 指定要加载的映射⽂件-->
<mappers>
<mapper resource="mapper/ProductsMapper.xml"/></mappers>
</configuration>
上面取值没有变,只是内部标签换成了关联外部文件。
别名(typeAliases)
typeAliases用于为Java的类型取别名,从而简化mapper中类名的书写,比如在mapper.xml中输出映射,要写包名加类名,如果很多的话会很麻烦,使用别名可以简化其书写,但是注意要按照上面的结构,typeAliases标签要在properties标签下面,书写顺序不能颠倒。
下面是给实体类取别名:
<?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>
<!-- 内部标签定义的属性-->
<!-- <properties>-->
<!-- <property name="driver" value="com.mysql.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql:///mybatisdb?characterEncoding=utf8"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="123456"/>-->
<!-- </properties>-->
<!-- 外部标签关联属性文件-->
<properties resource="jdbc.properties" />
<!-- 取别名的标签 注意顺序在properties 后面 type是类名 alias是取得别名 可以省略,省略后默认是类名,首字母不区分大小写-->
<typeAliases>
<typeAlias type="po.Product" alias="product"></typeAlias>
</typeAliases>
<environments default="development">
<!-- 可配置多个环境 并指定默认使⽤的环境-->
<environment id="development">
<!-- 指定事务管理器-->
<transactionManager type="JDBC"/>
<!-- 指定数据源 就是数据来⾃哪⾥ 这⾥默认使⽤MyBatis⾃带的连接池-->
<dataSource type="POOLED">
<!--从属性里面取值用${}-->
<property name="driver" value="${driver}"/>
<!-- //表示本机localhost &==& xml中&需要转译-->
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 指定要加载的映射⽂件-->
<mappers>
<mapper resource="mapper/ProductsMapper.xml"/>
</mappers>
</configuration>
摘取出来详细讲解:
<!--取别名的标签 注意顺序在properties 后面 type是类名 alias是取得别名 可以省略,省略后默认是类名,首字母不区分大小写-->
<typeAliases>
<typeAlias type="po.Product" alias="product"></typeAlias>
</typeAliases>
type:是对应类名
alias:alias是取得别名 可以省略,省略后默认是类名,首字母不区分大小写,在使用时可以写:product或Product
但是一般不这样写,如果实体类很多的话,这样配置很麻烦,我们可以直接扫描包:
<typeAliases>
<!-- 扫描包,都设置为类名,首字母不区分大小写-->
<package name="po"/>
</typeAliases>
上面两者用法一样,用法如下:
<?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">
<!--namespace ⽤于多个Mapper出现相同的sql时 区分不同包-->
<mapper namespace="mapper.ProductsMapper">
<!-- 通过id查询 #{}代表取值-->
<select id="selectById" parameterType="int" resultType="product">
select * from products where pid = #{pid}
</select>
<!-- 模糊查询 在字符串里取值就不能用#{} 而要用${}-->
<select id="selectByName" parameterType="String" resultType="Product">
select * from products where pname like "%${pname}%"
</select>
</mapper>
从上面 resultType
可以看出首字母不区分大小写
使用包扫描时,可能会有两个不同包下的类相同,这时可以采用注解解决:
//区分别名相同的类,设置为products1
@Alias("products1")
public class Products {
private int pid;
private String pname;
private float price;
private Date pdate;
private String cid;
}
注意:一定保证扫描到这个类的包,否则注解是无效的
下面列出MyBatis已存在的别名:
byte | 别名 |
---|---|
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
_String | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
映射(Mappers)
在mapper.xml文件中定义sql语句后,就必须让MyBatis知道,到哪里去找这些定义好的sql,这就需要在配置文件中指出要加载的mapper的位置;MyBatis支持4种方式来加载mapper文件:
1.指定资源文件的相对目录 相对于classpath,maven项目会自动将java和resources都添加到classpath中
<mappers>
<!-- 1.指定资源文件的相对目录 相对于classpath
maven项目会自动将java和resources都添加到classpath中
所以相对与resources来指定路径即可-->
<mapper resource="mapper/ProductsMapper.xml"/>
</mappers>
2.指定文件的绝对路径,MyBatis支持但是一般不用
<mappers>
<!-- 2.指定文件的绝对路径,MyBatis支持但是一般不用-->
<mapper url="file:///Users/jerry/Downloads/MYB/src/main/resources/mapper/ProductsMapper.xml"/>
</mappers>
3.通过指定接口 让MyBatis自动去查找对应的Mapper,这种方式要求映射文件和接口处于同一目录下,并且名称相同,要保证上述要求只需要在resources下创建于接口包名相同的目录即可
<mappers>
<!-- 3.通过指定接口 让MyBatis自动去查找对应的Mapper
这种方式要求映射文件和接口处于同一目录下,并且名称相同
要保证上述要求只需要在resources下创建于接口包名相同的目录即可
注意:运行前先clean,否则可能因为之前已经存在target而不会重新编译,导致无法加载新建的mapper文件
-->
<mapper class="com.yyh.mapper.ProductsMapper"/>
<!-- 4.指定包名称,扫描包下所有接口和映射文件
这种方式同样要求映射文件和接口处于同一目录下,并且名称相同-->
<package name="com.yyh.mapper"/>
</mappers>
注意:运行前先clean,否则可能因为之前已经存在target而不会重新编译,导致无法加载新建的mapper文件
4.指定包名称,扫描包下所有接口和映射文件,这种方式同样要求映射文件和接口处于同一目录下,并且名称相同
<mappers>
<!-- 4.指定包名称,扫描包下所有接口和映射文件
这种方式同样要求映射文件和接口处于同一目录下,并且名称相同-->
<package name="com.yyh.mapper"/>
</mappers>
注意:上面方法3和方法4,对于普通项目,我们可以把mapper.xml 和 接口 放在一个目录下,但是对于maven项目,我们可以把接口放在java下,把mapper.xml放在recources下,如果是单级目录,只需保证包名一致,即在Java和recources下创建同名的文件夹mapper, 如果是多级目录此时注意如果要保持目录一致,即在java我们可以创建时输入 一级目录.二级目录.三级目录
等,但是在recources下不可以这样创建,应该使用/
即:一级目录/二级目录/三级目录
,此处是因为在recources下会把点成文件名,创建一个包,而Java会当成分别包的符号,创建多级目录,虽然看着一样,但是结构不同。
包结构:
对于上面三个目录结构,java是 com.lbb.mapper
创建的他在本地是 com/lbb/mapper 三个文件夹; resources 标2的是 com.lbb.mapper
创建的,他在本地显示是一个文件夹,文件夹名为 com.lbb.mapper;resources 标3的是 com/lbb/mapper
创建的,他在本地是 com/lbb/mapper 三个文件夹
动态SQL
动态SQL指的是SQL语句不是固定死的,可以根据某些条件而发生相应的变化,这样的需求非常多见
例如:页面提供的搜索功能,要根据用户给出的一个或多个条件进行查询,查询条件不固定
在JDBC中,我们通过Java代码来判断某个条件是否有效然后拼接SQL语句,这是非常繁琐的,MyBatis的动态SQL很好的解决了这个问题,使判断逻辑变得简洁直观;
在Mapper中通过标签来完成动态SQL的生成
1. if
从页面接受参数后我们会将参数打包为对象,然后将对象作为参数传给MyBatis执行查询操作,sql语句需要根据是否存在参数而动态的生成
接口声明方法:
// 按条件查询
List<Product> selectByProduct(Product product);
mapper中:
<!-- 按条件查询-->
<select id="selectByProduct" parameterType="product" resultType="Product">
select * from products where 1=1
<if test="pid != null and pid != 0 ">
and pid = #{pid}
</if>
<if test="pname != null and pname != '' ">
and pname like "%${pname}%"
</if>
</select>
where 1=1
用于保持sql的正确性,当不存在条件时,则查询全部
测试:
@Test
public void selectByProductTest(){
//创建工厂创建类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//加载配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建会话工程
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(in);
try (SqlSession session = factory.openSession()) {
ProductsMapper mapper = session.getMapper(ProductsMapper.class);
Product product = new Product();
//按名字查询
// product.setPname("新疆");
// 按id查询
product.setPid(3);
List<Product> list = mapper.selectByProduct(product);
System.out.println(list);
}
}
2.where
where的作用就是用于取出上面的where 1=1,因为这会让人看起来产生疑惑,其作用是将内部语句中的第一个and去除
<!-- 按条件查询-->
<select id="selectByProduct" parameterType="product" resultType="Product">
select * from products
<where>
<if test="pid != null and pid != 0 ">
and pid = #{pid}
</if>
<if test="pname != null and pname != '' ">
and pname like "%${pname}%"
</if>
</where>
</select>
3. foreach
当一个条件中中需要需要多个参数时则需要将多个参数拼接到一起,例如: in, not in
接口声明方法:
//按ids查询
List<Product> selectById(List<Integer> ids);
mapper:
<?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">
<!--namespace ⽤于多个Mapper出现相同的sql时 区分不同包-->
<mapper namespace="mapper.ProductsMapper">
<!-- 通过id查询 #{}代表取值 参数是list 返回时List<product>-->
<select id="selectById" parameterType="list" resultType="product">
select * from products
<if test="list != null">
<!--遍历list-->
<foreach collection="list" item="id" open="where pid in (" close=")" separator=",">
#{id}
</foreach>
</if>
</select>
</mapper>
对于上面foreach标签:
foreache 标签属性说明:
强调:动态sql本质就是在拼接字符串,带着自己拼接sql的思路来编写动态sql会更好理解
collection 要遍历的集合
open 拼接的前缀
close 拼接的后缀
separator 拼接元素之间的分隔符
item 遍历得到的临时变量名
index 当前元素的索引(不常用)
测试:
@Test
public void secletByIdTest(){
//创建工厂创建类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//加载配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建会话工程
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(in);
try (SqlSession session = factory.openSession()) {
//不使用动态代理
//Product product = session.selectOne("selectById", 3);
//使用动态代理
ProductsMapper mapper = session.getMapper(ProductsMapper.class);
List<Integer> ids = new ArrayList<Integer>();
ids.add(2);
ids.add(3);
ids.add(4);
ids.add(20);
List<Product> list = mapper.selectById(ids);
System.out.println(list);
}
}
4. set
set标签用于更新语句,当同事要更新多个字段时,我们需要留意当前是否是最后一个set,避免在后面出现,符号,使用set标签后可自动去除最后的逗号
mapper:
<update id="updateProductTest" parameterType="products">
update products
<set>
<if test="pname != null and pname != ''">
pname = #{pname},
</if>
<if test="price != null and price > 0">
price = #{price},
</if>
<if test="pdate != null">
pdate = #{pdate},
</if>
<if test="cid != null and cid != ''">
cid = #{cid},
</if>
</set>
where pid = #{pid}
</update>
测试:
@Test
public void updateTest2(){
//创建工厂创建类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//加载配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建会话工程
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(in);
SqlSession session = factory.openSession();
ProductsMapper mapper = session.getMapper(ProductsMapper.class);
//获取已有对象
Products product = mapper.selectProductById(7);
product.setPname("云南小土豆");
product.setPrice(10.5f);
//执行更新
mapper.updateProductTest(product);
System.out.println(product);
session.commit();
session.close();
}
5. sql与include
Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。 例如可以吧sql语句中的字段列表提取出来作为通用的sql片段。然后在sql语句中使用 include 节点引用这个sql片段。
<?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">
<!--namespace ⽤于多个Mapper出现相同的sql时 区分不同包-->
<mapper namespace="mapper.ProductsMapper">
<!-- 模糊查询 sql片段-->
<sql id="sql_name">pid,pname,price,pdate,cid</sql>
<!-- 引用上面sql片段-->
<select id="selectByName" parameterType="String" resultType="Product">
select
<include refid="sql_name"></include>
from products where pname like "%${pname}%"
</select>
</mapper>
高级映射
在一些情况下数据库的记录和POJO对象无法直接映射,包括两种情形:
数据库字段与POJO字段名称不同(可以避免);
关联查询时,需要将关联表的数据映射为另一个类型的POJO(一对一),或List中(一对多);
在MyBatis中通过resultMap来完成自定义映射
1.自定义字段与属性映射
当数据库列名与自定义的映射对象的字段名不一样时,就可以使用resultMap来自定义映射关系,时期能够映射
比如:
数据库为:
对象类为:
public class Product {
private int pid; //id
private String pname; //名称
private double price; //价格
private Date pdate; //更新日期
private String cid; //分类
}
此时如果按上面那样直接返回类型写成Product类,因为字段不匹配,所以name会映射不上,这时候就可以按下面使用resultMap:
接口:
Product selectById(int id);
mapper:
<resultMap id="myresultMap" type="product" autoMapping="true">
<id column="pid" property="pid"/>
<result column="name" property="pname"/>
</resultMap>
<select id="selectById" parameterType="int" resultMap="myresultMap">
select * from products where pid = #{id}
</select>
注解:
select 标签里的 resultMap对应resultMap标签里id
resultMap 标签的type对应返回类型
autoMapping="true" 自动映射,如果列名与字段名一致,就会自动映射,不一致可以通过id标签与result标签进行映射
id标签:主键定义映射标签,注意要放在 result标签上面,column 数据库对应列名,property对应的对象字段名
result 普通属性定义标签,如果有id标签,放在id标签后面,column 数据库对应列名,property对应的对象字段名
2. 关联查询
关联关系
两个表之间记录的对应关系,分为一对一和一对多,而多对多则是三张表之间的关系,若掌握了两张表之间的一对多关系的处理,则多对多也就不是问题了,因为本质上多对多就是两个一对多组成的。
一对一关联查询
User类,关联的表对应的实体类:
public class User {
private int id;
private String username;
}
Product 查询的类
public class Product {
private int pid; //id
private String pname; //名称
private double price; //价格
private Date pdate; //更新日期
private String cid; //分类
private int user_id;
private User user; //关联的类
}
Product 类里面包含一个User类,我们要做的就是把对应的列名映射到User类中。
接口:
Product selectById(int id);
mapper:
<resultMap id="myresultMap" type="product" autoMapping="true">
<!--id取了别名,所以要映射一下,主键所以用id标签 列名是取得别名-->
<id column="pid" property="pid"/>
<result column="name" property="pname"/>
<!--关联的表 property 对应字段名 javaType映射类型-->
<association property="user" javaType="user" autoMapping="true">
<!--id取了别名,所以要映射一下,主键所以用id标签 列名是取得别名-->
<id column="uid" property="id"/>
</association>
</resultMap>
<select id="selectById" parameterType="int" resultMap="myresultMap">
<!--防止id重复,给id取别名-->
select * ,products.pid pid ,user.id uid
from products join user on products.user_id = user.id where pid = #{id}
</select>
注解:
association 一对一映射,映射到类中去
property 对应字段名
javaType映射类型
autoMapping="true" 自动映射开启
上面用法和普通映射一样,为了防止两个表的id名重复,所以在查询时取了别名,查询时采用的是内连接。
测试:
@Test
public void secletByIdTest(){
//创建工厂创建类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//加载配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建会话工程
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(in);
try (SqlSession session = factory.openSession()) {
//使用动态代理
ProductsMapper mapper = session.getMapper(ProductsMapper.class);
Product product = mapper.selectById(2);
System.out.println(product);
}
}
一对多映射:
需求:根据用户id查询用户的产品
产品类:
public class Product {
private int pid; //id
private String pname; //名称
private double price; //价格
private Date pdate; //更新日期
private String cid; //分类
private int user_id;
private User user; //关联的类
}
用户类:
public class User {
private int id;
private String username;
List<Product> list; //产品类
}
接口:
public interface UserMapper {
//查询某一用户的所有产品
User selectById(int id);
}
配置文件:
<?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="mapper.UserMapper">
<resultMap id="my_map" type="user" autoMapping="true">
<id column="uid" property="id"/>
<collection property="list" javaType="list" ofType="product" autoMapping="true">
<id column="pid" property="pid"/>
<result column="name" property="pname"/>
</collection>
</resultMap>
<select id="selectById" parameterType="int" resultMap="my_map">
SELECT *,products.pid pid,`user`.id uid
FROM `user` JOIN products ON `user`.id = products.user_id
WHERE user.id = #{id}
</select>
</mapper>
注解:
对于上面namespace对应接口 包名加类名
collection 映射一个集合,property 映射的集合名,ofType集合里面元素的类型,javaType定义集合类型
注意:无论如何在collection标签中必须至少存在一个手动映射字段否则,将不会合并重复的主记录,按照官方的说法,建议将手动映射id字段,可提高整体性能:官方文档
测试:
public class UserTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
//创建工厂创建类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//加载配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建会话工程
factory = sqlSessionFactoryBuilder.build(in);
}
@Test
public void Test(){
try (SqlSession session = factory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectById(1);
System.out.println(user);
}
}
}
嵌套映射,select
当关联查询非常复杂时,可以用嵌套的select,其原理是在映射复杂数据时执行另一个select来完成
上面查询可以写成下面形式:
<?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="mapper.UserMapper">
<resultMap id="my_map" type="user" autoMapping="true">
<!-- 指定嵌套查询 column是传给内层查询的参数 -->
<collection property="list" javaType="list" ofType="product" column="id" select="selectByUserId">
</collection>
</resultMap>
<!-- 外层查询-->
<select id="selectById" parameterType="int" resultMap="my_map">
SELECT * FROM `user` WHERE id = #{id}
</select>
<!-- 嵌套查询-->
<!--按照user的查询结果 查询产品表-->
<resultMap id="product_map" type="product" autoMapping="true">
<result column="name" property="pname"/>
</resultMap>
<select id="selectByUserId" parameterType="int" resultMap="product_map">
select * from products where user_id = #{id}
</select>
</mapper>
对于上面代码,先执行查询user表,查询之后返回user类,进行映射,映射时调用collection标签里的select 找到对应的标签,column是指定的参数,然后进行查询products表,查询过后进行匹配到集合里面。