mybatis相关知识点

映射文件的相关属性

namespace命名空间

作用: 对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用

<!-- 需求:通过id查询用户表的记录 -->
<select id="findUserById" parameterType="int" resultType="com.chaychan.mybatis.po.User">
    SELECT * FROM USER WHERE id=#{value}
</select>

上面代码的解释

id:标识映射文件中的 sql,将sql语句封装到mappedStatement对象中,所以将id称为statement的id

parameterType:指定输入 参数的类型,这里指定int型

resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。

“#{}” 表示一个占位符号

“#{id}” 其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称.

${}的使用

<!-- 通过用户的名称模糊搜索用户,搜索的结果可能有多条   resultType指定就是单条记录所映射的java对象
     ${}表示拼接sql串,将接收到的内容不加任何修饰拼接在sql中
               使用${}拼接sql,会引起sql注入,比如传入的字符串是sql指令(有一定的风险)
     ${value}:接收输入的内容,如果传入的类型是简单类型,${}中只能用value
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.chaychan.mybatis.po.User">
  SELECT * FROM USER WHERE USERNAME LIKE '%${value}%';
</select>

以上的模糊搜索会引起sql注入,所以还是使用下面的代码

<select id="findUserByName" parameterType="java.lang.String" resultType="com.chaychan.mybatis.po.User">
  <!-- SELECT * FROM USER WHERE USERNAME LIKE '%${value}%';  
 为了防止sql注入,所以采用下面的方式--> 
  SELECT * FROM USER WHERE USERNAME LIKE #{value};
</select>

代码中传入参数替代占位符

List<User> list = sqlSession.selectList("test.findUserByName","%小明%");

插入数据

 <!-- 添加用户
     parameterType:指定输入参数的类型为pojo(包含用户信息)
     #{}指定pojo的属性名,就可以接收到相应的属性值,mybatis是通过OGNL获取属性值
 -->
<insert id="insertUser" parameterType="com.chaychan.mybatis.po.User">
    insert into user(username,birthday,sex,address) 
    value(#{username},#{birthday},#{sex},#{address})
</insert>

插入数据后拿到自增长的主键的值

<insert id="insertUser" parameterType="com.chaychan.mybatis.po.User">
     <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
              SELECT LAST_INSERT_ID()
     </selectKey>
    insert into user(username,birthday,sex,address) 
    value(#{username},#{birthday},#{sex},#{address})
</insert>

以上代码的解释

SELECT LAST_INSERT_ID(): 得到刚 insert进去记录的主键值,只适用于自增长主键
keyProperty: 将查询到的主键值设置到parameterType对应的对象的哪个属性中,上述代码是将主键值设置到User对象的id属性中
order: SELECT LAST_INSERT_ID()的执行顺序,相对于insert来说的顺序
resultType: 指定SELECT LAST_INSERT_ID()的结果类型

在插入数据之前通过mysql的uuid()生成主键,然后再将其作为主键值插入

使用mysql的uuid()生成主键
执行过程:
首先通过uuid()得到主键,将主键设置到user对象的id属性中
其次在insert执行时,从user对象中取出id属性值

<insert id="insertUser" parameterType="com.chaychan.mybatis.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
      SELECT uuid()
</selectKey>
    insert into user(id,username,birthday,sex,address) 
    value(#{id},#{username},#{birthday},#{sex},#{address})
 </insert>

mapper的编写

程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类的代理对象
开发规范:
1.在mapper.xml中的namespace等于mapper接口的类的全路径

<mapper namespace="com.chaychan.mybatis.mapper.UserMapper">  

2.mapper.java接口中的方法名要和mapper.xml中statement的id一致
3.mapper.java接口中的方法的输入参数类型要和mapper.xml中statement的parameterType指定的类型一致
4.mapper.java接口中的方法返回值类型要和mapper.xml中statement的resultType指定的类型一致

如mapper.xml中代码:

<select id="findUserById" parameterType="int" resultType="com.chaychan.mybatis.po.User">
    SELECT * FROM USER WHERE id=#{value}
</select>   

mapper接口中的方法:

/**根据id查找用户信息*/
public User findUserById(int id) throws Exception;

定义别名

单个别名的定义

SqlMapConfig.xml中配置User对象全路径对应的别名为user

<!-- 定义别名 -->
<typeAliases>
    <!--单个别名的定义-->
   <typeAlias type="com.chaychan.mybatis.po.User" alias="user"/>
</typeAliases>

mapper.xml中只需使用别名user:

<select id="findUserById" parameterType="int" resultType="user">
    SELECT * FROM USER WHERE id=#{value}
</select>

批量别名的定义

SqlMapConfig.xml中配置要包名

<!-- 定义别名 -->
<typeAliases>
     <!-- 批量别名的定义
          指定包名,mybatis就会自动扫描包中的po类,自动定义别名,别名为类名(首字母大小写都可以)
      -->
     <package name="com.chaychan.mybatis.po"/>

</typeAliases>

加载映射文件

单个加载映射文件,通过mapper接口加载映射文件

批量加载映射文件,指定mapper接口所在的包名,mybatis会自动加载mapper接口

两种方法都要遵循一定的规范:需要将mapper接口的类名和mapper.xml映射文件名保持一致,且放在同一个目录下

<!-- 加载 映射文件 -->
<mappers>
    <mapper resource="sqlmap/User.xml"/>
    <!-- <mapper resource="mapper/UserMapper.xml"/> -->
    <!-- 单个加载映射文件,通过mapper接口加载映射文件
     遵循一定的规范:需要将mapper接口的类名和mapper.xml映射文件名保持一致,且放在同一个目录下
     -->
    <!-- <mapper class="com.chaychan.mybatis.mapper.UserMapper"/> -->

    <!-- 
           批量加载映射文件 
           指定mapper接口所在的包名,mybatis会自动加载mapper接口
           遵循一定的规范:需要将mapper接口的类名和mapper.xml映射文件名保持一致,且放在同一个目录下
    -->
    <package name="com.chaychan.mybatis.mapper"/>
</mappers>

reusltMap入门

<!-- 定义resultMap
将SELECT id id_,username username_ FROM USER 和User类中的属性作一个映射关系

type:resultMap最终映射的java对象类型,可以使用别名
id:对resultMap的唯一标识
 -->
 <resultMap type="user" id="userResultMap">
    <!-- id表示查询结果集中唯一标识 
    column:查询出来的列名
    property:type指定的pojo类型中的属性名
    最终resultMap对column和property作一个映射关系 (对应关系)
    -->
    <id column="id_" property="id"/>
    <!-- 
    result:对普通名映射定义
    column:查询出来的列名
    property:type指定的pojo类型中的属性名
    最终resultMap对column和property作一个映射关系 (对应关系)
     -->
    <result column="username_" property="username"/>

 </resultMap>

<!-- 使用resultMap进行输出映射
resultMap:指定定义的resultMap的id,如果这个resultMap在其它的mapper文件,前边需要加namespace
-->
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
    SELECT id id_,username username_ FROM USER WHERE id=#{value}
</select>

定义sql片段

<!-- 定义sql片段
id:sql片段的唯 一标识

经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高
在sql片段中不要包括 where
 -->
<sql id="user_query_where">
   <if test="userCustom != null">
           <if test="userCustom.sex != null and userCustom.sex != ''">
               and sex = #{userCustom.sex}
           </if>
           <if test="userCustom.username != null and userCustom.username != ''">
               and username like '%${userCustom.username}%'
           </if>
  </if>
</sql>

引用sql片段

<select id="findUserList" parameterType="userQueryVo" resultType="userCustom">
    select * from user 
    <where>
      <include refid="user_query_where" />
    </where>
 </select>

foreach的使用

 <if test="ids != null">
               <!-- 使用 foreach遍历传入ids
                   使用实现下边的sql拼接:
                  AND (id=1 OR id=10 OR id=16) 
                -->
                <foreach collection="ids" item="item_id" 
                      open="AND (" close=")" separator="OR">

                     id=#{item_id}

                </foreach> 

                 <!-- 使用实现下边的sql拼接:
                  AND id in(1,10,16) 
                  -->
                <foreach collection="ids" item="item_id" 
                    open="AND id in(" close=")" separator=",">

                   #{item_id}

                </foreach>
 </if>

collection:指定输入对象中集合属性
item:每个遍历生成对象中
open:开始遍历时拼接的串
close:结束遍历时拼接的串
separator:遍历的两个对象中需要拼接的串

延迟加载

sqlConfig.xml中配置开启延迟加载

<!-- 全局配置参数,需要时再设置 -->
<settings>
    <!-- 打开延迟加载 的开关 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 将积极加载改为消极加载即按需要加载 -->
    <setting name="aggressiveLazyLoading" value="false"/>
    <!-- 开启二级缓存 -->
    <!-- <setting name="cacheEnabled" value="true"/> -->
</settings>

定义一个延迟加载的mapper,如查询订单的时候,延迟加载用户信息,因为orders表中的user_id关联user表的id,当需要获取user对象的时候,就会执行延迟加载。
相当于两步:
1.先查询orders表获取到订单;
2.根据订单对象中user_id查找出相关的user对象

<!-- 延迟加载的resultMap -->
<resultMap type="com.chaychan.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
    <!--对订单信息进行映射配置 -->
    <id column="id" property="id" />
    <result column="user_id" property="userId" />
    <result column="number" property="number" />
    <result column="createtime" property="createtime" />
    <result column="note" property="note" />

    <!-- 实现对用户信息进行延迟加载
        select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement)
        要使用userMapper.xml中findUserById完成根据用户id(user_id)用户信息的查询,如果findUserById不在本mapper中需要前边加namespace
        column:订单信息中关联用户信息查询的列,是user_id
        关联查询的sql理解为:
        SELECT orders.*,
        (SELECT username FROM USER WHERE orders.user_id = user.id)username,
        (SELECT sex FROM USER WHERE orders.user_id = user.id)sex
         FROM orders
         -->
   <association property="user" javaType="com.chaychan.mybatis.po.User" column="user_id"
    select="com.chaychan.mybatis.mapper.UserMapper.findUserById"
   ></association>

</resultMap>

<!-- 查询订单关联查询用户,用户信息需要延迟加载 -->
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
    SELECT * FROM orders
</select>

测试代码

List<Orders> list = ordersMapperCustom.findOrdersUserLazyLoading();

    for (Orders orders : list) {
        User user = orders.getUser();
        System.out.println(user);
    }

当获取list的时候,控制台会输入查找orders表的sql语句,当orders对象调用getUser()方法的时候,控制台会输出根据id查找用户的sql语句。

查询缓存

一级缓存是sqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据,不同的sqlSession之间的缓存数据区域(HashMap)是互不影响的。

二级缓存是mapper级别的缓存,多个sqlSession去操作同一个Mapper中的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。

为什么要用缓存?如果缓存中有数据,就不用到数据库中去查找,大大提高系统的性能。

一级缓存的原理

例子:

第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户的信息,如果没有,从数据查询用户信息。得到用户信息后,存储在以及缓存中。

如果sqlSession去执行commit操作(执行插入、更新、删除),将清空sqlSession中的一级缓存,这样做的目的是为了让缓存中存储的是最新的信息,避免脏读。

第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户的信息,缓存中有,直接从缓存中获取用户信息。

二级缓存

mybatis默认开启一级缓存,如果要开启二级缓存,需要在xml中进行配置

原理:

sqlSession1去查询用户id为1的用户信息,查询到用户信息后将数据存储到二级缓存中。

sqlSession2去查询用户id为1的用户信息时,先去缓存中查找,如果存在则直接取出数据。

二级缓存和一级缓存的区别,二级缓存的范围更大,多个sqlSession可以共享一个Mapper的二级缓存区域,不如UserMapper有自己的二级缓存区域,其他mapper也有对应的二级缓存区域,按namespace区分。即每一个namespace的mapper有一个二级缓存区域。

如果两个mapper的namespace相同,这两个mapper执行sql查询到的数据将存在相同的二级缓存区域中。

整合ehcache

配置mapper中cache中的type为ehcache对cache接口的实现类

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

导入mybatis-ehcache-1.0.2.jar,ehcache-core-2.6.5.jar

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值