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

MyBatis操作数据库——入门

MyBatis操作数据库——入门


文章目录

  • MyBatis操作数据库——入门
  • 什么是MyBatis?
  • MyBatis入门
    • 准备工作
    • 配置数据库连接字符串
    • 打印日志
    • 单元测试
  • 持久层代码
    • 查询
    • 增加
    • 删除
    • 修改
  • MyBatis XML配置文件
    • 配置数据库连接字符串和MyBatis
  • 持久层代码
    • 添加mapper接口
    • 添加UserInfoMapper.xml
    • 增加
    • 删除
    • 更新
    • 查询
  • 其他查询操作
    • 多表查询
    • #{} 和 ${}的区别
    • 排序功能
    • like查询
  • 数据库连接
    • 介绍
    • 使用
      • 1. Hikari
      • 2. Druid


什么是MyBatis?

  • MyBatis是一款优秀的持久层框架,用于简化JDBC的开发
  • MyBatis本是 Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github

在上面我们提到一个词:持久层

  • 持久层:指的就是持久化操作的层,通常指数据访问层(dao),是用来操作数据库的
    在这里插入图片描述

  • 简单的来说,MyBatis是更简单用于与数据库交互的框架,也就是说使用更简单的操作对数据库进行读取和操作

MyBatis入门

Mybatis操作数据库的步骤:

  1. 准备工作(创建springboot工程、数据库表准备、实体类)
  2. 引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)
  3. 编写SQL语句(注解/XML)
  4. 测试

准备工作

  1. 创建SpringBoot项目,并导入MyBatis的依赖和MySQL驱动包
  2. 项目创建完成之后,自动在pom.xml文件中,导入了MyBatis的依赖和MySQL的驱动

在这里插入图片描述

配置数据库连接字符串

Mybatis中要连接数据库,需要数据库相关参数配置

  • MySQL驱动类
  • 登录名
  • 密码
  • 数据库连接字符串

如果是application.yml文件,配置内容如下:

# 数据库连接配置
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver

注意事项:
如果使用 MySQL 是5.x之前的使用的是"com.mysql.jdbc.Driver",如果是大于5.x使用的是"com.mysql.cj.jdbc.Driver"

如果是application.properties文件,配置内容如下:

#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=root

打印日志

在Mybatis当中我们可以借助日志,查看到sql语句的执行、执行传递的参数以及执行结果,在配置文件中进行配置即可

mybatis:configuration: # 配置打印 MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

如果是application.properties,配置内容如下:

#指定mybatis输出日志的位置,输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

注意:后续配置项,默认只提供一种,请自行进行配置项转换。

单元测试

在创建出来的SpringBoot项目中,idea已经帮我们创建好测试类了,我们直接点击添加即可
在这里插入图片描述
在这里插入图片描述

持久层代码

查询

MyBatis语句:

@Select("select username, password, age, gender, phone from user_info where id = 4")public List<UserInfo> queryAllUser();

弊端:上述情况只能固定查询id等于4的情况,假如需要查询其他id的情况,那么id应该为一个动态的数值

解决:我们可以使用#{}的方式获取参数

@Select("select username, password, age, gender, phone from user_info where id = #{id}")public UserInfo queryAllUser(int id);

注意⚠️:

  • 我们在上面查询时发现,有几个字段是没有赋值的,只有 Java 对象属性和数据库字段一模一样时,才会进行赋值

原因分析:

当自动映射查询结果时,MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略大小写)。这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性

解决办法:

  1. 起别名
  2. 结果映射
  3. 开启驼峰命名
  • 起别名
@Select("select create_time as createTime from user_info")LocalDateTime getCreateTime(UserInfo userInfo);
  • 结果映射
@Select("select create_time createTime from user_info")@Results(id = "userInfoResultMap", value = {@Result(property = "createTime", column = "create_time")})default List<UserInfo> selectUserInfo() {return null;}

假如后续还想使用这个映射关系的话,可以用Result注解定义一个名称

@Select("select create_time as createTime from user_info")@ResultMap("userInfoResultMap")List<UserInfo> selectUserInfoWithResultMap();
  • 驼峰命名(推荐)
    通常数据库列使用蛇形命名法进行命名(下划线分割各个单词),而 Java 属性一般遵循驼峰命名法约定。
    为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase 设置为 true。
mybatis:configuration:map-underscore-to-camel-case: true #配置驼峰自动转换

驼峰命名规则: abc_xyz => abcXyz

  • 表中字段名: abc_xyz
  • 类中属性名: abcXyz

增加

MyBatis语句:

@Insert("insert into user_info (username, password, age, gender, phone) values (#{username}, #{password}, #{age}, #{gender}, #{phone})")void insertUser(UserInfo userInfo);
  • 常量已经被替换成动态参数了
  1. 起别名:
  • 在 MyBatis 中,@Param注解是用来为方法参数起别名的
import org.apache.ibatis.annotations.Param;
import java.util.List;public interface UserMapper {// 根据用户id查询用户信息,这里使用@Param注解为参数起别名User selectUserById(@Param("id") Long userId); 
}
  1. 返回主键
  • useGeneratedKeys:这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
  • keyProperty:指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)

说人话:

  • useGeneratedKeys = true:启用 “获取数据库自增主键” 的功能
  • keyProperty = “id”:指定将获取到的主键值赋给实体类的 id 属性
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("insert into user_info (username, age, gender, phone) values (#{userInfo.username},#{userInfo.age},#{userInfo.gender},#{userInfo.phone})")
Integer insert(@Param("userInfo") UserInfo userInfo);

删除

MyBatis语句:

@Delete("delete from user_info where id = #{id}")void deleteUser(@Param("id") Integer id);

修改

MyBatis语句:

@Update("update user_info set username = #{username} where id = #{id}")void updateUser(UserInfo userInfo);

MyBatis XML配置文件

MyBatis开发有两种方式:

  1. 注解
  2. XML

上面我们学习了注解的方式,接下来我们学习XML方式

使用XML方式需要以下两步:

  1. 配置数据库连接字符串和MyBatis
  2. 写持久层代码

配置数据库连接字符串和MyBatis

如果是application.yml文件,配置内容如下:

# 数据库连接配置
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
# 配置 mybatis xml 的文件路径,在 resources/mapper 创建所有表的 xml 文件
mybatis:mapper-locations: classpath:mapper/**Mapper.xml

如果是application.properties文件,配置内容如下:

#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=root
# 配置 mybatis xml 的文件路径,在 resources/mapper 创建所有表的 xml 文件
mybatis.mapper-locations=classpath:mapper/**Mapper.xml

持久层代码

  1. 方法定义 Interface
  2. 方法实现 XXX.xml

添加mapper接口

@Mapper
public interface UserInfoMapper {UserInfo queryAllUser(String username);
}

添加UserInfoMapper.xml

固定的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.example.demo.mapper.UserInfoMapper"></mapper>

增加

用于向数据库插入一条记录,核心标签为 <insert>

<!-- id:与 Mapper 接口中的方法名一致 -->
<insert id="insertUser">INSERT INTO user (username, age, email, create_time)VALUES (#{username}, #{age}, #{email}, #{createTime})
</insert>

说明

  • #{属性名}:MyBatis 的参数占位符,对应实体类 User 的属性(如 #{username} 对应 user.getUsername())。
  • 若需返回自增主键,需添加 useGeneratedKeyskeyProperty 属性:
    <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"><!-- SQL 语句同上 -->
    </insert>
    
    插入后,自增主键会自动赋值给 User 对象的 id 属性

删除

用于删除数据库中的一条或多条记录,核心标签为 <delete>

<delete id="deleteUserById">DELETE FROM userWHERE id = #{id}
</delete>

说明

  • #{id}:接收传入的主键 ID 参数,通过 WHERE 条件定位要删除的记录。
  • 可根据需求添加更复杂的条件(如批量删除):
    <delete id="deleteUsersByIds">DELETE FROM userWHERE id IN (#{ids}) <!-- ids 为逗号分隔的 ID 字符串,如 "1,2,3" -->
    </delete>
    

更新

用于修改数据库中的记录,核心标签为 <update>

<update id="updateUser">UPDATE userSET username = #{username},age = #{age},email = #{email},update_time = #{updateTime}WHERE id = #{id}
</update>

说明

  • SET 后跟随要更新的字段,字段值通过 #{属性名} 从参数(通常是 User 对象)中获取。
  • WHERE 条件通常使用主键(如 id),确保只更新目标记录,避免批量更新错误。
  • 可按需更新部分字段(无需更新的字段不写在 SET 中)。

查询

用于从数据库查询数据,核心标签为 <select>,需指定返回结果类型。

(1)查询单个对象

<!-- resultType:指定查询结果的返回类型(实体类全路径) -->
<select id="selectUserById" resultType="com.example.entity.User">SELECT id, username, age, email, create_time, update_timeFROM userWHERE id = #{id}
</select>

(2)查询多个对象(返回列表)

<!-- 返回列表时,resultType 仍指定单个实体类型,MyBatis 会自动封装为 List -->
<select id="selectAllUsers" resultType="com.example.entity.User">SELECT id, username, age, email, create_time, update_timeFROM user
</select>

(3)条件查询(模糊查询)

<select id="selectUsersByUsername" resultType="com.example.entity.User">SELECT id, username, age, email, create_time, update_timeFROM userWHERE username LIKE CONCAT('%', #{username}, '%')
</select>

解决办法和注解类似:

  1. 起别名
  2. 结果映射
  3. 开启驼峰命名

其中1、3的解决办法和注解一样,不再多说,接下来看下xml如果来写结果映射

Mapper.xml

<resultMap id="BaseMap" type="com.example.demo.model.UserInfo"><id column="id" property="id"></id><result column="delete_flag" property="deleteFlag"></result><result column="create_time" property="createTime"></result><result column="update_time" property="updateTime"></result>
</resultMap><select id="queryAllUser" resultMap="BaseMap">select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from user_info
</select>

说明

  • resultType:必须指定,用于 MyBatis 将查询结果映射为对应的 Java 对象(单个对象或集合中的元素)
  • 模糊查询:使用 LIKE 关键字,通过 CONCAT('%', #{username}, '%') 拼接通配符(避免 SQL 注入风险)

其他查询操作

多表查询

import com.example.demo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;@Mapper
public interface ArticleInfoMapper {@Select("SELECT ta.id,ta.title,ta.content,ta.uid,tb.username,tb.age,tb.gender " +"FROM articleinfo ta LEFT JOIN user_info tb ON ta.uid = tb.id " +"WHERE ta.id = #{id}")ArticleInfo queryUserByUid(Integer id);
}

#{} 和 ${}的区别

从上面两个例子可以看出:

  1. #{} 使用的是预编译 SQL,通过 ? 占位的方式,提前对 SQL 进行编译,然后把参数填中. #{} 会根据参数类型,自动拼接引号 ‘’ .(自动添加)
  2. ${} 会直接进行字符替换,一起对 SQL 进行编译。如果参数为字符串,需要加上引号 ‘’(手动添加)
  • 参数为数字类型时,也可以加上,查询结果不变,但是可能会导致索引失效,性能下降
  • #{}${}的区别在于:#{}采用预编译SQL的方式,能防止SQL注入,更安全,会把参数用占位符?替代后提前编译SQL;${}是即时SQL,直接进行字符替换后再编译SQL,存在SQL注入风险,且可能因参数格式等问题影响性能或索引使用

排序功能

-从上面的例子中,可以得出结论:${}会有SQL注入的风险,所以我们尽量使用#{}完成查询
-既然如此,是不是${}就没有存在的必要性了呢?当然不是.

接下来我们看下${}的使用场景:

  • Mapper实现
@Select("select id, username, age, gender, phone, delete_flag, create_time, update_time " +"from user_info order by id ${sort} ")
List<UserInfo> queryAllUserBySort(String sort);
  • 使用 ${sort} 可以实现排序查询,而使用 #{sort} 就不能实现排序查询了。

  • 注意:此处 sort 参数为 String 类型,但是 SQL 语句中,排序规则是不需要加引号 '' 的,所以此时的 ${sort} 也不加引号

  • 可以发现,当使用 #{sort} 查询时,asc前后自动给加了引号,导致 sql 错误
    #{} 会根据参数类型判断是否拼接引号 ''
    如果参数类型为String,就会加上引号.

  • 除此之外,还有表名作为参数时,也只能使用 ${}

like查询

在 MyBatis 中使用 LIKE 进行模糊查询时,#{}${} 的使用方式及区别如下:

  1. 使用 #{} 实现 LIKE 查询(推荐)
    #{} 是预编译方式,会自动处理参数,避免 SQL 注入,是更安全的方式。
    需要通过字符串拼接通配符(%),有两种实现方式:

方式1:在 Java 代码中拼接通配符

// 调用时在参数中加入 %
String username = "张";
List<User> users = userMapper.selectByUsername("%" + username + "%");
<!-- Mapper XML -->
<select id="selectByUsername" resultType="User">SELECT * FROM user WHERE username LIKE #{username}
</select>
  1. 在 SQL 中使用 CONCAT() 拼接
<!-- Mapper XML 中直接拼接 % -->
<select id="selectByUsername" resultType="User">SELECT * FROM user WHERE username LIKE CONCAT('%', #{username}, '%')
</select>
  1. 使用 ${} 实现 LIKE 查询(不推荐,有注入风险)
    ${} 是直接字符串替换,会原样插入参数,可能导致 SQL 注入,仅在确认参数安全时使用。
<select id="selectByUsername" resultType="User">SELECT * FROM user WHERE username LIKE '%${username}%'
</select>

风险示例
username 参数为 ' OR '1'='1,替换后 SQL 会变成:
SELECT * FROM user WHERE username LIKE '%' OR '1'='1%',导致查询所有数据,引发安全问题

数据库连接

上面MyBatis的讲解中,我们使用了数据库连接池的技术,避免频繁创建,销毁连接

介绍

数据库连接池分配负责,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是需要再建立一个

在这里插入图片描述

  • 没有使用数据库连接池的情况:每次执行SQL语句,要先创建一个新的连接对象,然后执行SQL语句,SQL语句执行完,再关闭连接对象释放资源。这种重复的创建连接,销毁连接比较消耗资源
  • 使用数据库连接池的情况:程序启动时,会在数据库连接池中创建一定数量的Connection对象,当客户请求数据库连接池,会从数据库连接池中获取Connection对象,然后执行SQL,SQL语句执行完,再把Connection归还给连接池

优点:

  1. 减少网络开销
  2. 资源重用
  3. 提升系统性能

使用

常见的数据库连接池:

  • C3P0
  • DBCP
  • Druid
  • Hikari

目前比较流行的是 Hikari、Druid

1. Hikari

SpringBoot默认使用的数据库连接池

2023-08-18 18:59:51.834  INFO 54668 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2023-08-18 18:59:51.974  INFO 54668 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
[UserInfo(id=null, username=admin, age=18, gender=1, phone=18612340801, status=null, createTime=null, updateTime=null), UserInfo(id=null, username=zhangsan, age=18, gender=1, phone=18612340802, status=null, createTime=null, updateTime=null), UserInfo(id=null, username=lisi, age=18, gender=1, phone=18612340803, status=null, createTime=null, updateTime=null), UserInfo(id=null, username=wangwu, age=18, gender=1, phone=18612340804, status=null, createTime=null, updateTime=null)]

Hikari 是日语"光"的意思(ひかり), Hikari也是以追求性能极致为目标

2. Druid

如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要引入相关依赖即可

<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.21</version>
</dependency>

如果SpringBoot版本为2.X, 使用druid-spring-boot-starter 依赖

<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.17</version>
</dependency>

运行结果:

2023-08-19 11:37:15.733  INFO 64692 --- [           main] c.a.d.s.b.a.DruidDataSourceAutoConfigure : Init DruidDataSource
2023-08-19 11:37:16.029  INFO 64692 --- [           main] com.alibaba.druid.pool.DruidDataSource   : dataSource-1 inited
2023-08-19 11:37:16.361  INFO 64692 --- [           main] d.SpringbootMybatisDemoApplicationTests : Started SpringbootMybatisDemoApplicationTests in 2.381 seconds (JVM running for 3.359)
[UserInfo(id=null, username=admin, age=18, gender=1, phone=18612340801, status=null, createTime=null, updateTime=null), UserInfo(id=null, username=zhangsan, age=18, gender=1, phone=18612340802, status=null, createTime=null, updateTime=null), UserInfo(id=null, username=lisi, age=18, gender=1, phone=18612340803, status=null, createTime=null, updateTime=null), UserInfo(id=null, username=wangwu, age=18, gender=1, phone=18612340804, status=null, createTime=null, updateTime=null)]
2023-08-19 11:37:16.741  INFO 64692 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource   : dataSource-1 closing ...
2023-08-19 11:37:16.760  INFO 64692 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource   : dataSource-1 closed

参考官方地址: https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

  • Druid连接池是阿里巴巴开源的数据库连接池项目
  • 功能强大,性能优秀,是Java语言最好的数据库连接池之一

文章转载自:

http://HuBBeBxC.spxsm.cn
http://7sHyRI4G.spxsm.cn
http://1HTiPTW9.spxsm.cn
http://bbJ070w9.spxsm.cn
http://rE4ro87o.spxsm.cn
http://yd05XY4A.spxsm.cn
http://XYDaV8nd.spxsm.cn
http://SbMwouMT.spxsm.cn
http://Y11vFLS0.spxsm.cn
http://f9CvI7km.spxsm.cn
http://Ecb2qCmH.spxsm.cn
http://oiyQko2a.spxsm.cn
http://KixanWHd.spxsm.cn
http://UMwDe5RZ.spxsm.cn
http://IYFvg8bR.spxsm.cn
http://6qBrEKCP.spxsm.cn
http://qWnmNhWV.spxsm.cn
http://mnewOgM7.spxsm.cn
http://VvApdvuZ.spxsm.cn
http://9X9ILN2J.spxsm.cn
http://8zxQltA0.spxsm.cn
http://nyIu0XkI.spxsm.cn
http://bCltE6DQ.spxsm.cn
http://RxtOFdDk.spxsm.cn
http://tWHgAoYq.spxsm.cn
http://Q8gsoHA8.spxsm.cn
http://yvWYLDgm.spxsm.cn
http://SwePpmzm.spxsm.cn
http://zN3VG8YN.spxsm.cn
http://isGxyxeL.spxsm.cn
http://www.dtcms.com/a/375602.html

相关文章:

  • AI编程:[实践]PDTAC通过叠加多种设计模式,实现高可扩展的第三方系统对接
  • 操作【GM3568JHF】FPGA+ARM异构开发板 使用指南:蓝牙
  • 小目标检测:FFCA-YOLO详解
  • Gemini 2.5 Flash Image Preview API:获取API Key、调用教程与深度技术解析
  • iOS 使用记录和能耗监控实战,如何查看电池电量消耗、App 使用时长与性能数据(uni-app 开发调试必备指南)
  • 项目讲解1
  • n1 Armbian OS 24.11.0 noble 安装suricata
  • 【算法--链表】114.二叉树展开为链表--通俗讲解
  • IntelliJ IDEA 2025.1 Java Stream Debugger 快速使用指南
  • IDEA2024.1使用Debug调试工具F8步过失效解决方法
  • Java 大视界 -- Java 大数据在智能交通智能公交系统优化与乘客出行服务提升中的应用(409)
  • Java数据结构——树
  • vue3和vue2生命周期的区别
  • 《棒球小白》棒球球落地了才能跑垒吗·棒球1号位
  • 排序算法(Java)
  • Oracle数据库
  • 腾讯开源智能体框架Youtu-agent全解析:特性、架构与实战指南
  • 【2511系统分析师备考-快速阅读一】
  • Vue 学习随笔系列二十五 -- 多文件上传并支持修改
  • 从0到1学习Vue框架Day03
  • 【Redis五种数据类型】
  • Redis 双向同步如何避免循环?【附实操演示】
  • Redis单线程模型为什么快?
  • At least one <template> or <script> is required in a single file component
  • 不止是DELETE:MySQL多表关联删除的JOIN语法实战详解
  • 动态控制rabbitmq中的消费者监听的启动和停止
  • C# 基于halcon的视觉工作流-章30-圆圆距离测量
  • Android Studio 构建项目时 Gradle 下载失败的解决方案
  • 【STM32项目开源】STM32单片机智能恒温箱控制系统
  • 苹果ios的系统app应用WebClip免签应用开源及方式原理