mybatis总结归纳

{ } 和 ${ } 的区别

#{ }表示一个占位符号,通过#{ }可以实现 preparedStatement 向占位符中设置值,自动进行java 类型和 jdbc 类型转换, 
  #{ } 可以有效防止sql注入。#{ } 可以接收简单类型值或 pojo 属性值(通过 OGNL 读取对象中的值,属性.属性.属性..方式获取对象属性值)。 如果 parameterType 传输单个简单类型值,#{ }括号中可以是 value 或其它名称。

{ }可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, {}括号中只能是 value。

parameterType 和 resultType 区别

parameterType:指定输入参数类型,mybatis 通过 ognl 从输入对象中获取参数值拼接在 sql 中。
resultType:指定输出结果类型,mybatis 将 sql 查询结果的一行记录数据映射为 resultType 指定类型的对象。

SqlMapConfig.xml 文件
Mybatis 的全局配置变量,配置内容和顺序如下:

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

​ environment(环境子属性对象)

​ transactionManager(事务管理)

​ dataSource(数据源)

mappers(映射器)

properties 属性
需求:将数据库连接参数单独配置在 db.properties 中,只需要在 SqlMapConfig.xml 中加载该配置文件 db.properties 的属性值。在 SqlMapConfig.xml 中就不需要直接对数据库的连接参数进行硬编码了。方便以后对参数进行统一的管理,其他的xml文件可以引用该 db.properties 。

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_test?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
那么 SqlMapConfig.xml 中的配置变成如下:

<!--加载配置文件-->
    <properties resource="db.properties"></properties>
    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理,事务由 Mybatis 控制-->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
配置完成后我们测试一下是否能够和刚才一样的能够成功呢?那么我就先在db.properties中把数据库密码故意改错,看是否是正确的?不出意外的话是会报错的。



注意: MyBatis 将按照下面的顺序来加载属性:

在 properties 元素体内定义的属性首先被读取。
然后会读取 properties 元素中 resource 或 url 加载的属性,它会覆盖已读取的同名属性。
最后读取 parameterType 传递的属性,它会覆盖已读取的同名属性。

因此,通过parameterType传递的属性具有最高优先级,resource或 url 加载的属性次之,最低优先级的是 properties 元素体内定义的属性。

建议:

不要在 properties 元素体内添加任何属性值,只将属性值定义在 db.properties 文件之中。
在 db.properties 文件之中定义的属性名要有一定的特殊性。如 xxx.xxx.xxx
settings(全局配置参数)
Mybatis 框架在运行时可以调整一些运行参数

比如:开启二级缓存、开启延迟加载。。。



typeAliases(类型别名)
需求:

在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。

如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。

Mybatis支持的别名:

别名    映射的类型
_byte    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
自定义别名:

在 SqlMapConfig.xml 中配置:(设置别名)

<typeAliases>
    <!-- 单个别名定义 -->
    <typeAlias alias="user" type="cn.zhisheng.mybatis.po.User"/>
    <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
    <package name="cn.zhisheng.mybatis.po"/>
    <package name="其它包"/>
</typeAliases>
在 UserMapper.xml 中引用别名:( resultType 为 user )
<select id="findUserById" parameterType="int" resultType="user">
        select * from user where id = #{id}
</select>

测试结果:

typeHandlers(类型处理器)
mybatis中通过typeHandlers完成jdbc类型和java类型的转换。

通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义.

mybatis支持类型处理器:

类型处理器 Java类型 JDBC类型
BooleanTypeHandler Boolean,boolean 任何兼容的布尔值
ByteTypeHandler Byte,byte 任何兼容的数字或字节类型
ShortTypeHandler Short,short 任何兼容的数字或短整型
IntegerTypeHandler Integer,int 任何兼容的数字和整型
LongTypeHandler Long,long 任何兼容的数字或长整型
FloatTypeHandler Float,float 任何兼容的数字或单精度浮点型
DoubleTypeHandler Double,double 任何兼容的数字或双精度浮点型
BigDecimalTypeHandler BigDecimal 任何兼容的数字或十进制小数类型
StringTypeHandler String CHAR和VARCHAR类型
ClobTypeHandler String CLOB和LONGVARCHAR类型
NStringTypeHandler String NVARCHAR和NCHAR类型
NClobTypeHandler String NCLOB类型
ByteArrayTypeHandler byte[] 任何兼容的字节流类型
BlobTypeHandler byte[] BLOB和LONGVARBINARY类型
DateTypeHandler Date(java.util) TIMESTAMP类型
DateOnlyTypeHandler Date(java.util) DATE类型
TimeOnlyTypeHandler Date(java.util) TIME类型
SqlTimestampTypeHandler Timestamp(java.sql) TIMESTAMP类型
SqlDateTypeHandler Date(java.sql) DATE类型
SqlTimeTypeHandler Time(java.sql) TIME类型
ObjectTypeHandler 任意 其他或未指定类型
EnumTypeHandler Enumeration类型 VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。

mappers(映射器)
使用相对于类路径的资源,如:

使用完全限定路径
如:

使用 mapper 接口类路径

如:

注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

注册指定包下的所有mapper接口
如:
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

Mapper.xml 映射文件
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。

输入映射
通过 parameterType 指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型。

传递 pojo 包装对象 (重点)

开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。

定义包装对象

定义包装对象将查询条件(pojo)以类组合的方式包装起来。

UserQueryVo.java

public class UserQueryVo    //用户包装类型
{
    //在这里包装所需要的查询条件
    //用户查询条件
    private UserCustom userCustom;
    public UserCustom getUserCustom()
    {
        return userCustom;
    }
    public void setUserCustom(UserCustom userCustom)
    {
        this.userCustom = userCustom;
    }
    //还可以包装其他的查询条件,比如订单、商品
}

UserCustomer.java

public class UserCustom extends User    //用户的扩展类
{
    //可以扩展用户的信息
}

UserMapper.xml 文件

    <select id="findUserList" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="cn.zhisheng.mybatis.po.UserCustom">
        select * from user where user.sex = #{userCustom.sex} and user.username like  '%${userCustom.username}%'
    </select>

UserMapper.java

//用户信息综合查询

public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;

测试代码

//测试用户信息综合查询

测试结果

输出映射
resultType
使用 resultType 进行输出映射,只有查询出来的列名和 pojo 中的属性名一致,该列才可以映射成功。
如果查询出来的列名和 pojo 中的属性名全部不一致,没有创建 pojo 对象。
只要查询出来的列名和 pojo 中的属性有一个一致,就会创建 pojo 对象。
输出简单类型

需求:用户信息综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页

实现:

    <select id="findUserCount" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="int">
      select count(*) from user where user.sex = #{userCustom.sex} and user.username like  '%${userCustom.username}%'
    </select>

//用户信息综合查询总数

   public int findUserCount(UserQueryVo userQueryVo) throws Exception;

//测试用户信息综合查询总数

    @Test
    public void testFindUserCount() throws Exception
    {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //创建包装对象,设置查询条件
        UserQueryVo userQueryVo = new UserQueryVo();
        UserCustom userCustom = new UserCustom();
        userCustom.setSex("男");
        userCustom.setUsername("张小明");
        userQueryVo.setUserCustom(userCustom);
        //调用UserMapper的方法
        System.out.println(userMapper.findUserCount(userQueryVo));
    }

注意:查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。

输出pojo对象和pojo列表

不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。

在mapper.java指定的方法返回值类型不一样:

1、输出单个pojo对象,方法返回值是单个对象类型

//根据id查询用户信息
public User findUserById(int id) throws Exception;
2、输出pojo对象list,方法返回值是List

//根据用户名查询用户信息

  public List<User> findUserByUsername(String userName) throws  Exception;

resultType总结:

输出pojo对象和输出pojo列表在sql中定义的resultType是一样的。

返回单个pojo对象要保证sql查询出来的结果集为单条,内部使用session.selectOne方法调用,mapper接口使用pojo对象作为方法返回值。

返回pojo列表表示查询出来的结果集可能为多条,内部使用session.selectList方法,mapper接口使用List对象作为方法返回值。

resultMap
resultType 可以指定 pojo 将查询结果映射为 pojo,但需要 pojo 的属性名和 sql 查询的列名一致方可映射成功。

如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。

resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。

使用方法:

1、定义 resultMap

2、使用 resultMap 作为 statement 的输出映射类型

将下面的 sql 使用 User 完成映射

select id id_, username username_ from user where id = #{value}

User 类中属性名和上边查询的列名不一致。

所以需要:

1、定义 resultMap

    <resultMap id="userResultMap" type="user">
        <!--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>

2、使用 resultMap 作为 statement 的输出映射类型

    <select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
        select id id_, username username_ from user where id = #{value}
    </select>

3、UserMapper.java

//根据id查询用户信息,使用 resultMap 输出

public User findUserByIdResultMap(int id) throws Exception;

4、测试

//测试根据id查询用户信息,使用 resultMap 输出
    @Test
    public void testFindUserByIdResultMap() throws Exception
    {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //调用UserMapper的方法
        User user = userMapper.findUserByIdResultMap(1);
        System.out.println(user);
    }

5、测试结果

动态 SQL
通过mybatis提供的各种标签方法实现动态拼接sql。

需求:

用户信息综合查询列表和用户信息查询列表总数这两个 statement的定义使用动态sql。

对查询条件进行判断,如果输入的参数不为空才进行查询条件拼接。

UserMapper.xml (findUserList的配置如下,那么findUserCount的也是一样的,这里就不全部写出来了)

<select id="findUserList" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="cn.zhisheng.mybatis.po.UserCustom">
        select * from user
        <!--where可以自动的去掉条件中的第一个and-->
        <where>
            <if test="userCustom != null">
                <if test="userCustom.sex != null and userCustom.sex != ''">
                    and user.sex = #{userCustom.sex}
                </if>
                <if test="userCustom.username != null">
                    and user.username like  '%${userCustom.username}%'
                </if>
            </if>
        </where>
    </select>

测试代码:因为设置了动态的sql,如果不设置某个值,那么条件就不会拼接在sql上

所以我们就注释掉设置username的语句

//userCustom.setUsername("张小明");

测试结果:

Sql 片段
通过上面的其实看到在 where sql语句中有很多重复代码,我们可以将其抽取出来,组成一个sql片段,其他的statement就可以引用这个sql片段,利于系统的开发。

这里我们就拿上边sql 中的where定义一个sq片段如下:

   <sql id="query_user_where">
       <if test="userCustom != null">
           <if test="userCustom.sex != null and userCustom.sex != ''">
               and user.sex = #{userCustom.sex}
           </if>
           <if test="userCustom.username != null">
               and user.username like  '%${userCustom.username}%'
           </if>
       </if>
   </sql>

那么我们该怎样引用这个sql片段呢?如下:

select * from user
        <where>
        <!--refid: 指定sql片段的id,如果是写在其他的mapper文件中,则需要在前面加上namespace-->
            <include refid="query_user_where"/>
        </where>

测试的话还是那样了,就不继续说了,前面已经说了很多了。

foreach
向sql传递数组或List,mybatis使用foreach解析

需求:

在用户查询列表和查询总数的statement中增加多个id输入查询。

sql语句如下:

SELECT * FROM USER WHERE id=1 OR id=10 ORid=16
或者
SELECT * FROM USER WHERE id IN(1,10,16)
在输入参数类型中添加 List ids 传入多个 id
public class UserQueryVo    //用户包装类型
{
    //传入多个id
    private List<Integer> ids;
}

修改 UserMapper.xml文件

WHERE id=1 OR id=10 OR id=16

在查询条件中,查询条件定义成一个sql片段,需要修改sql片段。

<if test="ids!=null">
            <!-- 使用 foreach遍历传入ids
            collection:指定输入 对象中集合属性
            item:每个遍历生成对象中
            open:开始遍历时拼接的串
            close:结束遍历时拼接的串
            separator:遍历的两个对象中需要拼接的串
             -->
             <!-- 使用实现下边的sql拼接:
              AND (id=1 OR id=10 OR id=16)
              -->
            <foreach collection="ids" item="user_id" open="AND (" close=")" separator="or">
                <!-- 每个遍历需要拼接的串 -->
                id=#{user_id}
            </foreach>

            <!-- 实现  “ and id IN(1,10,16)”拼接 -->
            <!-- <foreach collection="ids" item="user_id" open="and id IN(" close=")" separator=",">
                每个遍历需要拼接的串
                #{user_id}
            </foreach> -->
            </if>

测试代码:

//传入多个id
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(10);
ids.add(16);
//将ids传入statement中
userQueryVo.setIds(ids);
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务