MyBatis的中文官方 : https://mybatis.org/mybatis-3/zh/index.html

W3School的Mybatis网站 : https://www.w3cschool.cn/mybatis/

介绍(Ibatis3就叫MyBatis)

MyBatis:是一款轻量级的ORM(对象-关系-映射)、半自动的持久层框架
作用是:将原来的 JDBC 的SQL 与 JAVA代码的硬编译、高耦合转为SQL 与 JAVA分离:SQL语句有开发人员XML配置
功能边界清晰 :SQL的就写SQL,JAVA就写JAVA

MyBatis的规范

原生配置,pom-Dao层-interface-dao-config-domainMapper --实现类
新的方式,pom-Mapper层-interface-config-domainMapper --仅需接口
两者区别就是原生的方式必须要写实现类
注意事项:假如domain的属性名没有与sql的表字段名相同,就需要起别名了(就是如果想成功运行 就是接收的domain的属性名要与表的字段相同)

Mybatis接入流程:

导入Maven依赖 + 配置.xml + SqlMapper.xml
config.xml:核心全局配置文件:包含了数据源连接池信息、事务管理器信息、系统运行环境今昔
sqlMaper.xml:保存了所有的sql映射信息,将sql抽取出来
创建SqlSession对象(和connliction都非线程安全,每次使用,应该使用新的对象):代表了与数据库的一次会话
由于线程不安全,所以要pojo要实现Serializable接口

入门代码实现

入门代码结构


Mysql + Mybatis + Log4j 的Maven配置

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

先配置一个映射文件 UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD MyBatis 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="UserMapper">
    <select id="findAll" resultType="com.zanglikun.domain.User">
        select * from user
    </select>
</mapper>

在配置一个 核心配置文件 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="dev1">

        <environment id="dev1">
            <!-- 用的是那个事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 数据源类型 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="740969606"/>
            </dataSource>
        </environment>

    </environments>

    <!-- 加载映射文件 将来加载的时候 直接在下面引入就行 -->
    <mappers>
        <mapper resource="com/zanglikun/mapper/UserMapper.xml"></mapper>
    </mappers>
</configuration>

创建一个数据库 名为:mybatis 内容如下:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL,
  `username` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `password` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'zhangsan123', '123', 12);
INSERT INTO `user` VALUES (2, 'lisi456', '456', 45);

SET FOREIGN_KEY_CHECKS = 1;

测试代码

    @Test
    public void test1() throws IOException {
        // 获取核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        // 使用核心配置文件获取Session工厂对象
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        // 获得Session 会话对象
        SqlSession sqlSession = build.openSession();
        // 使用 会话对象进行操作
        List<Object> list = sqlSession.selectList("UserMapper.findAll");
        System.out.println(list.get(0));
        System.out.println(list.get(1));
        // 释放资源
        sqlSession.close();
    }

测试结果:

配置文件介绍:

注意点

#{设置 parameterType后 可直接填对象的属性名}

mybatis 默认是用的JDBC事务,需要我们手动提交

        // Mysql 最终要提交事务
        sqlSession.commit();

MyBatis 核心配置文件

1 environments 标签

2 mappers 标签

3 proerties 标签

在 configuration 标签下引入

    <properties resource="jdbc.properties"></properties>
    ......
            <!--数据源类型-->
            <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>
   ......

4 typeAliases 标签

    <!-- 自定义别名 (放置的位置有顺序,请放置在properties标签后面) -->
    <typeAliases>
        <typeAlias type="com.zanglikun.domain.User" alias="user"></typeAlias>
    </typeAliases>

同时 Mybatis 也为我们提供了 一些常用类型的别名

Mybatis API

这里 最容易被忽视,也是他的核心

SqlSessionFactoryBuilder 用来创建SqlSessionFactory的

SqlSessionFactory

openSession()
// 设置是否自动提交
openSession(boolean autoCommit)

SqlSession 会话对象 默认不会自动提交,需要手动提交 ,是Mybatis非常强大的类,可以控制 执行语句、提交事务、获取映射器实例的方法。

操作事务的方法

void commit()
void rollback()

初级进阶篇

我们实际生产过程中 不会使用 传统方式 :通过在Service实现层进行 创建 Resources读取核心配置文件,然后进行SqlSessionFactoryBuilder 进行创建 创建工厂对象 SqlSessionFactory ,然后创建出SqlSession对象,进行Sql的执行,等等!

所以 我们要是用 Mybatis 动态接口代理方式 ,需要遵守一下规范

具体实现方式

在通过获取SqlSession 获取的mapper对象使用 userMapper.findByid(1);进行查询,以及获取结果。

除了模式更变之外,我们 还需要引入 :

Dynamic SQL 即 动态SQL

常用 标签是 if、choose、trim、foreach、where

where 标签 :等同于where 1=1恒等式,条件判断时,自动地处理 and 或者 or 条件。

if 标签:实例:

<select id = "findAll" paramerType="string">
    select * from user
    <where>
        <if test="username != null">
            username = #{username}
        </if>
      </where>
</select>

foreach 标签

等价于 select * from user where username in (LIST)

<select id = "findAll" paramerType=="list">
    select * from user
    <where>
        <foreach collection="list" open="age in(" close=")" item= "id" separator=",">
             #{id}
        </foreach>
    </where>
</select>

include 标签 与 sql 标签 : 抽取的语句

<sql id = "ABC">select * from user</sql>

<select id = "findAll" paramerType="string">
    <include refid = "ABC"></include>
    <where>
        <if test="username != null">
            username = #{username}
        </if>
      </where>
</select>

trim 标签 : 一般都用于插入

  • prefix:在trim标签内sql语句加上前缀
  • suffix:在trim标签内sql语句加上后缀
  • prefixOverrides:指定去除多余的前缀内容,如:prefixOverrides=“AND | OR”,去除trim标签内sql语句多余的前缀"and"或者"or"。
  • suffixOverrides:指定去除多余的后缀内容。
<insert>
    insert into user
    <trim prefix="(" suffix=")" suffixOverrides=",">
       <if test="username != null">
            username,
       </if>
       <if test="password != null">
            username,
       </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
        <if test="username != null">
          #{username,jdbcType=VARCHAR},
        </if>
        <if test="password != null">
          #{password,jdbcType=VARCHAR},
        </if>
    </trim>
</insert>

set 标签: 一般用于更新 自动添加set关键字,剔除追加到条件末尾的任何不相关的逗号

注意事项:set关键字 使用 if 组合的时候 每个if 必须结尾有 逗号

<update id = "changeCompany" paramerType="com.zanglikun.pojo.Company"> 
  update company_order
    <set>
      <if test="companyId != null">
        company_id = #{companyId,jdbcType=BIGINT},
      </if>
      <if test="orderCreated != null">
        order_created = #{orderCreated,jdbcType=TIMESTAMP},
      </if>
    </set>
  where order_id = #{orderId,jdbcType=BIGINT}
</update>

#{}与${}的区别,面试题

#{}是预编译,而${}直接取出,有sql注入的风险的sql语句是与预编译 、是占位符形式的,然后执行的是将占位符复制的sql ,而${}直接是值,作用范围:字段名、表名不支持预编译,所以必须使用${}

Mybatis 核心配置文件深入

typeHandlets 无论是Mybatis 在预处理语句(PrepareStatement)中设置一个参数时,还是从结果集中取出一个值的时候,都会经过这个 类型转换器 将获取的值 以合适的方式转成Java类型。

当然直接说这个 肯定是难以理解的 我们以 实例需求 解决:

我们数据库一个字段是 bigInt 时间戳 但是 我们需要从数据库查出开的时候 是Java time包下的Date类型。

一个User对象 有个字段 birthday 类型是 Date类型

我们插入对象的时候,直接插入对象,就会出错。

解决办法:

自定义 TypeHandles

为什么BaseTypeHandle<T> ?

当我们继承BaseTypeHandel时候,指定了泛型后,必须重写的一部分方法 就是以此返回的。

package com.zanglikun.handler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

/**
 * @author : zanglikun
 * @date : 2021/3/17 16:49
 * @Version: 1.0
 * @Desc : 类型转换
 */
public class DateTypeHandler extends BaseTypeHandler<Date> {

    // 将java类型 转换成 数据库需要的时间戳类型
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        long time = date.getTime();
        preparedStatement.setLong(i,time);
    }

    // s 是sql查询结果的字段名称
    // resultSet 是结果集
    @Override
    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        long aLong = resultSet.getLong(s);
        Date date = new Date(aLong);
        return date;
    }

    // i 是sql结果的字段位置索引
    // resultSet 是结果集
    @Override
    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        long aLong = resultSet.getLong(i);
        Date date = new Date(aLong);
        return date;
    }

    // i 是sql结果的字段位置索引
    // callableStatement 不是很清楚
    @Override
    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        long aLong = callableStatement.getLong(i);
        Date date = new Date(aLong);
        return date;
    }
}
    <typeHandlers>
        <typeHandler handler="com.zanglikun.handler.DateTypeHandler"></typeHandler>
    </typeHandlers>

完成,将来遇到 时间戳 就可也映射成 Data了

Plugins 标签

Mybatis 会使用 第三方 PageHelper 插件 进行增强分页功能

导包

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.4</version>
        </dependency>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>1.0</version>
        </dependency>

配置文件引入

    <!-- 插件 -->
    <plugins>
        <!-- PageHelper 5.0 之后的版本一律用 PageInterceptor 如果是4.0 请自行百度查找-->
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
        </plugin>
    </plugins>

使用 设置当前页、每页显示条数

        PageHelper.startPage(page,pagesize); // 进行分页

        PageHelper.clearPage();

        PageHelper.startPage(page, pageSize,false); // 通过PageInfo得到的total是-1

        PageHelper.startPage(page, pageSize,true); // 等价于 PageHelper.startPage(page, pageSize);

        PageHelper.startPage(page, pageSize); // 此语句默认会有count计数 可通过PageInfo.getTotal(),得到查询的结果数。

        PageHelper.orderBy("id desc");// 将结果查询的适合通过id 降序排列

总结

写到这里,必须要反思 这些标签 具体是干嘛的,不然,时间久了必忘记!!!

进阶内容,去看下 新文章:https://www.zanglikun.com/3320.html

注意 配置文件出错,请检查 文件顺序,如何看提示呢?配置文件出错,直接 run 项目 就会 抛一下问题:

"configuration" 的内容书询 必须按照下面顺序匹配 "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)"。

特殊说明:
上述文章均是作者实际操作后产出。烦请各位,请勿直接盗用!转载记得标注原文链接:www.zanglikun.com
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取全部资料 ❤