Mybatis学习

Mybatis的工作原理

  • 读取Mybatis的配置文件:mybatis-config.xml为Mybatis的全局配置文件,配置了MyBatis的运行环境等信息。

  • 加载映射文件,也就是Sql映射文件,该文件中配置了操作数据库的相关的Sql语句,需要在Mybatis配置文件mybatis-config.xml中加载,可以加载多个映射文件,每个文件对应数据库中的一张表

  • 构造会话工厂:通过MyBatis的环境等配置信息构建会话工厂SqlSessionFactory

  • 创建会话对象:由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法

  • Executor执行器:MyBatis底层定义了一个Executor接口来操作数据库,他将根据SqlSession传递的参数动态地生成需要执行的Sql语句,同时负责查询缓存的维护

  • MappedStatement对象:在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息

  • 输入参数映射:映射类型可以是Map、List等集合类型,也可以是基本数据类型和pojo类型。类似于JDBC对preparedStatement对象设置参数的过程

  • 输出结果映射:输出结果类型可以是Map、List等集合类型。也可以是基本数据类型和pojo类型。类似于JDBC对结果集的解析过程

Mybatis的工作原理

创建mapper.xml,书写响应的查询语句

创建mybatis-config.xml通知mybatis在Spring中的配置文件在哪

创建dao包,放入我们所要的接口@Repository和@Mapper(标注的接口自动装配为MyBatis的映射接口)

创建controller包,书写方法控制程序运行

创建applicationContext.xml文件配置整个的整合流程

  1. 注解扫描包

  2. 配置dataSource,使用的是dbcp线程池

    1. 属性依次是我们的驱动类名,url,用户名,密码

    2. 最大连接数maxTotal,最大空闲书manxIdle,初始化连接数

  3. 添加声明式事务,创建一个bean的id为txManager的事务管理器

  4. 开通事务注解将txManager配入

  5. 创建SqlSessionFactory,放入来源dataSource对象,同时告诉xml文件,mybatis文件的位置(数据源)

  6. 扫描mapper组件,将SqlSessionFactory放入

完成,搭载测试类即可
 

 <!-- 扫描包注解 -->

        <context:component-scan base-package="com.dao"></context:component-scan>

        <context:component-scan base-package="com.controller"></context:component-scan>

        <!-- 配置数据源 -->

        <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">

         <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>

         <property name="url" value="jdbc:mysql://127.0.0.1:3306/springtest?serverTimezone=UTC "></property>

         <property name="username" value="root"></property>

         <property name="password" value="cao236476"></property>

         <!-- 最大连接数 -->

         <property name="maxTotal" value="30"></property>

         <!-- 最大空闲连接数 -->

         <property name="maxIdle" value="10"></property>

         <!-- 初始化连接数 -->

         <property name="initialSize" value="5"></property>

        </bean>

       

        <!-- 添加声明式事务 -->

        <!-- 声明 -->

        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

         <!-- 来源 -->

         <property name="dataSource" ref="dataSource"></property>

        </bean>

        <!-- 开启事务注解 -->

        <tx:annotation-driven transaction-manager="txManager"/>

        <!-- 配置MyBatis工厂,同时指定资源,并与Mybatis完美结合 -->

        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

         <property name="dataSource" ref="dataSource"></property>

         <!-- configLocation的属性值为Mybatis的核心配置文件 -->

         <property name="configLocation" value="classpath:com/mybatis/mybatis-config.xml"></property>

        </bean>

       

         <!-- Mapper代理开发,使用Spring自动扫描mybatis的接口并装配

        (Spring将指定包中@Mapper注解标注的接口自动装配为Mabatis的映射接口) -->

        <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">

         <property name="basePackage" value="com.dao"></property>

         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" ></property>

        </bean>

 

assocication元素属性分析:

  • property:指定映射到实体类的对象属性

  • column:指定表中的对应字段(即查询返回的列名)

  • javaType:指定映射到实体对象属性的类型

  • select:指定引入嵌套的子SQL语句,该属性用于关联映射中的嵌套查询

 一对一级联查询的三种方法:


<mapper namespace="com.dao.PersonDao">

<!--

    * property:指定映射到实体类的对象属性

    * column:指定表中的对应字段(即查询返回的列名)

    * javaType:指定映射到实体对象属性的类型

    * select:指定引入嵌套的子SQL语句,该属性用于关联映射中的嵌套查询

    id表示主键   result表示一般字段

 -->

    <!-- 

        先查询的是person,后查询idcard表。这里查询的是Person对象,Person对象中包含卡的消息,也就是通过查询Person是没有办法

        查询到Idcard对象的信息,所以使用resultMap输送数据,嵌套查询

        对应的card,对应person中的idcard_id,查询Idcard对象需要通过selectCodeById来

    -->

    <!-- 建立一对一查询,级联查询第一种方法(嵌套查询,执行两个sql语句) -->

    <resultMap type="com.mybatis.pojo.Person" id="cardAndPerson1">

        <id property="id" column="id"/>

        <result property="name" column="name"/>

        <result property="age" column="age"/>

        <association property="card" column="idcard_id" javaType="com.mybatis.pojo.Idcard"

        select="com.dao.IdcardDao.selectCodeById">

        </association>

    </resultMap>

    <!-- 这里才是主方法,查询的主方法,数据来自cardAndPerson -->

    <select id="selectPersonById1" parameterType="Integer" resultMap="cardAndPerson1">

        select * from person where id=#{id}

    </select>

    

    <!--

        嵌套结果查询,先联合查询,得到结果之后,在将表中字段和idcard字段的结果结合起来

        嵌套结果,组成最后的输出结果

     -->

    <!-- 一对一根据id查询个人信息,级联查询的第二种方法(嵌套结果,执行一个sql语句) -->

    <resultMap type="com.mybatis.pojo.Person" id="cardAndPerson2">

        <id property="id" column="id"/>

        <result property="name" column="name"/>

        <result property="age" column="age"/>

        <!-- 一对一级联查询 直接映射到结果 -->

        <association property="card" javaType="com.mybatis.pojo.Idcard">

            <id property="id" column="idcard_id"/>

            <result property="code" column="code"/>

        </association>

    </resultMap>

    <select id="selectPersonById2" parameterType="Integer" resultMap="cardAndPerson2">

        select p.*,ic.code

        from person p,idcard ic

        where p.idcard_id = ic.id and p.id=#{id}

    </select>

    <!--

        本次查询指定的SelectPersonById本身定义的时候就可以直接存储person+code

        所以输出的结果是person+code

     -->

    <!-- 一对一根据id查询个人信息:连接查询(使用pojo存储结果) -->

    <select id="selectPersonById3" parameterType="Integer" resultType="com.pojo.SelectPersonById">

        select p.*,ic.code

        from person p, idcard ic

        where  p.idcard_id = ic.id and p.id=#{id}

    </select>

</mapper>  

 其中的查询的结果,idcard的结果都是通过@Mapper映射过去的。

不管是一对一还是一对多都有三种查询方式

  • 嵌套查询(执行两次sql语句)

    • 一对一:

      • 使用的是<assocication property="" column="" javaType="" select=""/>

      • 其中property是对应的映射到实体类的属性

      • column是指定表中的对应的字段(列名,此列名一般是作为查询property的数据传入)

      • javaType对应映射到实体类的属性的类型(property中配置的是它(类)的内容)

      •  select指定引入嵌套的子SQL语句,该属性用于关联映射中的嵌套查询(用于第二次sql命令的执行)

      • sql语句是查询全部

    • 一对多:

      • 使用的是<collection property="" column="" ofType="" select=""/>

      • 其中property是对应的映射到实体类的属性

      • column是指定表中的对应的字段(列名,此列名一般是作为查询property的数据传入)

      • ofType对应映射到实体类的属性的类型(property中配置的是它(类)的内容)

      •  select指定引入嵌套的子SQL语句,该属性用于关联映射中的嵌套查询(用于第二次sql命令的执行)

      • sql语句是查询全部

 

  • 嵌套结果(执行一次sql语句)

    • 一对一:

      • 使用的是<association property="" javaType=""/>

      • property是对应的映射到实体类的属性

      • javaType是对应的映射到实体类的属性的类型(propert隶属于这个类)

      • 与一对一不同点,没有指定指定对应的表中的列名,采用了

      • <associcaton/><id property="" column=""/><result property="" column=""/>...(还有属性可以直接加result标签声明)<association>利用这个来直接映射到association的property中

      • sql语句是联合查询,根据指定的<assocication/><association>中配置的对应关系直接映射

    • 一对多:

      • 使用的是<collection property="" ofType=""/>

      • property是对应的映射到实体类的属性

      • ofType是对应的映射到实体类的属性的类型(propert隶属于这个类)

      • 与一对一不同点,没有指定指定对应的表中的列名,采用了

      • <associcaton/><id property="" column=""/><result property="" column=""/>...(还有属性可以直接加result标签声明)<association>利用这个来直接映射到association的property中

      • sql语句是联合查询,根据指定的<collection/><collection>中配置的对应关系直接映射

  • 使用pojo类存储结果(自定义一个pojo类存储需要的信息)

    • 自定义一个类,类中的属性是查询信息中这个pojo类中所需要的,查询语句执行完之后,直接根据定义的pojo类直接映射输出

具体实现:下面有代码分析

 <!-- 一对多查询 根据uid查询用户及其关联的订单信息:级联查询第一种方法(嵌套查询) -->

    <resultMap type="com.mybatis.pojo.MyUser" id="userAndOrders1">

        <id property="uid" column="uid"/>

        <result property="uname" column="uname"/>

        <result property="usex" column="usex"/>

        <!-- 一对多级联查询 ofType表示集合中的元素类型,将uid传递给selectOrdersById -->

        <collection property="ordersList" column="uid" ofType="com.mybatis.pojo.Orders"

        select="com.dao.OrdersDao.selectOrdersById"></collection>

    </resultMap>

    <select id="selectUserOrdersById1" parameterType="Integer" resultMap="userAndOrders1">

        select * from user where uid=#{id}

    </select>

    

    <!-- 一对多  根据uid查询用户及其关联的订单信息:级联查询第二种方法(嵌套结果)-->

    <resultMap type="com.mybatis.pojo.MyUser" id="userAndOrders2">

        <id property="uid" column="uid"/>

        <result property="uname" column="uname"/>

        <result property="usex" column="usex"/>

        <collection property="ordersList" ofType="com.mybatis.pojo.Orders">

            <id property="id" column="id"/>

            <result property="ordersn" column="ordersn"/>

        </collection>

    </resultMap>

    <select id="selectUserOrdersById2" parameterType="Integer" resultMap="userAndOrders2">

        select u.*,o.id,o.ordersn from user u, orders o where u.uid = o.user_id and u.uid=#{id}

    </select>

    

    <!-- 一对多  根据uid查询用户及其关联的订单信息:连接查询,使用pojo类存储数据 -->

    <select id="selectUserOrdersById3" parameterType="Integer" resultType="com.pojo.SelectUserOrdersById">

        select u.*,o.id,o.ordersn from user u, orders o where u.uid = o.user_id and u.uid=#{id}

    </select>

三种方式的结果集

DEBUG [main] - ==>  Preparing: select * from user where uid=?

DEBUG [main] - ==> Parameters: 1(Integer)

DEBUG [main] - <==      Total: 1

DEBUG [main] - ==>  Preparing: select * from orders where user_id = ?

DEBUG [main] - ==> Parameters: 1(Integer)

DEBUG [main] - <==      Total: 2

MyUser [uid=1, uname=哈哈哈, usex=女, ordersList=[Orders [id=1, ordersn=123456], Orders [id=6, ordersn=654321]]]

=============

DEBUG [main] - ==>  Preparing: select u.*,o.id,o.ordersn from user u, orders o where u.uid = o.user_id and u.uid = ?

DEBUG [main] - ==> Parameters: 1(Integer)

DEBUG [main] - <==      Total: 2

MyUser [uid=1, uname=哈哈哈, usex=女, ordersList=[Orders [id=1, ordersn=123456], Orders [id=6, ordersn=654321]]]

==============

DEBUG [main] - ==>  Preparing: select u.*,o.id,o.ordersn from user u, orders o where u.uid = o.user_id and u.uid=?

DEBUG [main] - ==> Parameters: 1(Integer)

DEBUG [main] - <==      Total: 2

[SelectUserOrdersById [uid=1, uname=哈哈哈, usex=女, id=1, ordersn=123456], SelectUserOrdersById [uid=1, uname=哈哈哈, usex=女, id=6, ordersn=654321]]

多对多的级联查询

场景:一个订单可以有多个产品,用产品细节表将这二者联合起来

建立orders_detail表,表中保存orders_id,product_id,需要查询的是订单中的产品数,一个订单中的产品是多个的,所以可以使用多对多级联查询,具体实现如下 

<resultMap type="com.mybatis.pojo.Orders" id="ordersAndProduct">

        <id property="id" column="id"/>

        <result property="ordersn" column="ordersn"/>

        <!-- 第三个属性提供了 所以使用一对多 -->

        <collection property="products"  ofType="com.mybatis.pojo.Product">

            <id property="id" column="pid"/>

            <result property="name" column="name"/>

            <result property="price" column="price"/>

        </collection>

    </resultMap>

    <select id="selectOrdersProduct" parameterType="Integer" resultMap="ordersAndProduct">

        select o.*,p.id as pid, p.name,p.price from orders o, orders_detail od, product p

        where od.orders_id = o.id and od.product_id = p.id

    </select>

这里需要注意的是在传值的时候,使用的别名也需要使用别名来传递,在上面的代码中,products中的id需要传入的是产品的id,可是产品的id被去了别名pid,所以在column中需要使用pid传入,以便映射传值,注意直接p.id传入,打印出的结果产品id会显示null

  

小结:

MyBatis实现查询时返回的结果集有哪几种常见的存储方式:

  • Map存储结果集,任何select语句都可以使用Map存储结果

  • 使用pojo存储结果集(常用),因为使用pojo一方面可以使用自动映射,有resultType属性,更为复杂的级联,一对一,一对多,多对多等,需要使用resultMap属性配置映射集合。

MyBatis中如何给SQL语句传递参数?

利用#{参数名} 在parameterType是int时,sql语句中必须是#{},防注入

利用${参数名}是什么就输出什么

CRUD是 Create(创建)、Read(读取)、Update(更新)和Delete(删除)的缩写。

 

动态SQL

  • <if>元素

  • <choose>,<when>,<otherwise>元素,类似于switch

  • <trim>

    • trim元素中可以加上前缀prefix和后缀suffix

    • 也可忽略前缀prefixOverrides和后缀suffixOverrides,可以设置前缀为where来代替where标签

  • <where>元素

    • 使用标签不用写where,直接忽视第一条语句中的and

  • <set>元素

    • <set></set>中写判断条件以及要更新列名及值,后面写set条件where xx=xx

  • <foreach>元素

    • 有多个属性

    • item:迭代的别名;index:指定一个名字,表示迭代过程中每次迭代到的位置

    • open表示语句以什么开始,separator表示每次迭代之间以什么符号作为分隔符

    • close表示语句以什么结束,最终要的是collection传入要执行的参数的类型(List array Map等)

  • <bind>元素

    • 模糊查询,属性name表示执行sql所用的值来源(真实值),value表示满足条件的所有的模糊查询中获得的数据

部分标签例子:

<!-- 使用if元素根据条件动态查询用户信息 -->

    <select id="selectUserByIf" parameterType="com.mybatis.pojo.MyUser" resultType="com.mybatis.pojo.MyUser">

        select * from user where 1=1

        <if test="uname!=null and uname!=''">

            and uname like concat('%',#{uname},'%')

        </if>

        <if test="usex!=null and usex!=''">

            and usex=#{usex}

        </if>

    </select>

    <!-- 使用choose元素 -->

    <select id="selectUserByChoose" parameterType="com.mybatis.pojo.MyUser" resultType="com.mybatis.pojo.MyUser">

        select * from user where 1=1

        <choose>

            <when test="uname!=null and uname!=''">

                and uname like concat('%',#{uname},'%')

            </when>

            <when test="usex!=null and usex!=''">

                and usex=#{usex}

            </when>

            <otherwise>

                and uid>10

            </otherwise>

        </choose>

    </select>

    <!-- 使用foreach元素 -->

    <select id="selectUserByForeach" resultType="com.mybatis.pojo.MyUser" parameterType="List">

        select * from user where uid in

        <foreach item="item" index="index" collection="list" open="(" separator="," close=")">

            #{item}

        </foreach>

    </select>

    <!-- 使用bind模糊查询 -->

    <select id="selectUserByBind" parameterType="com.mybatis.pojo.MyUser" resultType="com.mybatis.pojo.MyUser">

        <bind name="paran_uname" value="'%'+uname+'%'"/>

        select * from user where uname like #{paran_uname}

    </select>

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值