1.MyBatis概述

  • MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  • Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatement、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

2.为什么要使用MyBatis(使用JDBC编程有哪些问题)?

  1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

  2. Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

  3. 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
  4. 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

3.MyBatis架构

  1. MyBatis配置

    • SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

    • mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
  2. 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

  3. 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

  4. mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
  5. Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。

  6. Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

  7. Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor

4.MyBatis入门

创建Maven工程

修改pom.xml导入MyBatis以及Junit和MySql驱动的jar包

<dependencies>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency> <!--junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- mybatis -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
   </dependency>
</dependencies>

classpath目录下创建MyBatis的核心配置文件SqlMapConfig.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>
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments> <!-- 加载映射文件 -->
<mappers>
<mapper resource="User.xml" />
</mappers> </configuration>

创建测试数据库

创建po类  ---Po类作为mybatis进行sql映射使用,po类通常与数据库表对应

package pojo;

import java.util.Date;

public class User {

    private int id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址 getter and setter方法......     @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
                + address + "]";
    }       }

创建sql映射文件User.xml

<?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:命名空间,做sql隔离 -->
<mapper namespace="test"> <!--
id:sql语句唯一标识
parameterType:指定传入参数类型
resultType:返回结果集类型
#{}占位符:起到占位作用,如果传入的是基本类型(string,long,double,int,boolean,float等),那么#{}中的变量名称可以随意写.
-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="cn.itheima.pojo.User">
select * from user where id=#{id}
</select> <!--
如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所以映射文件中应该配置成集合泛型的类型
${}拼接符:字符串原样拼接,如果传入的参数是基本类型(string,long,double,int,boolean,float等),那么${}中的变量名称必须是value
注意:拼接符有sql注入的风险,所以慎重使用
-->
<select id="findUserByUserName" parameterType="java.lang.String" resultType="cn.itheima.pojo.User">
select * from user where username like '%${value}%'
</select> <!--
#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性.....
如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
-->
<insert id="insertUser" parameterType="cn.itheima.pojo.User" >
<!-- 执行 select LAST_INSERT_ID()数据库函数,返回自增的主键
keyProperty:将返回的主键放入传入参数的Id中保存.
order:当前函数相对于insert语句的执行顺序,在insert前执行是before,在insert后执行是AFTER
resultType:id的类型,也就是keyproperties中属性的类型
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert> <delete id="delUserById" parameterType="int">
delete from user where id=#{id}
</delete> <update id="updateUserById" parameterType="cn.itheima.pojo.User">
update user set username=#{username} where id=#{id}
</update>
</mapper>

加载映射文件 --mybatis框架需要加载映射文件,将User.xml添加在SqlMapConfig.xml

<!-- 加载映射文件 -->
<mappers>
<mapper resource="User.xml" />
</mappers>

创建测试类UserTest进行测试

查询单个User对象

@Test
public void test1() throws IOException {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 通过会话执行sql 第一个参数是名称空间+SqlID 第二个参数表示sql执行需要的参数
User user = openSession.selectOne("test.findUserById", 1);
System.out.println(user.toString());
// 关闭会话
openSession.close(); }

通过username进行模糊查询

@Test
public void test2() throws IOException {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 调用User.xml中的魔化查询方法 返回集合
List<User> selectList = openSession.selectList("test.findUserByName", "张");
// 循环结果
System.out.println(selectList.size());
for (User user : selectList) {
System.out.println(user.toString());
}
// 关闭会话
openSession.close();
}

添加一条User用户到数据库

@Test
public void test3() throws IOException {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 创建需要插入的User对象
User user = new User();
user.setUsername("Jimisun");
user.setSex("1");
user.setAddress("北京");
System.out.println("====插入前的User的id=" + user.getId());
// 会话调用插入的sql
openSession.insert("test.insertUser", user);
// 默认mybatis自动开启事务,需要手动提交事务
openSession.commit();
System.out.println("====插入后的User的id=" + user.getId());
// 关闭会话
openSession.close();
}

删除一条记录

@Test
public void test4() throws IOException {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
// 会话执行sql操作
openSession.delete("test.deleteUserById", 1);
// 提交事务
openSession.commit();
// 关闭会话
openSession.close();
}

更新一条记录

@Test
public void test5() throws Exception {
// 核心配置文件
String resource = "SqlMapConfig.xml";
// 通过流将核心配置文件加载进来
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过配置文件创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过会话工厂获取会话
SqlSession openSession = factory.openSession();
//创建User对象
User user = new User ();
user.setId(1);
user.setUsername("王麻子");
openSession.update("test.updateByUserId", user);
//提交事务
openSession.commit();
//关闭会话
openSession.close(); }

 5.使用MyBatis的开发方法

  • 原生Dao方法

    • UserDao  接口
    • UserDaoImpl  实现类
      • findUserById()  -----方法内使用MyBatis框架进行操作

        // 核心配置文件
        String resource = "SqlMapConfig.xml";
        // 通过流将核心配置文件加载进来
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 通过配置文件创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 通过会话工厂获取会话
        SqlSession openSession = factory.openSession();
        // 通过会话执行sql 第一个参数是名称空间+SqlID 第二个参数表示sql执行需要的参数
        User user = openSession.selectOne("test.findUserById", 1);
        System.out.println(user.toString());
        // 关闭会话
        openSession.close();
  • Mapper接口开发    ----Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
    • 开发规范

      • Mapper.xml文件中的namespace与mapper接口的类路径相同。

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

      • Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

    • 开发目录
      • UserDao   接口 遵循上面规则
      • UserServiceImpl直接调用
            @Test
        public void testFindUserById() throws Exception{
        SqlSession openSession = factory.openSession();
        //通过getMapper方法来实例化接口
        UserMapper mapper = openSession.getMapper(UserMapper.class); User user = mapper.findUserById(1);
        System.out.println(user);
        }

 6.SqlMapConfig.xml配置文件

  • properties(属性) 常用于加载配置文件

    <properties resource="db.properties"></properties>
    <environments default="development">
    <environment id="development">
    <!-- 使用jdbc事务管理-->
    <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>
  • typeAliases(类型别名)

    <typeAliases>
    <!-- 定义单个pojo类别名
    type:类的全路劲名称
    alias:别名
    -->
    <typeAlias type="cn.itheima.pojo.User" alias="user"/> <!-- 使用包扫描的方式批量定义别名
    定以后别名等于类名,不区分大小写,但是建议按照java命名规则来,首字母小写,以后每个单词的首字母大写
    -->
    <package name="cn.itheima.pojo"/>
    </typeAliases>
  • mappers(映射器)

    • 相对于类路径的资源

      <mapper resource="sqlmap/User.xml" />
    • 使用mapper接口开发
      <mapper class="cn.redrat.mybatis.mapper.UserMapper"/>
    • 注册指定包下所有的mapper接口
      <package name="cn.redrat.mybatis.mapper"/>
      • 注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

7.输入映射和输出映射

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

    • parameterType(输入类型)

      • 传递基本类型包含String
      • 传递pojo对象
      • 传递vo对象
    • resultType(输出类型)

      • 返回pojo类型
      • 返回集合
      • 返回基本类型包含String

8.动态Sql --通过mybatis提供的各种标签方法实现动态拼接sql

  • if

    <!-- 传递pojo综合查询用户信息   注意要做不等于空字符串校验-->
    <select id="findUserList" parameterType="user" resultType="user">
    select * from user
    where 1=1
    <if test="id!=null">
    and id=#{id}
    </if>
    <if test="username!=null and username!=''">
    and username like '%${username}%'
    </if>
    </select>
  • where
    <select id="findUserList" parameterType="user" resultType="user">
    select * from user
    <where>
    <if test="id!=null and id!=''">
    and id=#{id}
    </if>
    <if test="username!=null and username!=''">
    and username like '%${username}%'
    </if>
    </where>
    </select

    where标签的作用可以去掉sql语句中的where 1=1 并自动处理第一个 and

  • foreach
    <select id="findUserByIds" parameterType="cn.redrat.pojo.QueryVo" resultType="cn.redrat.pojo.User">
    select * from user
    <where>
    <if test="ids != null">
    <!--
    foreach:循环传入的集合参数
    collection:传入的集合的变量名称
    item:每次循环将循环出的数据放入这个变量中
    open:循环开始拼接的字符串
    close:循环结束拼接的字符串
    separator:循环中拼接的分隔符
    -->
    <foreach collection="ids" item="id" open="id in (" close=")" separator=",">
    #{id}
    </foreach>
    </if>
    </where>
    </select>

9.MyBatis关联查询核心示例

  • 一对一查询

    <!-- 一对一:自动映射 -->
    <select id="findOrdersAndUser1" resultType="cn.redrat.pojo.CustomOrders">
    select a.*, b.id uid, username, birthday, sex, address
    from orders a, user b
    where a.user_id = b.id
    </select> <!-- 一对一:手动映射 -->
    <!--
    id:resultMap的唯一标识
    type:将查询出的数据放入这个指定的对象中
    注意:手动映射需要指定数据库中表的字段名与java中pojo类的属性名称的对应关系
    -->
    <resultMap type="cn.redrat.pojo.Orders" id="orderAndUserResultMap">
    <!-- id标签指定主键字段对应关系
    column:列,数据库中的字段名称
    property:属性,java中pojo中的属性名称
    -->
    <id column="id" property="id"/> <!-- result:标签指定非主键字段的对应关系 -->
    <result column="user_id" property="userId"/>
    <result column="number" property="number"/>
    <result column="createtime" property="createtime"/>
    <result column="note" property="note"/> <!-- 这个标签指定单个对象的对应关系
    property:指定将数据放入Orders中的user属性中
    javaType:user属性的类型
    -->
    <association property="user" javaType="cn.redrat.pojo.User">
    <id column="uid" property="id"/>
    <result column="username" property="username"/>
    <result column="birthday" property="birthday"/>
    <result column="sex" property="sex"/>
    <result column="address" property="address"/>
    </association>
    </resultMap>
    <select id="findOrdersAndUser2" resultMap="orderAndUserResultMap">
    select a.*, b.id uid, username, birthday, sex, address
    from orders a, user b
    where a.user_id = b.id
    </select>
  • 一对多
    <resultMap type="cn.redrat.pojo.User" id="userAndOrdersResultMap">
    <id column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="birthday" property="birthday"/>
    <result column="sex" property="sex"/>
    <result column="address" property="address"/> <!-- 指定对应的集合对象关系映射
    property:将数据放入User对象中的ordersList属性中
    ofType:指定ordersList属性的泛型类型
    -->
    <collection property="ordersList" ofType="cn.redrat.pojo.Orders">
    <id column="oid" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="number" property="number"/>
    <result column="createtime" property="createtime"/>
    </collection>
    </resultMap>
    <select id="findUserAndOrders" resultMap="userAndOrdersResultMap">
    select a.*, b.id oid ,user_id, number, createtime
    from user a, orders b where a.id = b.user_id
    </select>

MyBatis基础入门的更多相关文章

  1. MyBatis基础入门《二十》动态SQL(foreach)

    MyBatis基础入门<二十>动态SQL(foreach) 1. 迭代一个集合,通常用于in条件 2. 属性 > item > index > collection : ...

  2. MyBatis基础入门《十九》动态SQL(set,trim)

    MyBatis基础入门<十九>动态SQL(set,trim) 描述: 1. 问题 : 更新用户表数据时,若某个参数为null时,会导致更新错误 2. 分析: 正确结果: 若某个参数为nul ...

  3. MyBatis基础入门《十八》动态SQL(if-where)

    MyBatis基础入门<十八>动态SQL(if-where) 描述: 代码是在<MyBatis基础入门<十七>动态SQL>基础上进行改造的,不再贴所有代码,仅贴改动 ...

  4. MyBatis基础入门《十七》动态SQL

    MyBatis基础入门<十七>动态SQL 描述: >> 完成多条件查询等逻辑实现 >> 用于实现动态SQL的元素主要有: > if > trim > ...

  5. MyBatis基础入门《十六》缓存

    MyBatis基础入门<十六>缓存 >> 一级缓存 >> 二级缓存 >> MyBatis的全局cache配置 >> 在Mapper XML文 ...

  6. MyBatis基础入门《十五》ResultMap子元素(collection)

    MyBatis基础入门<十五>ResultMap子元素(collection) 描述: 见<MyBatis基础入门<十四>ResultMap子元素(association ...

  7. MyBatis基础入门《十四》ResultMap子元素(association )

    MyBatis基础入门<十四>ResultMap子元素(association ) 1. id: >> 一般对应数据库中改行的主键ID,设置此项可以提高Mybatis的性能 2 ...

  8. MyBatis基础入门《十三》批量新增数据

    MyBatis基础入门<十三>批量新增数据 批量新增数据方式1:(数据小于一万) xml文件 接口: 测试方法: 测试结果: =============================== ...

  9. MyBatis基础入门《十二》删除数据 - @Param参数

    MyBatis基础入门<十二>删除数据 - @Param参数 描述: 删除数据,这里使用了@Param这个注解,其实在代码中,不使用这个注解也可以的.只是为了学习这个@Param注解,为此 ...

  10. MyBatis基础入门《十 一》修改数据

    MyBatis基础入门<十 一>修改数据 实体类: 接口类: xml文件: 测试类: 测试结果: 数据库: 如有问题,欢迎纠正!!! 如有转载,请标明源处:https://www.cnbl ...

随机推荐

  1. Python 实现小数和百分数的相互转换

    # -*- coding: utf-8 -*- #百分比转换位小数 # -*- coding: utf-8 -*- s = '20%' # 默认要转换的百分比是字符串aa = float(s.stri ...

  2. c语言打印一个整数的二进制形式

    printf函数没有这个功能,如果想打印一个数的二进制形式,就得自己计算.下面是我看到的最简便的算法: #include <stdio.h> int main(int argc, char ...

  3. atitit.软件开发概念--过滤和投影 数据操作

    atitit.软件开发概念--过滤和投影 数据操作 投影的本质及扩展 物体在太阳光的照射下形成的影子(简称日影)就是平行投影.日影的方向可以反映时间 投影还比喻此物通过彼物表现出来的迹象. 作者::老 ...

  4. nginx源代码分析--GDB调试

    利用gdb[i]调试nginx[ii]和利用gdb调试其他程序没有两样,只是nginx能够是daemon程序,也能够以多进程执行,因此利用gdb调试和寻常会有些许不一样. 当然,我们能够选择将ngin ...

  5. location [=|$|最长原则|^~](nginx-1.4.4)

    优先级由上到下依次递减: location =/a/1.png { return 400; } } location ~* \.png$ { return 403; } location /a/1.p ...

  6. Nokia Imaging SDK 的高级使用—实时滤镜拍照

    有关 Nokia Imaging SDK 的初级使用,可以参考:Nokia Imaging SDK滤镜使用入门 本文的主题: 1.如何 PhotoCaptureDevice 类使用,以及如何在 Med ...

  7. jmap 查看内存使用直方图

    jps   -- 查看进程号 jmap -histo pid  查看堆内存中的对象数目.大小统计直方图, 如果带上live则表示先进行一次fullgc 再统计内存使用情况,如下: jmap -hist ...

  8. 第八课:不一样的链表 linux链表设计哲学 5星级教程

    这一课最后实现的链表,和普通链表不同,借鉴了linux内核链表的思想,这也是企业使用的链表. 基础介绍: 顺序表的思考 顺序表的最大问题是插入和删除需要移动大量的元素!如何解决?A:在线性表数据元素之 ...

  9. python学习笔记(7)--爬虫隐藏代理

    说明: 1. 好像是这个网站的代理http://www.xicidaili.com/ 2. 第2,3行的模块不用导入,之前的忘删了.. 3. http://www.whatismyip.com.tw/ ...

  10. Unix网络编程中的五种I/O模型_转

    转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描 ...