当前位置: 首页 > news >正文

MyBatis框架(入门)

引言

在 Java 开发中,持久层框架起着至关重要的作用,它帮助开发者更高效地与数据库进行交互。MyBatis 作为一个优秀的基于 Java 的持久层框架,因其简单易用、灵活高效的特点,受到了广大开发者的喜爱。本文将结合笔记内容,对 MyBatis 的相关知识进行系统的整理和详细的讲解。

一、MyBatis框架概述

MyBatis 是一个优秀的基于 Java 的持久层框架,它内部对 JDBC 进行了封装,让开发者只需关注 SQL 语句,而无需关心 JDBC 的复杂代码,大大简化了开发过程。MyBatis 通过 XML 或者注解的方式配置要执行的 Statement 对象,将 Java 对象与 SQL 语句中的动态参数进行映射,最后执行 SQL 语句并将结果以 Java 对象的形式返回,采用了 ORM(对象关系映射)的思想。

 二、MyBatis 入门程序

2.1创建数据库和表结构

首先需要创建数据库和表结构,示例代码如下:

create database mybatis_db;
use mybatis_db;CREATE TABLE `user` (`id` int(11) NOT NULL auto_increment,`username` varchar(32) NOT NULL COMMENT '用户名称',`birthday` datetime default NULL COMMENT '生日',`sex` char(1) default NULL COMMENT '性别',`address` varchar(256) default NULL COMMENT '地址',PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;insert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (1,'老王','2018-02-27 17:47:08','男','北京'),(2,'熊大','2018-03-02 15:09:37','女','上海'),(3,'熊二','2018-03-04 11:34:34','女','深圳'),(4,'光头强','2018-03-04 12:04:06','男','广州');

 2.2 MyBatis 入门步骤

 创建 Maven 项目:创建一个 Maven Java 工程,并引入相关坐标。

<dependencies><!--mybatis核心包--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><!--mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><!-- 单元测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope></dependency><!-- 日志 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>
</dependencies>

编写User实现类:定义User类,属性尽量使用包装类型

为什么使用包装类型而不是基本类型?

1、 NULL 与 0 的本质区别

基本类型 (int) 默认值问题

private int age;  // 默认值为0

当 age=0 时,无法区分:

  • 用户确实输入了0岁

  • 用户根本没有输入年龄(此时应该为null)

 包装类型 (Integer) 的明确语义

private Integer age;  // 默认值为null
  • null 明确表示"未设置"或"未知"

  • 0 表示明确的0值

基本类型会强制将数据库NULL转换为默认值(如0),导致数据失真。

package cn.tx.domain;import java.io.Serializable;
import java.util.Date;public class User implements Serializable{private static final long serialVersionUID = 525400707336671154L;private Integer id;private String username;private Date birthday;private String sex;private String address;// 省略 getter 和 setter 方法以及 toString 方法
}

编写 UserMapper 接口和方法:定义 UserMapper 接口,包含查询所有用户的方法。

package cn.tx.mapper;import java.util.List;
import cn.tx.domain.User;public interface UserMapper {public List<User> findAll();
}

编写 UserMapper.xml 配置文件:在 resources 目录下创建 mapper 文件夹,并编写 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="com.qcbyjy.mapper.UserMapper"><select id="findAll" resultType="com.qcbyjy.domain.User">select * from user;</select>
</mapper>

其中,namespace 表示名称空间,用于查找 UserMapper 接口中的方法;id 属性对应 UserMapper 接口中的方法名;resultType 表示方法的返回值类型。

 编写主配置文件:在 resources 目录下创建 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="mysql"><!-- 配置具体的环境 --><environment id="mysql"><!-- 配置事务管理类型 --><transactionManager type="JDBC"/><!-- 配置是否需要使用连接池,POOLED使用,UNPOOLED不使用 --><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///mybatis_db"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><!-- 加载映射的配置文件 --><mappers><mapper resource="mappers/UserMapper.xml"/></mappers>
</configuration>

编写入门程序:编写测试类,测试查询所有用户的方法。

package cn.tx.test;import java.io.InputStream;
import java.util.List;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.Test;import cn.tx.domain.User;
import cn.tx.mapper.UserMapper;public class UserTest {@Testpublic void testFindAll() throws Exception {// 加载主配置文件,目的是构建SqlSessionFactory的对象InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");// 创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);// 使用SqlSessionFactory工厂对象创建SqlSession对象SqlSession session = factory.openSession();// 通过session创建UserMapper接口的代理对象UserMapper mapper = session.getMapper(UserMapper.class);// 调用查询所有的方法List<User> list = mapper.findAll();// 遍历集合for (User user : list) {System.out.println(user);}// 释放资源session.close();in.close();}
}

三、代理Dao方式的CRUD操作

3.1 UserMapper 接口和 UserMapper.xml 配置文件

 在 UserMapper 接口中定义增删改查等方法:

package cn.tx.mapper;import java.util.List;
import cn.tx.domain.User;public interface UserMapper {public List<User> findAll();public User findById(Integer userId);public void insert(User user);public void update(User user);public void delete(Integer userId);public List<User> findByName(String username);public Integer findByCount();
}

在 UserMapper.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.qcbyjy.mapper.UserMapper"><select id="findAll" resultType="com.qcbyjy.domain.User">select * from user</select><select id="findById" resultType="com.qcbyjy.domain.User" parameterType="int">select * from user where id = #{id};</select><insert id="insert" parameterType="com.qcbyjy.domain.User"><selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">select last_insert_id();</selectKey>insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})</insert><update id="update" parameterType="com.qcbyjy.domain.User">update user set username = #{username},birthday = #{birthday},sex = #{sex},address=#{address} where id = #{id}</update><delete id="delete" parameterType="Integer">delete from user where id = #{id}</delete><select id="findByName" resultType="com.qcbyjy.domain.User" parameterType="string"><!-- 第一种方式的SQL语句  -->select * from user where username  like #{username}<!-- 第二章SQL语句的编写 强调:'%${value}%'不能修改,固定写法(不推荐使用)  --><!-- SELECT * FROM  user where username LIKE  '%${value}%'--></select><select id="findByCount" resultType="int">select count(*) from user</select>
</mapper>

 3.2 UserTest 测试类

 编写测试类,对增删改查方法进行测试:

package cn.tx.test;import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;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.After;
import org.junit.Before;
import org.junit.Test;import cn.tx.domain.User;
import cn.tx.mapper.UserMapper;public class UserTest {private InputStream in;private SqlSession session;private UserMapper mapper;@Beforepublic void init() throws Exception {// 加载配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");// 创建工厂对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);// 创建Session对象session = factory.openSession();// 获取到代理对象mapper = session.getMapper(UserMapper.class);}@Afterpublic void destory() throws IOException {in.close();session.close();}@Testpublic void testFindAll() throws Exception {List<User> list = mapper.findAll();// 遍历for (User user : list) {System.out.println(user);}}@Testpublic void testFindById() throws Exception {User user = mapper.findById(41);System.out.println(user);}@Testpublic void testInsert() throws Exception {User user = new User();user.setUsername("美美");user.setBirthday(new Date());user.setSex("男");user.setAddress("顺义");mapper.insert(user);session.commit();System.out.println(user.getId());}@Testpublic void testUpdate() throws Exception {User user = mapper.findById(41);user.setUsername("小凤");mapper.update(user);session.commit();}@Testpublic void testDelete() throws Exception {mapper.delete(48);session.commit();}@Testpublic void testFindByName() throws Exception {List<User> list = mapper.findByName("王");for (User user : list) {System.out.println(user);}}@Testpublic void testFindByCount() throws Exception {Integer count = mapper.findByCount();System.out.println("总记录数:"+count);}
}

3.3 模糊查询符号使用的区别

  • #{}:可以实现 preparedStatement 向占位符中设置值,自动进行 Java 类型和 JDBC 类型转换,能有效防止 SQL 注入。可以接收简单类型值或 POJO 属性值,如果 parameterType 传输单个简单类型值,#{} 括号中可以是 value 或其它名称。
  • ${}:将传入的内容拼接在 SQL 中且不进行类型转换,只能接收简单类型值或 POJO 属性值,如果 parameterType 传输单个简单类型值,${} 括号中只能是 value。

 1. 安全查询示例

<!-- 使用#{} (推荐) -->
<select id="findUserById" parameterType="int" resultType="User">SELECT * FROM user WHERE id = #{userId}<!-- 等价于PreparedStatement: SELECT * FROM user WHERE id = ? -->
</select><!-- 使用${} (危险!) -->
<select id="findUserByName" parameterType="string" resultType="User">SELECT * FROM user WHERE username = '${value}'<!-- 等价于直接拼接: SELECT * FROM user WHERE username = '输入值' -->
</select>

攻击测试

// 如果传入: 
String name = "admin' OR '1'='1";// #{}方式执行:
SELECT * FROM user WHERE username = 'admin\' OR \'1\'=\'1'  -- 安全,作为整体字符串处理// ${}方式执行:
SELECT * FROM user WHERE username = 'admin' OR '1'='1'     -- 危险! 会返回所有用户

2、必须使用${value}的情况 

  • #{}生成的PreparedStatement可被缓存复用

  • ${}每次都会重新编译SQL

四、MyBatis参数详解

 MyBatis 中主要涉及两种参数类型:parameterType(输入参数)和 resultType(输出结果类型),下面分别介绍:

1. parameterType(输入参数类型)

用于指定 SQL 语句的输入参数类型,支持以下几类:

(1)简单数据类型
  • 类型:包括基本数据类型(如 intdoublelong)和包装类(如 IntegerString)。
  • 特点:框架支持简写,例如 intintegerInteger 等都可代表 java.lang.Integer
(2)POJO(JavaBean 实体类)对象类型
  • 场景:传入自定义的实体类(如 User)作为参数。
  • 注意:默认需使用全类名(如 com.qcbyjy.domain.User),但若在配置文件中注册了别名(见下文),可使用别名简化。
(3)POJO 包装对象类型
  • 场景:当需要传递多个实体类或附加参数时,可定义一个包装类(如 QueryVo),包含多个实体类属性(如 UserRole)。

 示例

public class QueryVo implements Serializable {private String name; // 自身属性private User user;   // 关联 User 对象private Role role;   // 关联 Role 对象// 省略 getter/setter
}
<select id="findByVo" parameterType="com.qcbyjy.domain.QueryVo" resultType="com.qcbyjy.domain.User">select * from user where username = #{user.username} <!-- 访问包装类中的 User 对象属性 -->
</select>

2. resultType(输出结果类型)

用于指定 SQL 语句执行结果的返回类型,支持以下几类:

(1)简单数据类型
  • 类型:与 parameterType 类似,如 intStringlong 等,用于统计结果(如计数)。
(2)POJO 数据类型
  • 场景:将查询结果映射为单个实体类对象(如 User)。
  • 条件:要求 SQL 查询的列名与 POJO 的属性名 完全一致,否则无法自动映射。
(3)resultMap(自定义结果映射)
  • 作用:当 SQL 列名与 POJO 属性名不一致时,通过 resultMap 手动映射列名和属性名。

示例: 

<!-- Mapper 中的查询语句 -->
<select id="findUsers" resultMap="userMap">select id _id, username _username, ... from user <!-- 列名带前缀 "_" -->
</select><!-- 定义 resultMap 映射关系 -->
<resultMap id="userMap" type="com.qcbyjy.domain.User"><result property="id" column="_id"/>       <!-- 将列 "_id" 映射到属性 "id" --><result property="username" column="_username"/><!-- 其他属性映射 -->
</resultMap>
  • 扩展resultMap 还可处理复杂映射(如一对一、一对多关系),适用于多表查询结果的封装。

 五、SqlMapConfig.xml 配置文件

 MyBatis 的核心配置文件,用于管理数据库连接、别名、映射文件等信息。以下是关键配置项:

1. 数据库信息管理(properties 标签)

  • 作用:统一管理数据库连接参数(如驱动、URL、用户名、密码),支持从外部文件读取。

 方式一:直接在配置文件中定义

<configuration><properties><property name="jdbc.driver" value="com.mysql.jdbc.Driver"/><property name="jdbc.url" value="jdbc:mysql:///mybatis_db"/><property name="jdbc.username" value="root"/><property name="jdbc.password" value="root"/></properties><!-- 其他配置 -->
</configuration>
方式二:引用外部属性文件(推荐)

1、创建 jdbc.properties 文件(放在类路径下):

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis_db
jdbc.username=root
jdbc.password=root

 2、在 SqlMapConfig.xml 中引用:

<configuration><properties resource="jdbc.properties"/> <!-- resource 为文件相对路径 --><!-- 配置数据库连接时使用 ${key} 取值 --><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>
</configuration>

2. 类型别名(typeAliases 标签)

  • 作用:为类名设置简短别名,简化配置中的全类名书写。

 方式一:为单个类定义别名

<typeAliases><typeAlias type="com.qcbyjy.domain.User" alias="user"/> <!-- 别名不区分大小写 -->
</typeAliases>
  • 使用:在 Mapper 中可直接用 resultType="user" 代替全类名。

 方式二:为包下所有类自动生成别名

<typeAliases><package name="com.qcbyjy.domain"/> <!-- 自动将包内类名作为别名(首字母不区分大小写) -->
</typeAliases>
  • 效果:若类名为 User,别名即为 user 或 User 等(忽略大小写)。

 3. 其他关键配置

 环境配置(environments)

<environments default="mysql"> <!-- default 指定默认环境 --><environment id="mysql"><transactionManager type="JDBC"/> <!-- 事务管理类型,JDBC 表示使用数据库自带事务 --><dataSource type="POOLED"> <!-- 连接池类型,POOLED 为数据库连接池 --><!-- 数据库连接参数 --></dataSource></environment>
</environments>

映射文件加载(mappers)

<mappers><mapper resource="mappers/UserMapper.xml"/> <!-- 引用 Mapper 配置文件 -->
</mappers>

总结

  • parameterType:控制输入参数类型,简单类型可简写,复杂类型需用包装类或实体类。
  • resultType:控制输出结果类型,列名与属性名一致时直接用 resultType,不一致时用 resultMap 手动映射。
  • SqlMapConfig.xml:通过 properties 管理数据库信息,typeAliases 简化类名,mappers 加载 SQL 映射文件,提升配置的可读性和可维护性。

相关文章:

  • Arduino UNO采集血压/心率/血氧/体温等数据传输到Blinker云平台 手机APP显示数据
  • 【深度学习基础】从感知机到多层神经网络:模型原理、结构与计算过程全解析
  • 计算机系统---TPU(张量处理单元)
  • Java——创建多线程的四种方式
  • 【大模型面试每日一题】Day 22:若训练中发现Loss突然剧烈波动(Spike),可能有哪些原因?如何定位和修复?
  • MySQL之储存引擎和视图
  • C语言:在 Win 10 上,gcc 如何编译 调用 Tcl/Tk 的C程序
  • Hugo安装Stack主题
  • DAY 4 缺失值的处理
  • Spring ioc和Aop
  • 【ROS2】虚拟机使用fishros脚本一键安装humble
  • Codeforces 1017 Div4(ABCDEFG)
  • 翻译:20250518
  • 【Python数据处理系列】输入txt,读取特定字符转换成特定csv数据并输出
  • C# String 格式说明符
  • C++模板进阶使用技巧
  • NY337NY340美光固态颗粒NC010NC012
  • wsl2中Ubuntu22.04配置静态IP地址
  • 基于STM32F103与Marvell88W8686的WIFI无线监控视频传输系统研发(论文)
  • 1.5 MouseDown,MouseUp,LostMouseCapture的先后顺序
  • 消费维权周报丨上周涉汽车类投诉较多,涉加油“跳枪”等问题
  • 央媒:设施老化、应急预案套模板,养老机构消防隐患亟待排查
  • 旅马大熊猫“福娃”“凤仪”平安回国
  • 证监会披露两起操纵市场处罚结果,今年来涉操纵股票罚没金额超7.5亿元
  • 梅花奖在上海|秦海璐:演了15年《四世同堂》,想演一辈子
  • 广东一驴友在英德野景点溺亡,家属被爆向21名同伴索赔86万