mybatis详解

上一篇中,我写了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 &amp;==& 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 &amp;==& 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 &amp;==& 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别名
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
_StringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator
映射(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表,查询过后进行匹配到集合里面。

下一篇:mybatis之注解开发与逆向工程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值