MyBatis基础

目录

一、什么是Mybatis     

1.mybatis是什么?有什么特点?

2.什么是ORM?

3.为什么mybatis是半自动的ORM框架?

二、使用步骤

1.导入依赖

2.主配置文件 

3.Mapper映射文件

三、实际应用

1. hello mybatis

2.参数传递

 1.基本类型传递

2. 多个参数的传递

3.使用java对象传递参数

4. 使用Map进行传递,>

3. # 和 $ 的区别

4.返回类型

 1. resultType类型

 2. resultMap类型

5.动态sql

 1. if 和 where

2.foreach

3.Sql片段

6.逆向工程

7.多表联查

8.多表联查 + 分页查询

9.主键返回

总结


一、什么是Mybatis     

1.mybatis是什么?有什么特点?

        它是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低。简单来说,Mybatis是实现了Dao层访问数据库使用的一种框架,统一了不同数据库访问的规范

2.什么是ORM?

        Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系。

3.为什么mybatis是半自动的ORM框架?

        用mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句。用hibernate开发,只需要定义好ORM映射关系,就可以直接进行CRUD操作了。由于mybatis需要手写SQL语句,所以它有较高的灵活性,可以根据需要,自由地对SQL进行定制,也因为要手写SQL,当要切换数据库时,SQL语句可能就要重写,所以mybatis的数据库无关性低。虽然mybatis需要手写SQL,但相比JDBC,它提供了输入映射和输出映射,可以很方便地进行SQL参数设置,以及结果集封装。并且还提供了关联查询和动态SQL等功能,极大地提升了开发的效率。并且它的学习成本也比hibernate低很多

二、使用步骤

1.导入依赖

<!--配置Mybatis驱动-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>

<!--配置sql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>

        Mybatis的使用主要涉及两个配置文件:主配置文件和Mapper映射文件;通过定义xml由java反射机制定位需要的类

2.主配置文件 

   参数说明:(简单说明常用的参数)

   1. 引入外部文件

<properties resource="db.properties"></properties>

  2. 开启日志

<setting name="logImpl" value="STDOUT_LOGGING"></setting>

 3. 配置数据源

        子标签<environment>可以配置多个数据源,用于不同的环境,通过id进行区分

<environments default="development">
    <environment id="development">
    <!--...-->
    </environment>
</environments>

 4. mapper映射文件

        用于主配置文件和mapper文件之间产生映射关系,可以使用<mapper>或者<package>的方式定义;当使用<package>的时候,需要保证接口类和mapper.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 resource="db.properties"></properties>

    <settings>
        <!--设置日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"></setting>
    </settings>

    <typeAliases>
        <!--将package包下的类作为别名-->
        <package name="xxx"/>
    </typeAliases>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--分页参数合理化  -->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>

    <!--该部分应该由spring容器进行创建-->
    <environments default="development">
    <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
    <property name="driver" value="${db.driver}"/>
    <property name="url" value="${db.url}"/>
    <property name="username" value="${db.username}"/>
    <property name="password" value="${db.password}"/>
    </dataSource>
    </environment>
    </environments>

    <!-- 使用相对于类路径的资源引用 -->
    <!--sql映射文件位置-->
    <mappers>
        <mapper resource="xxx.xml"/>

        <!--当使用包名的时候需要保证mapper映射文件和接口类在相同路径下-->
        <!--<package name="xxx.dao"/>-->
</mappers>
</configuration>

3.Mapper映射文件

        书写sql语句的xml文件,定义后通过主配置文件进行导入

1) Mapper.xml文件中的namespace与mapper接口的全限定名相同

2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同

4) Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;还有一种返回类型是resultMap方式,可以自定义java对象属性和数据库列名的映射关系

基础模板: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">
<mapper namespace="">

    <select id="" resultType="">
    </select>
</mapper>

三、实际应用

1. hello mybatis

        配置文件模板,依赖在上面都提过,跳过了

        测试用例:通过主键获取用户信息

         UserDao为接口类,对外提供getUser(Integer id)方法

@Test
public void testMybatisConfig() {
    String config = "mybatisConfig.xml";
    try {
        InputStream is = Resources.getResourceAsStream(config);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession =  sqlSessionFactory.openSession();
//      User user = sqlSession.selectOne("com.righteye.day01.dao.UserDao.getUser", 10);
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = userDao.getUser(10);
        System.out.println(user);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

UserDao的映射文件:

<?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="com.righteye.day02.domain.User"> 

    <!--接口方法名-->
    <select id="getUser" resultType="com.righteye.day02.domain.User">
           select * from user where id = #{id}
    </select>
</mapper>

  hello Mybatis主要实现使用Mybatis的步骤:

        1.获取主配置文件:mybatisConfig.xml, 并进行加载

        2.获取SqlSessionFactory对象

        3.获取SqlSession对象(注:openSession中的参数如果为true,表示自动完成事务的提交,否则需要手动commit)

        4.通过sqlSession获取接口类对象(反射机制自动完成)

mybatis的动态代理:mybatis根据dao的方法调用,获取执行sql语句的信息。根据接口创建一个接口的实现类,并创建这个类的对象完成sqlSession调用方法,访问数据库。

2.参数传递

 1.基本类型传递

        mybatis中的基本数据类型和string称为基本类型;使用#{任意字符} 进行传递

select * from user where id = #{id}

2. 多个参数的传递

        传递多个参数的时候,在接口方法的形参位置前添加@Param, 为变量重命名,sql语句的书写时#{} 中的字符要和重命名相同

        @Param 实现原理会将@Param修饰部分转换成一个Map对象,即方法中实际传入一个Map对象

Map<String,Object> map = new HashMap<>();
map.put("myname", username);
map.put("pwd",password);

接口方法声明:

int insertUser(@Param("myname")String username, @Param("pwd")String password);

UserMapper文件:

<?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="com.righteye.day02.domain.User">

    <select id="insertUser" resultType="com.righteye.day02.domain.User">
        select * from user where user_name = #{myname} and password = #{pwd}
    </select>
</mapper>

3.使用java对象传递参数

   使用java对象的属性值,作为传递参数的名字

4. 使用Map<String, Object>进行传递

  接口方法, 在参数中传递Map:

User selectUser(Map<String,Object> map);

  mapper映射文件

<select id="selectUser" parameterType="map" resultType="com.righteye.domain.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
Map<String, Object> map = new HashMap<String, Object>();
map.put("username","小明");
map.put("pwd","123456");
User user = mapper.selectUser(map);

3. # 和 $ 的区别

        $ 底层使用jdbc的Statement对象,在sql语句中不存在?,而是使用字符串拼接;使用$可以替换sql中的字符串,用来替换表名、列名;

        # 底层使用PreparedStatement,使用?进行占位,防止sql注入,保证数据安全;比$使用更加频繁

4.返回类型

 1. resultType类型

        Mybatis执行sql语句后的返回值;返回值是一个java对象,java对象的类型可以是简单数据类型或自定义类型

        处理方式:mybatis执行sql语句,然后mybatis调用类的无参数构造方法创建对象,然后进行同名类赋值

<select id="getUser" resultType="com.righteye.day02.domain.User">
      select * from user where id = #{id}
</select>

 2. resultMap类型

resultMap:用于自定义属性和列名不统一;resultType默认数据库的值赋给同名java对象中的属性

<resultMap id="BaseResultMap" type="com.righteye.day02.domain.User">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="user_name" jdbcType="VARCHAR" property="userName" />
    <result column="password" jdbcType="VARCHAR" property="password" />
</resultMap>

<select id="selectUserAndOrders" resultType="BaseResultMap">
    select * from user u join orders o on u.id = o.uid where o.id = #{id};
  </select>

5.动态sql

        可以根据不同的条件获取不同的sql语句;主要是where部分

主要有三种标签:<if> <where> <foeach>

 1. if 和 where

        where标签就是代替了sql语句中的where条件;if就是分支判断

<select id="getTotalByCondition" resultType="int">
        select count(*)
        from tbl_activity a
        join tbl_user u
        on a.owner=u.id
        <where>
            <if test="name!=null and name!=''">
                a.name like '%' #{name} '%'
            </if>
            <if test="owner!=null and owner!=''">
                and u.name like '%' #{owner} '%'
            </if>
        </where>
    </select>

        <where>标签中如果有返回值的话则添加一个where, 如果标签返回值以and或者or开头则会进行剔除

2.foreach

        语法:

 <foreach>语句主要用于sql中的in语句,用于遍历集合

<foreach collection="" item="" begin="" end="" separator="">

collection:集合接口类型

item:自定义对象的名称

separator:间隔符

    <delete id="delete">
        delete from tbl_activity
        where id in
        <foreach collection="array" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </delete>

3.Sql片段

        增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

提取sql片段

<sql id="if-title-author">
   <if test="title != null">
      title = #{title}
   </if>
   <if test="author != null">
      and author = #{author}
   </if>
</sql>

引用Sql片段

<select id="queryBlogIf" parameterType="map" resultType="blog">
  select * from blog
   <where>
       <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
       <include refid="if-title-author"></include>
       <!-- 在这里还可以引用其他的 sql 片段 -->
   </where>
</select>

注意:

①、最好基于 单表来定义 sql 片段,提高片段的可重用性

②、在 sql 片段中不要包括 where

上述代码来自:狂神说MyBatis06:动态SQL

6.逆向工程

        mybatis官方提供mapper自动生成工具mybatis-generator-core来针对单表,生成实体类,以及Mapper接口和mapper.xml映射文件。针对单表,可以不需要再手动编写xml配置文件和mapper接口文件了,非常方便。但不支持生成关联查询

添加依赖:

 <!--导入逆向工程依赖-->
    <dependency>
      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-core</artifactId>
      <version>1.3.7</version>
    </dependency>
  </dependencies>

添加逆向工程插件

<build>
    <!--导入逆向工程插件-->
    <plugins>
      <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.6</version>
        <configuration>
          <!-- 配置文件的位置 -->
          <configurationFile>generatorConfig.xml</configurationFile>
          <verbose>true</verbose>
          <overwrite>true</overwrite>
        </configuration>
      </plugin>
  </build>

注:这里的generatorConfig.xml文件是以项目为根目录的,不要放在资源路径下

完整genaratorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <classPathEntry>
    <!--这个位置是maven仓库下mysql的jar包位置-->
            location="xxx"/>

    <context id="DB2Tables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!--表示生成的类是否需要注释-->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!-- 配置数据库连接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
             connectionURL="jdbc:mysql://localhost:3306/xxx" userId="root"
             password="123456">
        </jdbcConnection>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- 指定javaBean生成的位置 -->
        <javaModelGenerator targetPackage="xxx"
                            targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!--指定sql映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="xxx" targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <!-- 指定dao接口生成的位置,mapper接口 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="xxx" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>


        <!-- table指定每个表的生成策略 -->
        
        <table tableName="xx" domainObjectName="xx"></table>
    </context>
</generatorConfiguration>    

执行插件

7.多表联查

目标:给定user表和role表,属于一对多关系,目标找出每个用户对应的所有角色信息

表结构:

user表:

role表:

 u_r表:表示user和role的关系表

 首先给出普通的sql语句,在得出sql语句后再整合到mybatis中会更容易

select u.id, u.user_name, u.password, r.id rid, r.name from user u join u_r ur on u.id = ur.uid join role r on r.id = ur.rid

项目中使用逆向工程生成User类和Role类,为了存储查询的role信息,在User类在添加List<Role>属性,User类如下:

package com.righteye.day02.domain;

import java.util.List;

public class User {
    private Integer id;

    private String userName;

    private String password;

    private List<Role> rList;

    public List<Role> getrList() {
        return rList;
    }

    public void setrList(List<Role> rList) {
        this.rList = rList;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName == null ? null : userName.trim();
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", rList=" + rList +
                '}';
    }
}

UserMapper接口类中方法声明:List<User> selectAllUserWithRole();

UserMapper.xml文件配置如下:文件书写顺序只表示我写的时候的流程

  <!--
 	column用于指定用于关联查询的列
	property用于指定要封装到StudentExt中的哪个属性
	javaType用于指定关联查询得到的对象
	select用于指定关联查询时,调用的是哪一个DQL
  --> 

  <resultMap id="BaseResultMapWithRole" type="com.righteye.day02.domain.User">
    <id column="id" property="id"></id>
    <result column="user_name" property="userName"></result>
    <result column="password" property="password"></result>
    <!--返回的role是list集合,所以使用collection-->
    <collection property="rList" ofType="com.righteye.day02.domain.Role">
      <id column="rid" property="id"></id>
      <result column="name" property="name"></result>
    </collection>
  </resultMap>
  
  <sql id="Base_Column_List_withRole">
    u.id, u.user_name, u.password, r.id rid, r.name
  </sql>

  <!--selectAllUserWithRole-->
  <select id="selectAllUserWithRole" resultMap="BaseResultMapWithRole">
      select
      <include refid="Base_Column_List_withRole"></include>
      from user u
      join u_r ur on u.id = ur.uid
      join role r on r.id = ur.rid
  </select>

  

配置文件说明:

        由于返回的是一个List<Role>对象,所以使用collection, ofType表示返回的对象类型

测试方法:

    // 查询所有用户以及相关权限
    @Test
    public void test01() {
        String config = "mybatisConfig.xml";
        SqlSessionFactory sqlSessionFactory = null;
        try {
            InputStream is = Resources.getResourceAsStream(config);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSession session = sqlSessionFactory.openSession(true);

        UserMapper userMapper = session.getMapper(UserMapper.class);
        List<User> uList = userMapper.selectAllUserWithRole();
        for (User user : uList) {
            System.out.println(user);
        }
    }

运行结果:

8.多表联查 + 分页查询

7.多表联查的基础上进行更改,想要使用分页插件对查询的数据进行分页;分页代码:

    @Test
    public void test01() {
        String config = "mybatisConfig.xml";
        SqlSessionFactory sqlSessionFactory = null;
        try {
            InputStream is = Resources.getResourceAsStream(config);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSession session = sqlSessionFactory.openSession(true);

        UserMapper userMapper = session.getMapper(UserMapper.class);

//        使用分页插件
        PageHelper.startPage(2, 1);
        List<User> uList = userMapper.selectAllUserWithRole();
        
        PageInfo pageInfo = new PageInfo(uList, 5);
        System.out.println(pageInfo);
    }

查询结果如下:

        可以发现分页查询后只出现了一个角色信息(上面最终测试结果有两个角色信息,分页失效了),原因在于sql语句书写问题,按 7.多表联查 的书写正常查询结果为:

        分页的结果是在这个基础上进行的,所以为了将相同用户的所有角色全部查到需要修改sql语句,可以使用子查询,使用id一次性查询所有的role.name;修改UserMapper.xml配置文件:

   <!--实现分页查询-->
  <resultMap id="BaseResultMapWithRole" type="com.righteye.day02.domain.User">
    <id column="id" property="id"></id>
    <result column="user_name" property="userName"></result>
    <result column="password" property="password"></result>

    <!--返回的role是list集合,所以使用collection, 这里使用子查询-->
    <collection property="rList" select="Base_Column_By_UserID" column="id">
      <id column="id" property="id"></id>
      <result column="name" property="name"></result>
    </collection>

  </resultMap>

  <sql id="Base_Column_List">
    id, user_name, password
  </sql>

  <!--selectAllUserWithRole update-->
  <select id="selectAllUserWithRole" resultMap="BaseResultMapWithRole">
    select
    <include refid="Base_Column_List"></include>
    from user
  </select>

  <!--子查询-->
  <select id="Base_Column_By_UserID" resultType="com.righteye.day02.domain.Role">
    select id, name
    from role join u_r ur on role.id = ur.rid
    where ur.uid = #{id}
  </select>

        这里感觉类似group by u.id的思想,即将user按照id排序后依次查找每个id对应的所有角色,而前面那种方法是使用笛卡尔积得到所有的情况在进行筛选

9.主键返回

使用useGeneratedKeyskeyProperty属性

  <insert id="insertEmp" useGeneratedKeys="true" keyColumn="u_id" keyProperty="uId">
    insert into employee(u_name, u_birday, u_money, u_did, u_password)
    values(#{uName}, #{uBirday}, #{uMoney},#{uDid}, #{uPassword})
  </insert>

    这种方法适用于数据库支持后去自增主键。keyProperty表示java实体类中的字段,keyColumn表示数据库表中的字段。

    还有一种方法看下面学习连接  

总结

简单记录目前掌握的Mybatis基础知识,待继续学习再做完善

学习链接:mybatis看这一篇就够了,简单全面一发入魂_v1009784814的博客-CSDN博客_mybatis看这一篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值