MyBatis 基本应用

本文档介绍了MyBatis的基本应用,包括快速入门步骤、环境搭建、增删改查操作、映射文件和核心配置文件解析。重点讲解了MyBatis的配置元素如environments、mapper标签,以及SqlSessionFactory、SqlSession和Dao层的实现方式。内容涵盖了从添加MyBatis依赖、创建数据库表、编写映射文件到使用SqlSession进行数据库操作的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

快速入门

开发步骤

  1. 添加 MyBatis 相关依赖
  2. 创建数据库数据表
  3. 创建对应实体类
  4. 编写映射文件 Mapper.xml
  5. 编写核心配置文件 SqlMapConfig.xml
  6. 编写测试类以及相关测试方法

环境搭建

  1. 引入 MyBatis 以及其他相关依赖

    • 添加 Maven 编译信息

      <properties>
          <maven.compiler.encode>UTF-8</maven.compiler.encode>
          <maven.compiler.source>11</maven.compiler.source>
          <maven.compiler.target>11</maven.compiler.target>
      </properties>
      
    • 引入依赖

      <dependencies>
          <!-- 数据库驱动 -->
          <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>8.0.23</version>
          </dependency>
          <!-- Mybatis -->
          <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis</artifactId>
              <version>3.5.6</version>
          </dependency>
          <!-- JUnit -->
          <!-- https://mvnrepository.com/artifact/junit/junit -->
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
          </dependency>
          <!-- Log4j2 -->
          <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
          <dependency>
              <groupId>org.apache.logging.log4j</groupId>
              <artifactId>log4j-core</artifactId>
              <version>2.14.1</version>
          </dependency>
      </dependencies>
      
    • 静态资源过滤

      <build>
          <resources>
              <resource>
                  <directory>src/main/java</directory>
                  <includes>
                      <include>**/*.xml</include>
                      <include>**/*.properties</include>
                  </includes>
                  <filtering>false</filtering>
              </resource>
              <resource>
                  <directory>src/main/resources</directory>
                  <includes>
                      <include>**/*.xml</include>
                      <include>**/*.properties</include>
                  </includes>
                  <filtering>false</filtering>
              </resource>
          </resources>
      </build>
      
  2. 创建数据库数据表 user

    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
        `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
        `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
        `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
        `password` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
        PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    
    SET FOREIGN_KEY_CHECKS = 1;
    
  3. 创建对应实体类 User

    package cn.worstone.bean;
    
    public class User {
        private String id;
        private String name;
        private String username;
        private String password;
    
        public User() {
        }
    
        public User(String id, String name, String username, String password) {
            this.id = id;
            this.name = name;
            this.username = username;
            this.password = password;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        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 + '\'' + ", name='" + name + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + '}';
        }
    }
    
  4. 编写映射文件 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">
    <mapper namespace="userMapper">
        <insert id="add" parameterType="User">
            INSERT INTO user (id, name, username, password) VALUES (#{id}, #{name}, #{username}, #{password})
        </insert>
        <update id="update" parameterType="User">
            UPDATE user SET name = #{name}, username = #{username}, password = #{password} WHERE id = #{id}
        </update>
        <delete id="delete" parameterType="String">
            DELETE FROM user WHERE id = #{id}
        </delete>
        <select id="selectOne" parameterType="User" resultType="User">
            SELECT id, name FROM user WHERE id = #{id}
        </select>
        <select id="selectList" parameterType="Map" resultType="User">
            SELECT id, name FROM user WHERE password = #{password} AND name LIKE #{name}"%"
        </select>
    </mapper>
    
  5. 编写核心配置文件 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>
        <settings>
            <setting name="logImpl" value="LOG4J2"/>
        </settings>
        <typeAliases>
            <package name="cn.worstone.bean"/>
        </typeAliases>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/spring?useUnicode=true&amp;characterEncoding=utf8&amp;nullCatalogMeansCurrent=true&amp;useSSL=false&amp;useJDBCCompliantTimezoneShift=true&amp;useLegacyDatetimeCode=false&amp;serverTimezone=UTC"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <!-- 使用 package 设置映射配置文件, namespace 不可以随意设置, 必须关联 Mapper 接口 -->
            <mapper resource="cn/worstone/mapper/UserMapper.xml"/>
        </mappers>
    </configuration>
    
  6. 编写测试类以及相关测试方法

    package cn.worstone.mapper;
    
    import cn.worstone.bean.User;
    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 org.junit.Before;
    import org.junit.Test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.UUID;
    
    public class UserMapperTest {
    
        private SqlSessionFactory sqlSessionFactory;
    
        // 在每个测试方法执行前执行的方法
        @Before
        public void before() throws IOException {
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
    
        @Test
        public void addTradition() {
            SqlSession sqlSession = this.sqlSessionFactory.openSession();
            User user = new User();
            user.setId(UUID.randomUUID().toString().toUpperCase());
            user.setName("XXX");
            user.setUsername("first");
            user.setPassword("123456");
            // namespace + "." + SQL 语句 id
            sqlSession.insert("userMapper.add", user);
            sqlSession.commit();
            sqlSession.close();
        }
    
        @Test
        public void updateTradition() {
            SqlSession sqlSession = this.sqlSessionFactory.openSession();
            User user = new User();
            user.setId("9DAC0A44-B8B9-4615-A4B0-5559739F70E6");
            user.setName("沈幼楚");
            user.setUsername("first");
            user.setPassword("654321");
            sqlSession.update("userMapper.update", user);
            sqlSession.commit();
            sqlSession.close();
        }
    
        @Test
        public void deleteTradition() {
            SqlSession sqlSession = this.sqlSessionFactory.openSession(true);
            sqlSession.delete("userMapper.delete", "9DAC0A44-B8B9-4615-A4B0-5559739F70E6");
            sqlSession.close();
        }
    
        @Test
        public void selectOneTradition() {
            SqlSession sqlSession = this.sqlSessionFactory.openSession();
            User user = sqlSession.selectOne("userMapper.selectOne", "9846f655-6e08-422a-940e-a420efc84847");
            System.out.println(user);
            sqlSession.close();
        }
    
        @Test
        public void selectListTradition() {
            SqlSession sqlSession = this.sqlSessionFactory.openSession();
            Map<String, Object> conditions = new HashMap<>();
            conditions.put("name", "沈");
            conditions.put("password", "123456");
            List<User> users = sqlSession.selectList("userMapper.selectList", conditions);
            for (User user : users) {
                System.out.println(user);
            }
            sqlSession.close();
        }
    }
    

    MySQL5.5.3 之后增加了 utf8mb4 字符编码,mb4most bytes 4。简单说 utf8mb4utf8 的超集并完全兼容 utf8,能够用四个字节存储更多的字符。

    但抛开数据库,标准的 UTF-8 字符集编码是可以用 1~4 个字节去编码 21 位字符,这几乎包含了世界上所有能看见的语言。然而在 MySQL 里实现的 utf8 最长使用 3 个字节,也就是只支持到了 Unicode 中的基本多文本平面(U 0000U FFFF),包含了控制符、拉丁文、中、日、韩等绝大多数国际字符,但并不是所有,最常见的是现在手机端常用的表情字符 Emoji 和一些不常用的汉字,如 “墅” ,这些需要四个字节才能编码出来。

    当数据库中要求能够存入这些表情或宽字符时,可以把字段定义为 utf8mb4,同时要注意 连接字符集 也要设置为 utf8mb4,否则在 严格模式 下会出现 Incorrect string value: /xF0/xA1/x8B/xBE/xE5/xA2… for column 'name' 这样的错误,非严格模式下此后的数据会被截断

    MyBatis 通过 package 标签设置映射配置文件时,映射配置文件中的 namespace 属性不可以随意设置,必须为 Mapper 接口的资源路径

    MyBatis 中的模糊查询可以通过两种方式实现:

    • SQL 语句 like 搭配 "%" 实现
    • SQL 语句 like 搭配传入参数 "...%" 实现

MyBatis 增删改查操作

  • 映射文件中使用 parameterType 指定参数的数据类型

  • 映射文件中使用 resultType 指定返回结果集的数据类型

  • 添加、删除、修改操作需要提交事务。可以设置 SqlSession 自动提交事务,也可以通过 SqlSessioncommit() 方法手动提交事务

  • SQL 语句中,使用 #{}${} 方式引入变量,变量名称需要与实体类属性名或者 Map 中设置的 key 一致

    MyBatis${} 方式是使用字符串拼接的方式拼接参数,容易造成 SQL 注入 的问题

MyBatis 映射文件概述

<?xml version="1.0" encoding="UTF-8"?>
<!-- 映射配置文件 DTD 文档类型定义 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 根标签, 其中 namespace 属性为当前映射文件的标识. -->
<!-- namespace.id 构成每个 MappedStatement 唯一标识 statement -->
<mapper namespace="userMapper">
    <!-- id 属性设置当前 SQL 语句的标识 -->
    <!-- parameterType 属性设置传入参数类型 -->
    <!-- resultType 属性设置返回结果参数类型 -->
    <!-- 与 select 标签类似的还有 insert、 update、 delete, 分别对应数据库的相关操作 -->
    <select id="selectList" parameterType="Map" resultType="User">
        <!-- SQL 语句 -->
        SELECT id, name FROM user WHERE password = #{password} AND name LIKE #{name}"%"
    </select>
</mapper>

命名空间(namespace)的作用有两个,一个是利用更长的全限定名来将不同的语句隔离开来,同时也实现了接口绑定。长远来看,只要将命名空间置于合适的 Java 包命名空间之中,你的代码会变得更加整洁,也有利于你更方便地使用 MyBatis。为了减少输入量,MyBatis 对所有具有名称的配置元素(包括语句,结果映射,缓存等)使用了如下的命名解析规则。

  • 全限定名(比如 “com.mypackage.MyMapper.selectAllThings”)将被直接用于查找及使用
  • 短名称(比如 “selectAllThings”)如果全局唯一也可以作为一个单独的引用。 如果不唯一,有两个或两个以上的相同名称(比如 “com.foo.selectAllThings”“com.bar.selectAllThings”),那么使用时就会产生**“短名称不唯一”的错误,这种情况下就必须使用全限定名**

MyBatis 核心配置文件

MyBatis 的核心配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
      • transactionManager(事务管理器)
      • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)

MyBatis 常用配置解析

environments 标签

MyBatis 可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

<environments default="development">
	<environment id="development">
    	<transactionManager type="JDBC">
      		<property name="..." value="..."/>
    	</transactionManager>
    	<dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
    	</dataSource>
  	</environment>
</environments>
  • MyBatis 中有两种类型的事务管理器(transactionManager

    • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。

    • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:

      <transactionManager type="MANAGED">
        	<property name="closeConnection" value="false"/>
      </transactionManager>
      

    如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。

  • dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。有三种内建的数据源类型

    • UNPOOLED – 这个数据源的实现会每次请求时打开和关闭连接。
    • POOLED – 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
    • JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。
mapper 标签
<mappers>
    <!-- 使用相对于类路径的资源引用 -->
  	<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
    <!-- 使用完全限定资源定位符(URL) -->
    <mapper url="file:///var/mappers/AuthorMapper.xml"/>
    <!-- 使用映射器接口实现类的完全限定类名 -->
    <mapper class="org.mybatis.builder.AuthorMapper"/>
    <!-- 将包内的映射器接口实现全部注册为映射器 -->
    <package name="org.mybatis.builder"/>
</mappers>

映射器类是 Java 类,它们包含 SQL 映射注解从而避免依赖 XML 文件。不过,由于 Java 注解的一些限制以及某些 MyBatis 映射的复杂性,要使用大多数高级映射(比如:嵌套联合映射),仍然需要使用 XML 配置。有鉴于此,如果存在一个同名 XML 配置文件,MyBatis 会自动查找并加载它

MyBatis 相应 API

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder 可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。

String resource = "org/mybatis/builder/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是 方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码**“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式**。

SqlSession openSession()
SqlSession openSession(boolean autoCommit)
SqlSession

SqlSession 提供了在数据库执行 SQL 命令所需的所有方法

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求方法作用域绝对不能将 SqlSession 实例的引用放在一个类的静态域甚至一个类的实例变量也不行也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession session = sqlSessionFactory.openSession()) {
	// 你的应用逻辑代码
}

在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。

数据库相关操作的方法:

<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)

事务相关操作的方法:

void commit()
void rollback()

MyBatis Dao 层实现

传统开发方式

编写接口 UserDao

package cn.worstone.dao;

import cn.worstone.bean.User;

import java.util.List;

public interface UserDao {
    List<User> selectList();
}

编写接口实现类 UserDaoImpl

package cn.worstone.dao.impl;

import cn.worstone.bean.User;
import cn.worstone.dao.UserDao;
import cn.worstone.utils.SessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

public class UserDaoImpl implements UserDao {

    @Override
    public List<User> selectList() {
        // 单例模式
        SqlSessionFactory sqlSessionFactory = SessionFactoryUtils.getSqlSessionFactory();
        List<User> users = null;
        try (SqlSession session = sqlSessionFactory.openSession()) {
            users = session.selectList("userMapper.selectList");
        }
        return users;
    }
}

测试方法

@Test
public void selectList() {
    UserDao userDao = new UserDaoImpl();
    List<User> users = userDao.selectList();
    for (User user : users) {
        System.out.println(user);
    }
}
代理开发方式

代理开发方式只需要编写 Mapper 接口(相当于 Dao 接口),由 Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法同 Dao 接口实现类方法类似。 Mapper 接口开发需要遵循以下规范:

  1. Mapper.xml 文件中的 namespaceMapper 接口的全限定名相同
  2. Mapper 接口方法名和 Mapper.xml 中定义的每个 SQL 语句id 相同
  3. Mapper 接口方法的输入参数类型和 Mapper.xml 中定义的每个 SQL 语句parameterType 的类型相同
  4. Mapper 接口方法的输出参数类型和 Mapper.xml 中定义的每个 SQL 语句resultType 的类型相同

映射配置文件

<?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="cn.worstone.mapper.UserMapper">
    <select id="selectList" resultType="User">
        SELECT id, name FROM user
    </select>
</mapper>

编写 Mapper 接口 UserMapper

package cn.worstone.mapper;

import cn.worstone.bean.User;

import java.util.List;
// 接口的资源路径
public interface UserMapper {
    List<User> selectList();
}

测试方法

@Test
public void selectListProxy() {
    try (SqlSession session = sqlSessionFactory.openSession()) {
        UserMapper userMapper = session.getMapper(UserMapper.class);
        List<User> users = userMapper.selectList();
        for (User user : users) {
            System.out.println(user);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值