为了账号安全,请及时绑定邮箱和手机立即绑定

Mybatis持久层框架资料详解与入门教程

标签:
Java SSM 数据库
概述

Mybatis 是一个优秀的持久层框架,支持定制化 SQL、存储过程以及高级映射,能够将业务逻辑与数据库访问逻辑分离。它通过 XML 或注解的方式将 SQL 语句和 Java 方法进行映射,适用于多种数据库平台。Mybatis 提供了灵活的 SQL 执行能力和良好的可维护性。本文将详细介绍 Mybatis 持久层框架资料,包括其安装配置、核心概念、基本使用方法以及高级特性。

Mybatis简介

Mybatis 是一个优秀的持久层框架,支持定制化 SQL、存储过程以及高级映射。Mybatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取返回结果集的工作。Mybatis 通过 XML 或注解的方式将 SQL 语句和 Java 方法进行映射,从而将业务逻辑与数据库访问逻辑分离,使得程序结构更加清晰。

Mybatis是什么

Mybatis 是一款优秀的持久层框架,基于 Java 的持久化框架,与 Hibernate 类似,Mybatis 也是对象关系映射(ORM)框架。它并没有完全替代 JDBC 的所有功能,而是作为 JDBC 的封装层,可以与任何主流数据库产品一起使用。Mybatis 通过简单的 XML 或注解进行配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)映射成数据库中的记录。

Mybatis的优势和应用场景

优势:

  1. 灵活的 SQL 语句执行: Mybatis 支持自定义 SQL 语句,允许开发人员根据数据库特性编写高效 SQL。
  2. 与数据库无关: 由于使用自定义 SQL 语句,因此 Mybatis 与数据库无关,可以无缝地与任何数据库进行交互。
  3. 轻量级框架: Mybatis 相对于 Hibernate 更为轻量级,配置简单,学习成本低。
  4. 支持存储过程和自定义查询: Mybatis 支持存储过程和自定义查询,能够满足复杂业务逻辑。
  5. 良好的可维护性: Mybatis 将 SQL 语句与 Java 类分离,使得 SQL 语句易于管理和维护。

应用场景:

  1. 对数据库性能和灵活性要求较高: 当应用程序需要精细控制 SQL 语句和复杂的数据处理逻辑时,Mybatis 是很好的选择。
  2. 需要与多种数据库集成: Mybatis 可以与任何主流数据库产品一起使用,适合需要跨多个数据库平台的应用程序。
  3. 需要频繁执行存储过程: 对于涉及大量存储过程的应用场景,Mybatis 提供了很好的支持。
  4. 对性能要求较高的系统: Mybatis 允许开发人员编写高效的 SQL 语句,同时它还是轻量级框架,可以减少框架本身的消耗。
  5. 需要与已有的 SQL 代码集成: 对于已存在大量 SQL 代码的项目,可以直接使用 Mybatis 来进行数据库访问,无需重新编写代码。

Mybatis的安装和环境搭建

为了使用 Mybatis,需要在项目中添加 Mybatis 依赖。以 Maven 项目为例,展示如何在 pom.xml 文件中添加 Mybatis 依赖:

<dependencies>
    <!-- Mybatis核心依赖 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>

    <!-- MySQL数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.23</version>
    </dependency>

    <!-- C3P0数据库连接池 -->
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.4</version>
    </dependency>
</dependencies>

在配置好依赖后,需要创建 Mybatis 的配置文件 mybatis-config.xml,配置数据库连接信息以及 Mybatis 的其他配置。示例如下:

<?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/mydatabase"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/example/dao/UserMapper.xml"/>
    </mappers>
</configuration>

接下来,创建数据库表和对应的 Java 类。这里以一个简单的用户表为例:

CREATE TABLE users (
    id int(11) NOT NULL AUTO_INCREMENT,
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    PRIMARY KEY (id)
);

Java 类定义如下:

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

    // Getters and Setters
}

最后,需要创建 Mybatis 的 Mapper XML 文件,编写相关的 SQL 语句:

<?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.example.dao.UserMapper">
    <select id="selectUserById" resultType="com.example.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
</mapper>

至此,Mybatis 的安装和环境搭建已经完成。

Mybatis的核心概念

Mybatis 的核心概念包括 SqlSession、SqlSessionFactory、Mapper、Mapper 接口和 Mybatis 的配置文件。

SqlSession和SqlSessionFactory

SqlSession 是 Mybatis 中最重要的接口之一,是执行数据库操作的载体,可以理解为一个会话(session),它是线程不安全的。通过 SqlSession,可以执行 CRUD 操作、提交或回滚事务。

SqlSessionFactory 是一个工厂接口,用于创建 SqlSession。SqlSessionFactory 是线程安全的,可以通过 Mybatis 的配置文件创建 SqlSessionFactory。

下面是一个创建 SqlSessionFactory 的示例:

// 创建 SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));

// 通过 SqlSessionFactory 创建 SqlSession
SqlSession session = factory.openSession();

Mapper与Mapper接口

Mapper 是 Mybatis 中专门用于处理数据库操作的接口。通过 Mapper 接口,可以简化 SQL 语句的编写。Mapper 接口中的方法对应于 SQL 语句,可以通过注解或 XML 文件来定义这些 SQL 语句。

Mapper 接口通常定义如下:

public interface UserMapper {
    User selectUserById(int id);
}

相应的 Mapper XML 文件定义如下:

<mapper namespace="com.example.dao.UserMapper">
    <select id="selectUserById" resultType="com.example.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
</mapper>

Mybatis的配置文件(mybatis-config.xml)

Mybatis 的配置文件 mybatis-config.xml 包含了数据库连接信息、事务管理器配置、环境配置等重要信息。以下是配置文件的部分示例:

<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/mydatabase"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/example/dao/UserMapper.xml"/>
    </mappers>
</configuration>

其中 <environments> 标签用于配置数据库环境,<transactionManager> 标签用于配置事务管理器,<dataSource> 标签用于配置数据源,<mappers> 标签用于配置 Mapper 文件。

Mybatis的基本使用

Mybatis 的基本使用包括 CRUD 操作、结果集映射和动态 SQL 的编写。这些内容是 Mybatis 使用中最基础和常见的部分。

CRUD操作的实现

CRUD 是指创建(Create)、读取(Read)、更新(Update)和删除(Delete)操作。下面通过一个简单的例子来展示如何使用 Mybatis 进行 CRUD 操作。

首先,定义一个 User 类:

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

    // Getters and Setters
}

接下来定义 UserMapper 接口:

public interface UserMapper {
    User selectUserById(int id);
    List<User> selectAllUsers();
    int insertUser(User user);
    int updateUser(User user);
    int deleteUser(int id);
}

对应的 Mapper XML 文件:

<mapper namespace="com.example.dao.UserMapper">
    <select id="selectUserById" resultType="com.example.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
    <select id="selectAllUsers" resultType="com.example.User">
        SELECT * FROM users
    </select>
    <insert id="insertUser">
        INSERT INTO users (username, password) VALUES (#{username}, #{password})
    </insert>
    <update id="updateUser">
        UPDATE users SET username = #{username}, password = #{password} WHERE id = #{id}
    </update>
    <delete id="deleteUser">
        DELETE FROM users WHERE id = #{id}
    </delete>
</mapper>

在实际的项目中,还需要编写 Mybatis 的配置文件 mybatis-config.xml

<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/mydatabase"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/example/dao/UserMapper.xml"/>
    </mappers>
</configuration>

接下来编写测试代码:

public class MybatisTest {
    public static void main(String[] args) {
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
        SqlSession session = factory.openSession();

        UserMapper mapper = session.getMapper(UserMapper.class);

        // 添加用户
        User user = new User();
        user.setUsername("testUser");
        user.setPassword("testPassword");
        mapper.insertUser(user);
        session.commit();

        // 查询用户
        User userById = mapper.selectUserById(1);
        System.out.println(userById);

        // 查询所有用户
        List<User> allUsers = mapper.selectAllUsers();
        System.out.println(allUsers);

        // 更新用户
        user.setUsername("updatedUser");
        mapper.updateUser(user);
        session.commit();

        // 删除用户
        mapper.deleteUser(1);
        session.commit();

        session.close();
    }
}

结果集映射(ResultMap)

Mybatis 通过 ResultMap 来映射数据库中的字段到 Java 对象的属性。ResultMap 定义了列和属性之间的映射关系,支持一对一和一对多的映射。

下面通过一个简单的例子来展示如何使用 ResultMap。假设有一个用户表 users 和一个订单表 orders,用户表中有用户信息,订单表中有订单信息。每个用户可以有多个订单。

首先,定义 User 类和 Order 类:

public class User {
    private int id;
    private String username;
    private String password;
    private List<Order> orders;

    // Getters and Setters
}

public class Order {
    private int id;
    private int userId;
    private String orderName;
    private Date orderDate;

    // Getters and Setters
}

对应的 Mapper XML 文件:

<mapper namespace="com.example.dao.UserMapper">
    <resultMap id="UserResultMap" type="com.example.User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="password" column="password"/>
        <collection property="orders" ofType="com.example.Order" select="selectOrders" column="id" />
    </resultMap>

    <select id="selectUserById" resultMap="UserResultMap">
        SELECT * FROM users WHERE id = #{id}
    </select>

    <select id="selectOrders" resultType="com.example.Order">
        SELECT * FROM orders WHERE user_id = #{userId}
    </select>
</mapper>

在上面的配置中,<resultMap> 标签定义了用户和订单之间的映射关系,selectOrders 是一个调用另一个 SQL 语句的方法,通过 column 属性传递参数。

动态SQL的编写

Mybatis 动态 SQL 用于根据不同的条件生成不同的 SQL 语句。常用的动态 SQL 标签有 <if><choose><when><otherwise><foreach><set> 等。

下面通过一个例子来展示如何使用动态 SQL。假设需要一个查询语句,可以根据不同的参数条件查询用户。

<select id="selectUserByCondition" resultType="com.example.User">
    SELECT * FROM users
    <where>
        <if test="username != null">
            AND username = #{username}
        </if>
        <if test="password != null">
            AND password = #{password}
        </if>
    </where>
</select>

在上面的配置中,<where> 标签用于生成 SQL 的 WHERE 子句,<if> 标签用于根据条件生成 SQL。

Mybatis的高级特性

Mybatis 的高级特性包括一级和二级缓存、分页查询、插件开发与拦截器和类型处理器。

一级和二级缓存

Mybatis 支持一级缓存和二级缓存。

一级缓存:
一级缓存是 SqlSession 级别的缓存,每个 SqlSession 都有一个本地缓存,当执行 SQL 语句时,结果会先被缓存起来。一级缓存默认开启,不需要额外的配置。

二级缓存:
二级缓存是基于 Mapper 的缓存,同一个 Mapper 的所有 SqlSession 都可以共享这个缓存。二级缓存默认是关闭的,需要在 Mapper XML 文件中进行配置。

示例配置:

<cache />

默认情况下,二级缓存会为每个 Mapper 创建一个缓存实例。也可以自定义缓存策略和实现:

<cache
  eviction="FIFO"  <!-- 启用缓存的策略,默认是 LRU -->
  flushInterval="60000"  <!-- 缓存刷新间隔,默认是未指定 -->
  size="100"  <!-- 缓存的最大容量,默认是 1024 -->
  readOnly="true"  <!-- 是否只读缓存,默认是 false -->
/>

分页查询

Mybatis 提供了分页查询的支持,可以通过插件或在 SQL 语句中使用动态 SQL 来实现分页。

通过插件实现分页:
Mybatis 提供了插件机制可以实现分页插件。下面是一个简单的分页插件示例:

public class PaginationPlugin extends Interceptor {
    @Override
    public Object intercept(Invocation invocation) {
        Object target = invocation.getTarget();
        Method method = invocation.getMethod();

        if (method.getName().equals("select")) {
            MappedStatement mappedStatement = (MappedStatement) target;
            Configuration configuration = mappedStatement.getConfiguration();

            // 获取原 SQL 语句
            String originalSql = mappedStatement.getSqlSource().getOriginalSql();
            // 获取参数
            Object[] args = invocation.getArgs();

            // 分页参数
            int pageSize = (Integer) args[1];
            int skip = (Integer) args[2];

            // 构造新的 SQL 语句
            String newSql = originalSql + " limit " + skip + ", " + pageSize;
            // 构造新的 MappedStatement
            MappedStatement newMappedStatement = configuration.newMappedStatement(
                mappedStatement.getId(),
                new SqlSource(originalSql) {
                    @Override
                    public BoundSql getBoundSql(Object parameterObject) {
                        return new BoundSql(configuration, newSql, parameterObject);
                    }
                },
                mappedStatement.getSqlCommandType(),
                mappedStatement.getSqlId(),
                mappedStatement.getParameters(),
                mappedStatement.getKeyProperty(),
                mappedStatement.getKeyColumns(),
                mappedStatement.getKeyResultSet(),
                mappedStatement.getResultMap(),
                mappedStatement.getKeyResultType(),
                mappedStatement.getKeyResultHandler(),
                mappedStatement.getKeyResultMaps(),
                mappedStatement.getKeyResultSetType(),
                mappedStatement.getKeyResultSetHandler(),
                mappedStatement.getKeyResultMapType(),
                mappedStatement.getKeyResultHandlerType()
            );

            // 调用新的 MappedStatement
            return invocation.proceed(new Object[]{newMappedStatement, args[0]});
        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
public void setProperties(Properties properties) {
    // 设置属性
}
}

通过动态 SQL 实现分页:
在 Mapper XML 文件中使用动态 SQL 实现分页:

<select id="selectUserByPage" resultType="com.example.User">
    SELECT * FROM users
    <if test="skip != null">
        LIMIT #{skip}, #{pageSize}
    </if>
</select>

插件开发与拦截器

Mybatis 提供了插件机制,可以通过插件来扩展 Mybatis 的功能。插件通过实现 org.apache.ibatis.plugin.Interceptor 接口来实现。

下面是一个简单的插件示例,用于拦截所有的 SQL 语句并打印出来:

public class LoggingPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        Method method = invocation.getMethod();
        Object[] args = invocation.getArgs();

        System.out.println("Intercepting method: " + method.getName());
        System.out.println("Target: " + target);
        System.out.println("Arguments: " + Arrays.toString(args));

        Object result = invocation.proceed();

        System.out.println("Result: " + result);

        return result;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 设置属性
    }
}

插件配置需要在 mybatis-config.xml 中进行:

<plugins>
    <plugin interceptor="com.example.plugin.LoggingPlugin">
        <!-- 设置插件的属性 -->
    </plugin>
</plugins>

类型处理器(TypeHandler)

Mybatis 提供了类型处理器(TypeHandler)来处理 Java 类型和数据库类型之间的转换。默认情况下,Mybatis 会使用一些常见的类型处理器,如 IntegerTypeHandlerStringTypeHandler 等。可以通过实现 org.apache.ibatis.type.TypeHandler 接口来创建自定义的类型处理器。

下面是一个简单的自定义类型处理器示例,用于处理 Java 的 Date 类型和数据库的 VARCHAR 类型之间的转换:

public class CustomDateTypeHandler implements TypeHandler<Date> {
    @Override
    public void setParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
            ps.setNull(i, Types.VARCHAR);
        } else {
            ps.setString(i, new SimpleDateFormat("yyyy-MM-dd").format(parameter));
        }
    }

    @Override
    public Date getResult(ResultSet rs, String columnName) throws SQLException {
        String dateStr = rs.getString(columnName);
        if (dateStr == null) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
    }

    @Override
    public Date getResult(ResultSet rs, int columnIndex) throws SQLException {
        String dateStr = rs.getString(columnIndex);
        if (dateStr == null) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
    }

    @Override
    public Date getResult(Statement rs, int columnIndex) throws SQLException {
        String dateStr = rs.getString(columnIndex);
        if (dateStr == null) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
    }
}

在配置文件中注册自定义类型处理器:

<typeHandlers>
    <typeHandler handler="com.example.handler.CustomDateTypeHandler" javaType="java.util.Date" jdbcType="VARCHAR"/>
</typeHandlers>
Mybatis与Spring集成

Mybatis 与 Spring 集成可以让 Mybatis 更加方便地使用。Spring 提供了 MybatisTemplateSqlSessionTemplate 支持 Mybatis 的事务管理。同时,Spring 也提供了 @Mapper 注解和 Mapper 接口扫描功能。

Mybatis-Spring的引入

为了使用 Mybatis 和 Spring 的集成功能,需要在项目中引入 Mybatis-Spring 的依赖:

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
</dependency>

@Mapper注解与Mapper扫描

@Mapper 注解用于标记 Mapper 接口,Spring 会自动扫描并创建 Mapper 接口的实例。

例如:

@Mapper
public interface UserMapper {
    User selectUserById(int id);
}

@MapperScan 注解用于扫描 Mapper 接口所在的包,例如:

@Configuration
@MapperScan("com.example.mapper")
public class MybatisConfig {
    // Mybatis 配置
}

事务管理

Spring 提供了声明式事务管理和编程式事务管理。可以通过 @Transactional 注解来声明式地管理事务。

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public void addUser(User user) {
        userMapper.insertUser(user);
    }
}

事务管理器配置

在 Spring 配置文件中,可以通过 DataSourceTransactionManager 来配置事务管理器:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
Mybatis调试与优化

使用日志工具(如log4j)进行调试

Mybatis 提供了日志工具的支持,可以通过日志来查看 SQL 语句和参数等信息。下面是使用 log4j 配置 Mybatis 日志的示例:

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <logger name="com.example" level="debug" />
    <logger name="org.apache.ibatis" level="debug" />
    <root level="info">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

性能优化技巧

  1. 缓存的使用: 合理使用缓存可以减少数据库访问次数,提高性能。
  2. 连接池的使用: 使用数据库连接池可以减少连接的创建和销毁时间,提高性能。
  3. 动态 SQL 的优化: 通过动态 SQL 生成合适的 SQL 语句,避免不必要的查询。
  4. 批量操作: 使用批量插入、更新或删除可以减少数据库交互次数,提高性能。
  5. 适当的索引: 为数据库表添加适当的索引可以加快查询速度。

具体示例

缓存的使用
<cache />
<cache eviction="FIFO" flushInterval="60000" size="100" readOnly="true" />
连接池的使用
<dataSource type="POOLED">
    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
    <property name="username" value="root"/>
    <property name="password" value="password"/>
</dataSource>
索引的使用
CREATE INDEX idx_username ON users(username);

常见问题与解决方案

  1. 查询速度慢: 检查 SQL 语句是否高效,是否需要添加索引。
  2. 数据库连接问题: 检查数据库连接配置是否正确,是否连接超时。
  3. 数据不一致: 检查事务是否提交成功,是否有未提交的事务。
  4. 性能问题: 检查缓存是否有效,是否有不必要的数据库操作。

具体示例

查询速度慢
SELECT * FROM users WHERE username = 'testUser';
数据库连接问题
<property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
数据不一致
@Transactional
public void addUser(User user) {
    userMapper.insertUser(user);
}

通过本文的介绍,你应该已经掌握了 Mybatis 的基本概念、使用方法和高级特性。希望这些内容能够帮助你在实际项目中更有效地使用 Mybatis。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消