MyBatis

基本信息

MyBatis 本是 apache 的一个开源项目 iBatis , 2010年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。2013年11月迁移到 Github

iBATIS 一词来源于“ internet ”和“ abatis ”的组合,是一个基于 Java 的持久层(数据访问层)框架。
当前,最新版本是 MyBatis 3.5.7 ,其发布时间是2021年4月21日。

MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码参数的手工设置以及结果集的检索MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口JavaPOJOsPlain Ordinary Java Objects,普通的 Java 对象)映射成数据库中的记录

MyBatis 应用程序大都使用 SqlSessionFactory 实例,SqlSessionFactory 实例可以通过 SqlSessionFactoryBuilder 获得,而 SqlSessionFactoryBuilder 则可以从一个 XML 配置文件或者一个预定义的配置类的实例获得。

第一个 MyBatis 程序(增删改查)

  • 数据库建表
CREATE TABLE `tb_person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT INTO `example`.`tb_person`(`username`, `password`) VALUES ('zhangsan', '123')
INSERT INTO `example`.`tb_person`(`username`, `password`) VALUES ('lisi', '234')
INSERT INTO `example`.`tb_person`(`username`, `password`) VALUES ('zhaoliu', '345')
  • 创建 maven 工程
  • 导入 junit,mysql,mybatis 坐标
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.1</version>
    <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>
  • src /main /resources 下创建核心配置文件 mybatis-config.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核心配置文件-->
<configuration>

    <!--设置别名简化 resultType 书写,该标签必须在 environments 前-->
    <typeAliases>
        <!--1、单个别名的定义: alias:别名,type:别名映射的类型-->
        <typeAlias type="com.mybatis.entity.User" alias="User"/>

        <!--2、批量别名定义:指定包路径,自动扫描包下边的类,定义别名,别名默认为类名(首字母小写或大写)
        <package name="com.mybatis.entity"/>  -->
    </typeAliases>

    <!--environments配置环境组-->
    <!--default默认环境-->
    <!-- 配置开发环境,可以配置多个,在具体用时再做切换 -->
    <environments default="test">
        <!--environment单个环境-->
        <environment id="test">
            <!--transactionManager配置事务管理器-->
            <!-- 事务管理类型:JDBC、MANAGED -->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置连接池-->
            <!-- 数据源类型:POOLED、UNPOOLED、JNDI -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/example?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;rewriteBatchedStatements=true&amp;allowPublicKeyRetrieval=true&amp;allowMultiQueries=true"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--每一个Mapper.xml需要在Mybatis核心配置文件中注册-->
    <mappers>
        <!-- 路径用 斜线(/) 分割,而不是用 点(.) -->
        <mapper resource="com/mybatis/dao/UserMapper.xml"></mapper>
    </mappers>
</configuration>
  • 编写 MyBatis 工具类
package com.mybatis.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MyBatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            // 获取 SqlSessionFactory 实例
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // SqlSessionFactory,顾名思义,可以从中获得 SqlSession 的实例
    // SqlSession 包含了面向数据库执行 SQL 命令所需的所有方法。
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}

  • 编写代码

实体类

package com.mybatis.entity;

public class User {
    private int id;
    private String username;
    private String password;

	public User() {
        
    }

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

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

dao 层接口

package com.mybatis.dao;

import com.mybatis.entity.User;

import java.util.List;

public interface UserDao {

    List<User> getUserList();

    User getUserById(int id);

    int addUser(User user);

    int updateUser(User user);

    int deleteUserById(int id);
}

  • 创建映射文件 UserMapper.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 ,一般习惯为接口的包路径名-->
<mapper namespace="com.mybatis.dao.UserDao">

    <!-- 查询功能,resultType 设置返回值类型 -->
    <select id="getUserList" resultType="User">
        <!-- 书写 SQL 语句 -->
        SELECT * FROM tb_person;
    </select>

    <select id="getUserById" parameterType="int" resultType="User">
        SELECT *
        FROM tb_person
        WHERE id = #{id};
        <!--parameterType 是简单类型( java 8 种原始数据类型加 string ),占位符 #{} 变量名任取-->
    </select>

    <!--以实体来封装参数 -->
    <insert id="addUser" parameterType="User">
        INSERT INTO tb_person (id, username, password)
        VALUES (#{id}, #{username}, #{password});
        <!--parameterType 是对象或 map,占位符 #{} 变量名为对象属性或 map 的 key 值-->
    </insert>

    <update id="updateUser" parameterType="User">
        UPDATE tb_person
        set username=#{username},
            password=#{password}
        WHERE id = #{id};
    </update>

    <delete id="deleteUserById" parameterType="integer">
        DELETE
        FROM tb_person
        WHERE id = #{id};
    </delete>
</mapper>

pom.xml 添加以下代码,否则非 resources 文件夹下的 xml 文件和 properties 无法导出

<build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
</build>

Mybatis配置错误:java.lang.ExceptionInInitializerError 解决

  • 创建测试类
package com.mybatis.dao;

import com.mybatis.entity.User;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

import static com.mybatis.util.MyBatisUtils.getSqlSession;

public class testUserDao {
    @Test
    public void testGetUserList() {

        SqlSession sqlSession = getSqlSession();
        // 调用 mapper 中的方法:namespace + id
        List<User> userList = sqlSession.selectList("getUserList");
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

    @Test
    public void testGetUserByUserId() {
        SqlSession sqlSession = getSqlSession();
        User user = sqlSession().selectOne("getUserById", 1);
        System.out.println(user);
        sqlSession.close();
    }

    @Test
    public void testAddUser() {
        SqlSession sqlSession = getSqlSession();
        User user = new User(6, "xiaohong", "1234");
        int res = sqlSession.insert("addUser", user);
        if (res > 0) {
            System.out.println("插入成功");
        }
        // 进行 insert,update,delete 操作时,需要手动提交,否则 res > 0 但数据库没有更新数据
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void testUpdateUser() {
        SqlSession sqlSession = getSqlSession();
        User user = new User(6, "xiaohong", "3456");
        int res = sqlSession.update("updateUser", user);
        if (res > 0) {
            System.out.println("更新成功");
        }
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void testDeleteUserById() {
        SqlSession sqlSession = getSqlSession();
        int res = sqlSession.delete("deleteUserById", 1);
        if (res > 0) {
            System.out.println("删除成功");
        }
        sqlSession.commit();
        sqlSession.close();
    }
}

log4j

日志,方便排错

  • 导入坐标
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>
  • src /main /resources 下创建 log4j.properties

log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%5p] [%c]%m%n
#文件输出的相关设置
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/mxt.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS}] [%5p] [%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

运行测试类

在这里插入图片描述
在这里插入图片描述

基于 Mapper 代理的示例

@Test
    public void testGetUSerList2() {
        SqlSession sqlSession = getSqlSession();
        // 获得 mapper 代理对象
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        // 直接调用接口中的方法,不同于向 sqlSession 传 SQL id
        List<User> userList = mapper.getUserList();
        userList.forEach(System.out::println);
    }

需要遵循

  1. 接口的全限定名,要和 mapper.xmlnamespace 属性一致
  2. 接口中的方法名要和 mapper.xml 中的 SQL 标签的 id 一致
  3. 接口中的方法入参类型,要和 mapper.xmlSQL 语句的入参类型一致
  4. 接口中的方法出参类型,要和 mapper.xmlSQL 语句的返回值类型一致

使用 map 为参数类型时

int addUser2(Map<String,Object> map);
<!--传递map中的key-->
    <insert id="addUser2" parameterType="map">
        insert into tb_person (id, username, password)
        values (#{userId}, #{username}, #{password});
    </insert>
@Test
    public void addUser2(){
        SqlSession sqlSession = getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("userId",9);
        map.put("username","uhhhhh");
        map.put("password","23333");
        int res = mapper.addUser2(map);
        if (res > 0) {
            System.out.println("插入成功");
        }
        sqlSession.commit();
        sqlSession.close();
    }

模糊查询

<select id="getUserByName" parameterType="string" resultType="User">
        SELECT * FROM tb_person WHERE username like concat("%", #{name}, "%") ;
</select>

mybatis-config.xml 配置解析

配置文件中,各个标签要按照如下顺序进行配置,因为mybatis 加载配置文件的源码中是按照这个顺序进行解析的

<configuration> 配置
	<!-- 配置顺序如下
     properties  属性

     settings  设置

     typeAliases  类型别名

     typeHandlers  类型处理器

     objectFactory  对象工厂

     plugins  插件

     environments  环境配置
        environment  环境变量
            transactionManager  事务管理器
            dataSource  数据源

     mappers  映射器
     -->
</configuration>

  1. < properties >
    一般将数据源的信息单独放在一个 properties 文件中,然后用这个标签引入,在下面 dataSource 标签中,就可以用 ${} 占位符快速获取数据源的信息
db.url=jdbc:mysql://127.0.0.1:3306/example?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;rewriteBatchedStatements=true&amp;allowPublicKeyRetrieval=true&amp;allowMultiQueries=true
db.user=root
db.password=root
db.driver=com.mysql.cj.jdbc.Driver
<dataSource type="POOLED">
	<!-- 从配置文件中加载属性 -->
	<property name="driver" value="${db.driver}"/>
	<property name="url" value="${db.url}"/>
	<property name="username" value="${db.user}"/>
	<property name="password" value="${db.password}"/>
</dataSource>
  1. < settings >
    用来开启或关闭 mybatis 的一些特性,比如可以用<setting name="lazyLoadingEnabled" value="true"/>来开启延迟加载,可以用<settings name="cacheEnabled" value="true"/>来开启二级缓存

  2. < typeAliases >
    设置别名
    批量设置别名时如果要自定义别名可以在实体类上添加 @Alias 注解

@Alias(“xxx”)
public class xxx {}
  1. < typeHandlers >
    用于处理 Java 类型和 Jdbc 类型之间的转换,mybatis 有许多内置的 TypeHandler ,比如 StringTypeHandler ,会处理 Java 类型 StringJdbc 类型 CHARVARCHAR 。这个标签用的不多
  2. < objectFactory >
    mybatis 会根据 resultTyperesultMap 的属性来将查询得到的结果封装成对应的 Java 类,它有一个默认的 DefaultObjectFactory ,用于创建对象实例,这个标签用的也不多
  3. < plugins >
    可以用来配置 mybatis 的插件,比如在开发中经常需要对查询结果进行分页,就需要用到 pageHelper 分页插件
<!-- PageHelper 分页插件 -->
<plugins>
  <plugin interceptor="com.github.pagehelper.PageInterceptor">
     <property name="helperDialect" value="mysql"/>
  </plugin>
</plugins>
  1. < environments >
    配置数据源
  2. < mappers >
    用来配置 mapper.xml 映射文件,这些 xml 文件里都是 SQL 语句

生命周期

在这里插入图片描述

动态 SQL

动态 SQL:根据不同的条件生成不同的 SQL 语句

  • if
<select id="find" parameterType="User" resultType="User" >
        SELECT * FROM tb_person WHERE id >= 2
        <if test="username != null and username != ''">
            AND username like concat("%", #{username}, "%");
        </if>
</select>

当满足 test 条件时,才会将< if >标签内的 SQL 语句拼接上去

  • choose( whenotherwise) 类似 switch
<select id="queryUserChoose" parameterType="map" resultType="User">
        select * from tb_person
        <where>
            <choose>
                <when test="username !=null">
                    username=#{username}
                </when>
                <when test="password !=null">
                   and password=#{password}
                </when>
                <otherwise>
                    and id=#{id}
                </otherwise>
            </choose>
        </where>
</select>
  • set
<update id="updateUser" parameterType="map">
        update tb_person
        <set>
            <if test="username !=null">
                username=#{username},
            </if>
            <if test="password !=null">
                password=#{password}
            </if>
        </set>
        where id=#{id}
</update>
  • trim
    以下 trim 可代替 where
<trim prefix="WHERE" prefixOverrides="AND | OR">
   ...
</trim>

以下 trim 可代替 set

<trim prefix="SET" prefixOverrides=",">
   ...
</trim>
  • foreach
<select id="batchFindUser" parameterType="list" resultType="user" >
        SELECT * FROM student WHERE id in
        <foreach collection="list" item="id" open="(" separator="," close=")">
          #{id}
        </foreach>
</select>
<select id="batchFindUser" parameterType="list" resultType="user" >
        SELECT * FROM tb_person
        <where>
   			<foreach collection="list" item="id" open="(" close=")" separator="or">
       			id = #{id}
   			</foreach>
   		</where>
</select>
  • sql
    可将重复的 SQL 片段(尽量只有 if )提取出来,然后在需要的地方,使用 < include > 标签进行引用
<sql id="if-username-password">
    <if test="username != null">
        username = #{username}
    </if>
    <if test="password != null">
        and password = #{password}
    </if>
</sql>
<select id="queryUserIf" parameterType="map" resultType="User">
    SELECT * FROM tb_person
    <where>
        <include refid="if-username-password"></include>
    </where>
</select>

多对一处理

多个学生对应一个老师

CREATE TABLE `tb_teacher` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT INTO `example`.`tb_teacher`(`id`, `name`) VALUES (1, 'hhhh')
CREATE TABLE `tb_student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `tid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `tid` (`tid`),
  CONSTRAINT `tb_student_ibfk_1` FOREIGN KEY (`tid`) REFERENCES `tb_teacher` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT INTO `example`.`tb_student`(`id`, `name`, `tid`) VALUES (1, '小一', 1)
INSERT INTO `example`.`tb_student`(`id`, `name`, `tid`) VALUES (2, '小二', 1)
INSERT INTO `example`.`tb_student`(`id`, `name`, `tid`) VALUES (3, '小三', 1)
INSERT INTO `example`.`tb_student`(`id`, `name`, `tid`) VALUES (4, '小四', 1)
INSERT INTO `example`.`tb_student`(`id`, `name`, `tid`) VALUES (5, '小五', 1)

子查询

<?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.mybatis.dao.StudentDao">
    <!--查询学生信息,并根据 tid 找到对应老师-->
    <select id="getStudent" resultMap="StudentTeacher">
        SELECT * FROM tb_student;
    </select>

    <resultMap id="StudentTeacher" type="com.mybatis.entity.Student">
        <result property="id" column="id"></result>
        <result property="name" column="name"></result>
        <!--复杂的属性
            对象:association
            集合:collection-->
        <association property="teacher" column="tid" javaType="com.mybatis.entity.Teacher" select="getTeacher"></association>
    </resultMap>

    <select id="getTeacher" resultType="com.mybatis.entity.Teacher">
        SELECT * FROM tb_teacher WHERE id=#{id};
    </select>
</mapper>
  • resultType:返回类型
  • resultMap:描述如何将结果集映射到 java 对象,属性有 idtype
    • id:唯一标识,column 表示从数据库查询的属性,property 表示把该属性赋给实体对象的哪个属性
    • resultcolumn 表示从数据库查询的属性,property 表示把该属性赋给实体对象的哪个属性
    • association:连接另一个表,javaType表示指定实体类属性的类型,property 表示指定的实体类属性
    • collection:连接另一个表,property 表示指定的实体类属性,javaType表示指定实体类属性的类型,ofType表示映射到 List 或集合中的对象类型

多表查询

<select id="getStudent2" resultMap="StudentTeacher2">
        SELECT s.id sid,s.name sname,t.name tname,t.id tid
        FROM tb_student s,tb_teacher t
        WHERE s.tid=t.id;
    </select>
    <resultMap id="StudentTeacher2" type="com.mybatis.entity.Student">
        <id property="id" column="sid"></id>
        <result property="name" column="sname"></result>
        <association property="teacher" javaType="com.mybatis.entity.Teacher">
            <result property="id" column="tid"></result>
            <result property="name" column="tname"></result>
        </association>
    </resultMap>

一对多处理

一个老师对应多个学生

<?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.mybatis.dao.TeacherDao">
    <select id="getTeacher" resultMap="TeacherStudent" parameterType="int">
        SELECT * FROM tb_teacher WHERE id=#{tid};
    </select>
    <resultMap id="TeacherStudent" type="com.mybatis.entity.Teacher">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <collection property="studentList" column="id" javaType="ArrayList" ofType="com.mybatis.entity.Student" select="getStudentByTeacherId"></collection>
    </resultMap>
    <select id="getStudentByTeacherId" resultType="com.mybatis.entity.Student">
        SELECT * FROM tb_student WHERE tid=#{tid};
    </select>


    <select id="getTeacher2" resultMap="TeacherStudent2" parameterType="int">
        SELECT s.id sid,s.name sname,t.id tid,t.name tname
        FROM tb_student s,tb_teacher t
        WHERE s.tid=t.id AND t.id=#{tid}
    </select>
    <resultMap id="TeacherStudent2" type="com.mybatis.entity.Teacher">
        <id property="id" column="tid"></id>
        <result property="name" column="tname"></result>
        <collection property="studentList" javaType="ArrayList" ofType="com.mybatis.entity.Student">
            <result property="id" column="sid"></result>
            <result property="name" column="sname"></result>
        </collection>
    </resultMap>
</mapper>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值