[Study]MyBatis

Posted Spring-_-Bear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Study]MyBatis相关的知识,希望对你有一定的参考价值。

文章目录

一、MyBatis 概述及案例

1.1 MyBatis 简介

  1. MyBatis 最初是 Apache 的一个开源项目 iBatis, 2010 年 6 月 这个项目由 Apache Software Foundation 迁移到了 Google Code。随着开发团队转投 Google Code 旗下, iBatis3.x 正式更名为 MyBatis。代码于 2013 年 11 月迁移到 GithubiBatis 一词来源于 internetabatis 的组合,是一个基于 Java 的持久层框架。 iBatis 提供的持久层框架包括 SQL MapsData Access Objects(DAO)

  2. MyBatis 的特点

    1. 支持定制化 SQL、存储过程以及高级映射
    2. 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
    3. 使用简单的 XML 或注解用于配置映射,将接口和 JavaPOJOPlain Old Java Objects)映射成数据库中的记录
    4. 一个半自动的 ORMObject Relation Mapping)框架

1.2 持久化技术间的对比

  1. JDBC

    1. SQL 夹杂在 Java 代码中,耦合度高,导致硬编码内伤
    2. 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
    3. 代码冗长,开发效率低
  2. Hibernate 和 JPA

    1. 操作简便,开发效率高
    2. 程序中的长难复杂 SQL 需要绕过框架
    3. 内部自动生成的 SQL,不容易做特殊优化
    4. 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难
    5. 反射操作太多,导致数据库性能下降
  3. MyBatis

    1. 轻量级,性能出色
    2. SQL 和 Java 编码分开,功能边界清晰。Java 代码专注业务、SQL 语句专注数据
    3. 开发效率稍逊于 Hibernate,但是完全能够接受

1.3 第一个 MyBatis 程序

  1. 创建 maven 工程,设置工程打包方式为 jar 包,引入相关依赖

    <packaging>jar</packaging>
    
    <dependencies>
        <!-- Mybatis 核心 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!-- junit 测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- mysql 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
    </dependencies>
    
  2. resources 目录下创建 MyBatis 的核心配置文件 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>
        <!-- 设置连接数据库的环境 -->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                    <property name="username" value="project"/>
                    <property name="password" value="project"/>
                </dataSource>
            </environment>
        </environments>
        <!-- 引入映射文件 -->
        <mappers>
            <mapper resource="mappers/UserMapper.xml"/>
        </mappers>
    </configuration>
    
  3. 创建 POJO 类

    /**
     * @author Spring-_-Bear
     * @datetime 6/11/2022 9:24 AM
     */
    public class User 
        private String username;
        private String password;
    
    
    
  4. 创建对应 POJO 类的 Mapper,MyBatis中 的 mapper 接口相当于以前的 DAO。区别在于mapper 仅仅是接口,不需要提供实现类(由 MyBatis 提供代理实现类)

    /**
     * @author Spring-_-Bear
     * @datetime 2022/4/13 16:01
     */
    public interface UserMapper 
        List<User> getAllUsers();
    
    
  5. 在 resources/mapper 目录下创建第 4 步中创建的 Mapper 接口对应的 MyBatis *.xml 映射文件。映射文件的命名规则:对应的接口 + .xml 如 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="edu.whut.bear.mybatis.dao.UserMapper">
        <!-- SQL 语句 id 需与接口中对应的方法名一致 -->
        <!-- List<User> getAllUsers(); -->
        <select id="getAllUsers" resultType="edu.whut.bear.mybatis.pojo.User">
            select * from t_user
        </select>
    </mapper>
    
  6. 在 MyBatis 的核心配置文件 mybatis-config.xml 引入 UserMapper.xml 文件,如第 2 步中的 20 行

  7. 测试一把

    @Test
    public void getAllUsers() throws IOException 
        // 读取 MyBatis 核心配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        // 创建 SqlSessionFactoryBuilder 对象以获得 sql 会话工厂对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 获取 sql 会话工厂对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        // 生产会话,传入参数 true,自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        // 通过代理模式创建 UserMapper 接口的代理实现类对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 调用方法,执行 sql 语句查询所有用户信息
        List<User> allUsers = userMapper.getAllUsers();
        allUsers.forEach(System.out::println);
    
    
  8. 项目结构如下

1.4 加入 log4j 日志功能

  1. pom.xml 中引入依赖

    <!-- log4j 日志 -->
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>
    
  2. resources 目录下新建 log4j 的核心配置文件 log4j.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
        <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
            <param name="Encoding" value="UTF-8"/>
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%-5p %dMM-dd HH:mm:ss,SSS %m (%F:%L) \\n"/>
            </layout>
        </appender>
        <logger name="java.sql">
            <!-- 日志级别:FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试) -->
            <level value="debug"/>
        </logger>
        <logger name="org.apache.ibatis">
            <level value="info"/>
        </logger>
        <root>
            <level value="debug"/>
            <appender-ref ref="STDOUT"/>
        </root>
    </log4j:configuration>
    

1.5 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>
    <!--                 各标签的配置顺序:
            properties?,settings?,typeAliases?,
            typeHandlers?,objectFactory?,objectWrapperFactory?,
            reflectorFactory?,plugins?,environments?,
            databaseIdProvider?,mappers?
    -->
    <properties resource="jdbc.properties"/>

    <typeAliases>
        <!-- 自定义 POJO 类别名,不区分大小写,不设置 alias 属性默认值为类名 -->
        <!-- <typeAlias type="com.bear.mybatis.pojo.User" alias="User"/> -->
        
        <!-- 以包为单位,为包下的每个类设置默认别名为类名且不区分大小写 -->
        <package name="com.bear.mybatis.pojo"/>
    </typeAliases>

    <!-- 设置连接数据库的环境 -->
    <environments default="development">
        <environment id="development">
            <!-- JDBC:原生 API 进行事务操作管理 || MANAGED:被管理,如 Spring 中的 AOP -->
            <transactionManager type="JDBC"/>
            <!-- POOLED:使用数据库连接池 || UNPOOLED:不使用数据库连接池 || JNDI:调用上下文中的数据源 -->
            <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>
    <!-- 引入映射文件 -->
    <mappers>
		<!-- <mapper resource="mappers/UserMapper.xml"/> -->
        
        <!-- 以包为单位引入映射文件时,目录名(创建目录时以 / 分割而非 .)需与接口所在包名一致且映射文件名也需与接口名一致 -->
        <package name="com.bear.mybatis.mapper"/>
    </mappers>
</configuration>

1.6 SqlSessionUtils.java

/**
 * @author Spring-_-Bear
 * @datetime 6/11/2022 10:01 AM
 */
public class SqlSessionUtils 
    public static SqlSession getSqlSession() throws IOException 
        // 读取 MyBatis 核心配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        // 创建 SqlSessionFactoryBuilder 对象以获得 sql 会话工厂对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 获取 sql 会话工厂对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        // 生产会话,传入参数 true,自动提交事务
        return sqlSessionFactory.openSession(true);
    

二、获取参数值

2.1 获取参数的两种方式

  1. $ 的本质就是字符串拼接(使用 $ 时注意添加单引号以处理字符串拼接问题)
  2. # 的本质就是占位符赋值

2.2 获取单个字面量参数

<!-- $ 形式获取参数 -->
<!-- User getUserByUsername(String username); -->
<select id="getUserByUsername" resultType="User">
    <!-- 花括号中的变量名可任意取,注意单引号问题 -->
    select * from t_user where username = '$username'
</select>

<!-- # 形式获取参数 -->
<!-- User getUserByUsername(String username); -->
<select id="getUserByUsername" resultType="User">
    <!-- 花括号中的变量名可任意取 -->
    select * from t_user where username = #username
</select>

2.3 获取多个字面量参数

MyBatis 底层将参数封装在了 Map 集合中,键为 arg0、arg1······ 或 param1、param2······

<!-- param 从 1 开始计数 -->
<!-- User getUserByUsernameAndPassword(String username, String password); -->
<select id="getUserByUsernameAndPassword" resultType="User">
    select * from t_user where username = #param1 and password = #param2
</select>

<!-- arg 从 0 开始计数 -->
<!-- User getUserByUsernameAndPassword(String username, String password); -->
<select id="getUserByUsernameAndPassword" resultType="User">
    select * from t_user where username = #arg0 and password = #arg1
</select>

2.4 Map 传参获取参数

// UserMapper.java
List<User> getUserByMapParam(Map<String, String> map);

// UserMapperTest.java
@Test
public void getUserByMap() 
    SqlSession sqlSession = SqlSessionUtils.getSqlSession();
    ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
    Map<String, String> paramMap = new HashMap<>();
    paramMap.put("username", "admin");
    paramMap.put("password", "admin");
    List<User> userByMap = mapper.getUserByMap(paramMap);
    userByMap.forEach(System.out::println);

<!-- UserMapper.xml -->
<!-- List<User> getUserByMapParam(Map<String, String> map); -->
<select id="getUserByMapParam" resultType="User">
    select * from t_user where username = #username and password = #password
</select>

2.5 POJO 对象获取参数

<!-- int saveUser(User user); -->
<insert id="saveUser" >
    insert into t_user values (null, #username, #password, #age, #sex, #email)
</insert>

2.6 @Param 命名参数

List<User> login(@Param("username") String username, @Param("password") String password);
<!-- List<User> login(@Param("username") String username, @Param("password") String password); -->
<select id="login" resultType="User">
    select * from t_user where username = #username and password = #password
</select>

三、SELECT

3.1 查询用户总记录数

<!-- 使用 MyBatis 中的默认类型别名 integer -->
<!-- int getUserCounts(); -->
<select id="getUserCounts" resultType="integer">
    select count(id) from t_user
</select>

3.2 查询结果封装为 Map

  1. 将数据库表的每个字段依次封装为一条记录

    // UserMapper.java
    List<Map<String, Object>> getAllUsersToMap();
    
    // UserMapperTest.java
    @Test
    public void getAllUsersToMap() throws IOException 
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<Map<String, Object>> allUsersToMap = userMapper.getAllUsersToMap();
        // Output:username=0121910870207, password=0121910870207
        allUsersToMap.forEach(System.out::println);
    
    
    <!-- UserMapper.xml -->
    <!-- List<Map<String, Object>> getAllUsersToMap(); -->
        <select id="getAllUsersToMap" resultType="map">
            select *
            from t_user;
        </select>
    
  2. 以指定的字段为 key,查询结果 POJO 对象为值,封装为 Map

    // UserMapper.java
    @MapKey("real_name")
    以上是关于[Study]MyBatis的主要内容,如果未能解决你的问题,请参考以下文章

    mybatis学习 -每天一记(驼峰命名匹配)

    SpringBoot+Mybatis关于开启驼峰映射的设置

    Mybatis处理列名—字段名映射— 驼峰式命名映射

    mybatis支持属性使用驼峰的命名

    MyBatis驼峰命名方法问题解决方法

    mybatis 支持属性使用驼峰的命名 返回map为啥不支持