# MyBatis 基础了解
MyBatis最初是Apache基金会的一个开源项目,名为iBatis。是一款基于Java的持久层框架。
核心优点:
- 支持定制化SQL:MyBatis允许开发者编写自定义的SQL语句,满足复杂的业务需求。
- 存储过程与高级映射:除了支持SQL语句外,MyBatis还支持存储过程以及高级映射功能。
- 消除JDBC代码:MyBatis免除了几乎所有的JDBC代码,以及手动设置参数和获取结果集的工作。
- XML或注解配置:MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO(Plain Ordinary Java Objects,普通的Java对象)为数据库中的记录。
- 动态SQL:MyBatis支持根据不同的条件构造动态SQL语句,提高了代码的复用性。
- 缓存机制:提供一级缓存和二级缓存,减少了对数据库的频繁访问,提高了系统性能。
- 解除SQL与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。
一 入门
1 快速入门
创建Springboot 项目的时候 选择l两个依赖
- MyBatis Framework
- MySQL Driver
创建项目之后要在resources 下面的application.properties 下面配置
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=1234
创建一个User类
public class User {
private Integer id;
private String name;
private Short age;
private Short gender;
private String phone;
}
创建一个接口
package org.example.springbootmybatisquickstart.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.example.springbootmybatisquickstart.pojo.User;
import java.util.List;
@Mapper//在程序运行的时候框架会自动生成该接口的实现类对象 并且将对象交给IOC容器管理
public interface UserMapper {
//查询全部用户信息
@Select("select * from user")
public List<User> listUser();
}
然后再单元测试中运行
package org.example.springbootmybatisquickstart;
import org.example.springbootmybatisquickstart.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.example.springbootmybatisquickstart.pojo.User;
import java.util.List;
@SpringBootTest
class SpringbootMybatisQuickStartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testListUser () {
List<User> userList = userMapper.listUser();
for (User user : userList) {
System.out.println(user);
}
}
}
运行程序然后就会查询出来所有结果
User{id=1, name='白眉鹰王', age=55, gender=1, phone='18800000000'}
User{id=2, name='金毛狮王', age=45, gender=1, phone='18800000001'}
User{id=3, name='青翼蝠王', age=38, gender=1, phone='18800000002'}
User{id=4, name='紫衫龙王', age=42, gender=2, phone='18800000003'}
User{id=5, name='光明左使', age=37, gender=1, phone='18800000004'}
User{id=6, name='光明右使', age=48, gender=1, phone='18800000005'}
2 配置相关提示
右键选中SQL 语言 ,然后选择 显示上下午操作
3 JDBC概念
1 >定义**:JDBC是Java语言用来规范客户端程序如何访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
2 >**功能:
* 连接数据库:通过JDBC,Java程序可以连接到各种关系型数据库。
* 执行SQL语句:Java程序可以使用JDBC执行SQL查询、更新、删除等操作。
* 处理结果集:JDBC提供了处理SQL查询结果集的方法,使开发者可以方便地获取和处理数据。
4 数据库连接池
1> 定义
数据库连接池是一个连接的集合,它维护了一组数据库连接以供应用程序使用,而不是每次都创建新的连接。这些连接在需要时被提供给应用程序,使用完后被返回到池中以供后续使用。
2> 原理
数据库连接池在内部维护一定数量的数据库连接,并对外提供获取和返回连接的方法。当应用程序需要访问数据库时,它会从连接池中获取一个已建立的连接,而不是创建一个新的连接。当应用程序完成数据库操作后,它会将连接返回给连接池,以便其他应用程序或同一应用程序的后续操作可以重用该连接。
3> 优势
建立和断开数据库连接是耗时的操作。通过连接池,可以避免频繁创建和关闭连接,从而减少开销,提升系统性能。
-
资源管理 :
数据库连接是宝贵的资源。连接池能有效管理和复用这些连接,避免资源浪费,使应用程序更高效运行。
-
并发处理:
在高并发场景下,多个请求共享连接能减少数据库连接数量,提高并发处理能力,使应用程序更具扩展性。
-
连接可靠性:
网络问题或服务器故障可能导致数据库连接中断。但有了连接池,一旦检测到失效连接,它会立即重新创建一个可用的连接,确保应用程序始终可靠运行。
4> 实现
SpringBoot 是默认使用的hikari连接池
内部实现了这个方法
public Connection getConnection() throws SQLException
德鲁伊(Druid)连接池是阿里巴巴开源的一个高性能数据库连接池项目,广泛应用于各种Java应用程序中,特别适用于高并发、高性能、稳定可靠的数据库连接管理场景。以下是对德鲁伊连接池的详细介绍:
如果要切换德鲁伊连接池,那么先把其依赖引入进来
5 lombok
Lombok是一个Java库,它通过注解的方式自动为Java类生成诸如getter、setter、equals、hashCode、toString等方法的代码,从而减少了样板代码的编写,使得Java代码更加简洁、易读和可维护。
Lombok提供了一系列注解,这些注解可以在Java类中使用,以自动生成常用的方法。以下是一些常用的Lombok注解及其功能:
- 1 @Getter:生成类的getter方法。如果注解在字段上,则只为该字段生成getter方法。
- 2 @Setter:生成类的setter方法。如果注解在字段上,则只为该字段生成setter方法。
- 3 @ToString:生成toString方法。
- 4 @EqualsAndHashCode:生成equals和hashCode方法。
- 5 @Data:这是一个方便的注解,它集成了@Getter、@Setter、@ToString、@EqualsAndHashCode和@NoArgsConstructor注解的功能,为类生成这些方法。
- 6 @NoArgsConstructor:生成无参构造函数。
- 7 @AllArgsConstructor:生成包含所有参数的构造函数。
- 8 @RequiredArgsConstructor:生成包含标记为final的字段的构造函数,以及带有@NonNull注解的字段。
- 9 @Builder:生成建造者模式的构造函数,用于构建复杂对象。
二 Mybatis 操作
1 删除
//根据id删除员工数据
@Delete("delete from tb_emp where id = #{id}")
// 返回值int是影响的行数
int deleteEmpById(Integer id);
可以配置mybatis 日志输出到控制台
# 配置mybatis的日志 指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
控制台就会显示预编译SQL 语句
预编译SQL 性能更高 并且 更加安全
JDBC Connection [HikariProxyConnection@1971344738 wrapping com.mysql.cj.jdbc.ConnectionImpl@1d806de6] will not be managed by Spring
==> Preparing: delete from tb_emp where id = ?
==> Parameters: 15(Integer)
<== Updates: 0
SQL 注入 是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器攻击的方法
2 新增
// 增加员工数据 这里下划线使用驼峰代替
@Insert("insert into tb_emp(username, name, gender, image, job, dept_id, create_time, update_time) values (#{username},#{name},#{gender},#{image},#{job},#{deptId},#{createTime},#{updateTime});")
int insertEmp(Emp emp);
主键返回 :
在新增数据成功之后,需要获取插入数据库的数据的主键。
// 主键返回,会自动将生成主键值,赋值给emp.id属性返回
@Options(keyProperty = "id",useGeneratedKeys = true)
3 更新数据
// 更新数据
@Update("update tb_emp set username = #{username}, name=#{name} ,gender = #{gender} ,image =#{image},job=#{job} where id = #{id};")
public void updateEmp(Emp emp);
4 查询数据
// 查询数据
@Select("select * from tb_emp where id = #{id};")
Emp selectEmpById(Integer id);
数据封装
如果实体类属性名 和 数据库表查询返回的字段名一直,mybatis 会自动封装,否则不能自动封装
如若存在不一致的情况,如下解决方案
// 起个别名
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptId, create_time createTime, update_time updateTime from tb_emp where id = #{id};")
Emp selectEmpById(Integer id);
第二种方案 注解
// 通过Result 注解手动映射封装
@Results({
@Result(column = "dept_id", property = "deptId"),
@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime"),
})
@Select("select * from tb_emp where id = #{id};")
Emp selectEmpById(Integer id);
第三种方案 开启mybatis 的驼峰命名自动映射开关
# 配置mybatis的自动映射
mybatis.configuration.map-underscore-to-camel-case=true
查询多个条件的数据
// 查询多个条件的数据 这个地方是$符号,不是#符号,因为#符号是mybatis的占位符,$符号是字符串的占位符
@Select("select * from tb_emp where name like '%${name}%' and gender = #{gender} order by create_time desc;")
List<Emp> selectSearchEmp(String name,Short gender);
但是为了避免sql 注入 ,推荐 使用下面的方式concat 拼接函数
// select * from tb_emp where name like concat('%', '张', '%') and gender = 1 order by create_time desc;
@Select("select * from tb_emp where name like concat('%', #{name}, '%') and gender = #{gender} order by create_time desc;")
List<Emp> selectSearchEmp(String name,Short gender);
三 XML 映射文件
映射文件的名字必须与接口名称一致,同包同名
XML 配置文件可以查询官网 http://mybatis.p2hp.com/configuration.html
<?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="org.example.springbootmybatisquickstart.EmpMapper">
<select id="selectSearchEmp" resultType="org.example.springbootmybatisquickstart.pojo.Emp">
select * from tb_emp where name like concat('%', #{name}, '%') and gender = #{gender} order by create_time desc
</select>
</mapper>
可以在插件市场 安装MyBatisX 插件 ,
四 动态SQL
动态SQL指的是在运行时根据条件构建SQL语句,而不是使用静态的SQL语句。它可以根据不同的条件生成不同的SQL语句,使得查询、更新或删除数据时能够根据具体情况进行灵活的处理。
1 作用
- 1 >条件灵活:使用动态SQL可以根据不同的条件生成不同的SQL语句,满足各种查询、更新或删除需求。
- 2> 查询优化:有时候在编写静态SQL语句时难以预料到查询条件的变化,而使用动态SQL可以根据运行时的条件动态调整查询语句,从而更好地适应实际情况,提高查询性能。
- 3> 动态表名和字段名:有时候需要根据不同的场景来操作不同的表或字段,这时候就可以利用动态SQL来动态构建表名和字段名,实现灵活性和扩展性。
- 4> 防止SQL注入:通过使用参数化查询或者绑定变量的方式来构建动态SQL,可以有效防止SQL注入攻击,提升系统的安全性。
2 常用标签
MyBatis通过一系列的动态SQL标签来实现动态SQL的功能,这些标签包括:
- 1> :根据条件动态拼接SQL。该标签用于根据条件判断是否包含某段SQL片段。
- 2> :用于处理集合,生成IN查询或者批量操作语句。
- 3> sql 是定义可重用的SQL片段,include 是通过属性refid 指定包含sql片段
- 4> :用于自动添加WHERE关键字,并去除多余的AND或OR。如果标签中的if条件都不满足,则标签没有任何功能;若条件满足,则标签会自动添加WHERE关键字,并将条件前面多余的AND或OR去掉。
- 5> :用于动态更新语句中的SET部分,可以自动添加逗号并去除多余的逗号。
<mapper namespace="org.example.springbootmybatisquickstart.mapper.EmpMapper">
<select id="selectSearchEmp" resultType="org.example.springbootmybatisquickstart.pojo.Emp">
select * from tb_emp
<where>
<if test="name!= null and name!= ''">
name like concat('%', #{name}, '%')
</if>
<if test="gender!= null">
gender = #{gender}
</if>
order by create_time desc
</where>
</select>
</mapper>
<!-- 定义查询所有员工信息的操作 -->
<update id="update2">
update tb_emp set
<set>
<if test="username!= null">
username = #{username},
</if>
<if test="name!= null">
name = #{name},
</if>
<if test="gender!= null">
gender = #{gender},
</if>
<if test="image!= null">
image = #{image},
</if>
<if test="job!= null">
job = #{job}
</if>
</set>
where id = #{id}
</update>
for each
<!-- 批量删除员工的操作-->
<!--
collection=要遍历的集合
item=遍历出来的元素
separator = 分隔符
open = 遍历开始前拼接的SQL片段
close = 遍历结束后拼接的SQL片段 -->
<delete id="deleteEmpByIds">
delete from tb_emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<sql id="commonSelectEmp">
selcte id,username,name,gender,image,job,create_time from tb_emp
</sql>
<select id="selectSearchEmp" resultType="org.example.springbootmybatisquickstart.pojo.Emp">
<include refid="commonSelectEmp"/>
<where>
<if test="name!= null and name!= ''">
name like concat('%', #{name}, '%')
</if>
<if test="gender!= null">
gender = #{gender}
</if>
order by create_time desc
</where>
</select>