Mybatis框架 框架 框架(Framework)是一种半成品软件 ,它提供了一套完整的、可重用的设计、代码和库,旨在帮助开发者解决特定领域或类型的问题 。框架通常规定了软件系统的整体结构、主要组件及其之间的关系,以及它们之间的交互方式。框架相对于库不仅提供了一组工具,还规定了应用的结构和流程。开发者需要在框架的约束下工作,通过实现特定的接口或继承特定的类来完成应用的功能。
JDBC的问题 JDBC(Java Database Connectivity)是Java语言中用于执行SQL语句的应用程序接口(API),它为Java程序提供了一种与各种关系型数据库进行交互的标准方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package org.example.servlet;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.SQLException;public class JDBCexample { public static void main (String[] args) throws Exception { String jdbcURL = "jdbc:mysql://localhost:3306/willmo_cms" ; String username = "root" ; String password = "root" ; try (Connection connection = DriverManager.getConnection(jdbcURL, username, password)) { if (connection != null ) { System.out.println("Connected to the database!" ); } } catch (SQLException e) { e.printStackTrace(); } try (Connection connection = DriverManager.getConnection(jdbcURL, username, password); PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO test_table1 (id, Name,age) VALUES (12, 'JDBC插入测试',123)" )) { int rowsAffected = preparedStatement.executeUpdate(); if (rowsAffected > 0 ) { System.out.println("A new row has been inserted." ); } } } }
这对我们来说有几个问题
繁冗赘余
SQL和java代码紧紧耦合在一起,难以分开处理
Mybatis正是为了解决这个问题。
Mybatis MyBatis 是一款优秀的持久层框架 ,它支持自定义 SQL 、存储过程以及高级映射 。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
使用
步骤
核心任务
关键产出
简要说明
1
项目初始化
pom.xml(Maven)
在项目中引入 MyBatis 及其数据库驱动等依赖。
2
核心配置
mybatis-config.xml
配置数据源(数据库连接)、事务管理器、以及映射文件路径等。
3
创建实体类
例如 User.java
创建与数据库表结构对应的 Java 类(POJO)。
4
创建Mapper接口
例如 UserMapper.java
定义数据操作的方法(如 selectUserById)。
5
编写SQL映射
例如 UserMapper.xml
在 XML 文件或注解中具体实现 SQL 语句,这一步是为了打开操作数据库的窗口。
6
使用SqlSession
测试代码
获取 SqlSession,得到 Mapper 接口实例,调用方法完成数据库操作。
引入依赖和配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.31</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.19</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.22</version > </dependency >
Mybatis配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://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/willmo_cms" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="Mapper/UserMapper.xml" /> </mappers > </configuration >
创建用户类 1 2 3 4 5 6 7 8 9 10 package org.example.servlet;import lombok.Data;@Data public class User { public String name; public int age; public int id; }
创建Mapper接口 1 2 3 4 5 6 7 8 9 10 11 12 package Mybatis_demo;import org.example.servlet.User;import java.util.*;public interface UserMapper { List<User> list () ; User GetById (int id) ; void insert (User user) ; }
创建SQL映射文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="Mybatis_demo.UserMapper" > <insert id ="insert" > insert into test_table1(id,Name,age) values(#{id},#{name},#{age}) </insert > <select id ="list" resultType ="org.example.servlet.User" > select id,Name,age from test_table1 </select > <select id ="GetById" resultType ="org.example.servlet.User" > select id,Name,age from test_table1 where id = #{id} </select > </mapper >
使用sqlsession
这是在主方法直接使用Mybatis的部分,我们需要将sqlseesion实例化才能使用Mybatis对应的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package Mybatis_demo;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.example.servlet.User;import java.io.IOException;import java.io.InputStream;import java.util.List;public class mybatisDemo { public static void main (String[] args) { InputStream inputStream; { try { inputStream = Resources.getResourceAsStream("mybatis-config.xml" ); } catch (IOException e) { throw new RuntimeException (e); } } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> list = userMapper.list(); System.out.println("总和用户数量为" +list.size()); User user1 = new User () ; user1.setAge(90 ); user1.setId(10 ); user1.setName("插入测试" ); userMapper.insert(user1); sqlSession.commit(); for (int i = 1 ;i<= list.size()+1 ;i++) { User user = userMapper.GetById(i); System.out.println(user); } sqlSession.close(); } }
Mybatis的核心配置 可以上滑查看Mybatis配置,这就是我们连接数据库的配置,它解释了连接哪个数据库,操作的账号密码,操作模式等等。为了后续的开发更轻松,我们有必要学习一些配置的技巧
配置是有顺序的 ,请保证顺序正确,否则会报错
类型别名 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
例如方法实现
1 < select id= "list" resultType= "org.example.servlet.User">
其中的 org.example.servlet.User是一个全限定类名,写起来可能有些繁琐,如果我们限定类名
<typeAliases> <typeAlias alias="User" type="org.example.servlet.User"/> </typeAliases>
就能够直接使用 User来确认返回值。
尊重xml语法,定义别名需要包含在typeAliases标签里。
SQL标签
resultType
期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。
resultMap
对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。
这两个指定返回值类型只能使用一个,他们都能够将数据库返回类型转换成java数据类型,但是resultMap更加灵活,可以指定字段的映射规则。
java方法传入参数名和数据库字段相同时,就能够自动映射完成sql语句的执行。但是有时候,java方法传入参数的字段,和数据库里的字段对不上,那就会造成错误,而resultmap能够给我们创建一个映射来解决这个问题。
1 2 3 4 <select id ="Getuser" resultType ="org.example.servlet.User" > select id,Name,age from test_table1 ; </select > </mapper >
但是你的用户类定义是
1 2 3 4 5 6 7 8 9 10 package org.example.servlet;import lombok.Data;@Data public class User { public String User_name; public int age; public int id; }
这里的User_name和数据库字段Name对不上,我们就可以创建映射来使二者关联起来
1 2 3 <resultMap id = "userMap" type = "org.example.Servlet.User" > <result column = "Name" property = "User_name" > </result > </resultMap >
由此,我们的数据库字段和java中的User类就可以遵循各自的命名规范。
动态 SQL 动态 SQL 可以在 XML 层根据方法传入的参数动态拼装 SQL,避免手写大量不同情况的 SQL 字符串。常用标签:<if>、<where>、<trim>、<foreach>。
在模糊查找的时候可用。
1. <if> — 条件片段 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <select id ="searchUsers" parameterType ="map" resultType ="org.example.domain.User" > SELECT id, Name, age FROM test_table1 <where > <if test ="name != null and name != ''" > AND Name = #{name} </if > <if test ="minAge != null" > AND age >= #{minAge} </if > <if test ="maxAge != null" > AND age <= #{maxAge} </if > </where > </select >
<if> 根据参数决定是否插入 SQL 片段。
结合 <where> 自动处理开头的 AND/OR(见下)。
2. <where> — 自动处理前导逻辑运算符 <where> 会在包含的 SQL 片段前自动加 WHERE,并去除多余的前导 AND/OR。 (上例演示 <where> 的常见用法)
3. <trim> — 更灵活的前后缀裁剪 1 2 3 4 5 6 7 8 <update id ="updateUser" parameterType ="org.example.domain.User" > UPDATE test_table1 <set > <if test ="name != null" > Name = #{name}, </if > <if test ="age != null" > age = #{age}, </if > </set > WHERE id = #{id}</update >
或使用 <trim>:
1 2 3 4 <trim prefix ="SET" suffixOverrides ="," > <if test ="name != null" > Name = #{name}, </if > <if test ="age != null" > age = #{age}, </if > </trim >
<set> 是 <trim prefix="SET" suffixOverrides=",""> 的语法糖,适用于 UPDATE 的字段拼接。
4. <foreach> — 列表(IN)与批量插入
1 2 3 4 5 6 7 <select id ="getByIds" parameterType ="list" resultType ="org.example.domain.User" > SELECT id, Name, age FROM test_table1 WHERE id IN <foreach item ="id" collection ="list" open ="(" separator ="," close =")" > #{id} </foreach > </select >
1 2 3 4 5 6 7 <insert id ="batchInsert" parameterType ="list" > INSERT INTO test_table1 (Name, age) VALUES <foreach collection ="list" item ="user" separator ="," > (#{user.name}, #{user.age}) </foreach > </insert >
使用批量插入时,注意数据库与驱动的批量性能,必要时启用 JDBC 批处理或分批提交以避免内存过大。
性能 / 安全 1. 使用 #{} 避免 SQL 注入(不要用 ${})
#{}:使用预编译参数,自动进行类型处理与转义,它会将用户输入的数据以字符串的形式而不是sql命令输入控制台,能有效防止 SQL 注入。
${}:直接字符串替换(危险),仅在必须动态拼接 SQL 片段(如表名、列名)且确保来源受控时使用。
总结:对用户输入的值一律用 #{};只有在拼接 SQL 语法(表名、排序字段等)且已校验白名单时再考虑 ${}。
2. 批量插入与性能
对大量数据的插入,使用 <foreach> 批量插入比逐条插入更高效;也可以结合 JDBC 批处理(ExecutorType.BATCH)或分批次提交(例如每 500 条 commit 一次)。
注意:一次性插入过多记录可能导致单条 SQL 较大或内存问题,建议分批。
3. 索引与 SQL 优化(建议)
为常用的 WHERE/ORDER BY 字段建立索引;对慢查询使用 EXPLAIN 分析。
避免 SELECT *(按需列出),减少传输与解析开销。