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

Spring(7)——MyBatis入门(1)

一、MyBatis入门

1.1 什么是MyBatis

在这里插入图片描述

MyBatis是一款优秀的持久层框架,用于简化JDBC的开发。

1.2 如何操作MyBatis

  1. 在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

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

# 数据库连接配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?
characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
  1. Mapper接口

    @Mapper
    public interface UserMapper {
    
        @Select("select id, name, age, gender, phone from user")
    public List<User> list();
    }
    

Mybatis的持久层接⼝规范⼀般都叫xxxMapper
@Mapper注解:表示是MyBatis中的Mapper接⼝
程序运⾏时,框架会⾃动⽣成接⼝的实现类对象(代理对象),并给交Spring的IOC容器管理。
@Select注解:代表的就是select查询,也就是注解对应⽅法的具体实现内容。

1.3 数据库连接池

在没有数据库连接池时:没有使用数据库连接池:
客户端执行SQL语句:要先创建一个新的连接对象,然后执行SQL语句,SQL语句执行后又需要关闭连接对象从而释放资源,每次执行SQL时都需要创建连接、销毁链接,这种频繁的重复创建销毁的过程是比较耗费计算机的性能。

数据库连接池是个容器,负责分配、管理数据库连接(Connection)
程序在启动时,会在数据库连接池(容器)中,创建一定数量的Connection对象。

在这里插入图片描述

允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。

  • 客户端在执行SQL时,先从连接池中获取一个Connection对象,然后在执行SQL语句,SQL语句执行完之后,释放Connection时就会把Connection对象归还给连接池(Connection对象可以复用)。

释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏

  • 客户端获取到Connection对象了,但是Connection对象并没有去访问数据库(处于空闲),数据库连接池发现Connection对象的空闲时间 > 连接池中预设的最大空闲时间,此时数据库连接池就会自动释放掉这个连接对象 。

1.4 日志输入

在Mybatis当中我们可以借助日志,查看到sql语句的执行、执行传递的参数以及执行结果。具体操作
如下:

  1. 打开application.properties文件
  2. 开启mybatis的日志,并指定输出到控制台
#指定mybatis输出日志的位置, 输出控制台
mybatis.configuration.logimpl=org.apache.ibatis.logging.stdout.StdOutImpl

开启日志之后,我们再次运行单元测试,可以看到在控制台中,输出了以下的SQL语句信息:

在这里插入图片描述

1.4.5 #{} 和${} 的区别

  1. #{}:预编译占位符
  • 作用#{} 会将参数值作为预编译参数传递给数据库,类似于 JDBC 中的 PreparedStatement
  • 特点
    • 安全性高:能够有效防止 SQL 注入。
    • 自动类型转换:MyBatis 会根据参数类型自动处理数据类型(如字符串添加引号)。
    • 预编译:SQL 语句会被预编译,参数值以安全的方式插入。

示例

<select id="getById" resultType="Emp">
    SELECT * FROM emp WHERE id = #{id}
</select>

生成的 SQL:

SELECT * FROM emp WHERE id = ?

参数值会通过 PreparedStatement 安全地传递给数据库。

  1. ${}:字符串替换占位符
  • 作用${} 会直接将参数值替换到 SQL 语句中,类似于字符串拼接。
  • 特点
    • 灵活性高:可以用于动态拼接 SQL 片段(如表名、列名)。
    • 安全性低:直接拼接字符串,容易导致 SQL 注入。
    • 无自动类型转换:参数值会直接替换到 SQL 中,字符串需要手动添加引号。

示例

<select id="getByColumn" resultType="Emp">
    SELECT * FROM emp WHERE ${column} = #{value}
</select>

生成的 SQL:

SELECT * FROM emp WHERE name = 'John'

如果 ${column} 是用户输入的,可能会导致 SQL 注入。


  1. #{}${} 的对比
特性#{}${}
参数处理方式预编译参数(PreparedStatement直接字符串替换
安全性高,防止 SQL 注入低,容易导致 SQL 注入
自动类型转换是,自动处理数据类型否,需要手动处理
适用场景参数值传递(如 WHERE id = #{id}动态 SQL 片段(如表名、列名)

1.5 CRUD

1.5.1 删除

@Mapper
public interface EmpMapper {

    @Delete("delete from emp where id = #{id}")
    public void delete(Integer id);
}

测试:

@SpringBootTest
class QuickMybatisApplicationTests {

    @Autowired
    private EmpMapper empMapper;

    @Test
    public void testDelete(){
        empMapper.delete(17);
    }

}

1.5.2 插入

@Mapper
public interface EmpMapper {
    

    @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
            "values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
    public void insert(Emp emp);
}

测试:

@SpringBootTest
class QuickMybatisApplicationTests {

    @Autowired
    private EmpMapper empMapper;
    
    @Test
    public void testInsert(){
//创建员工对象
        Emp emp = new Emp();
        emp .setUsername("tom");
        emp.setName("汤姆");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);
//调用添加方法
        empMapper.insert(emp);
    }

}

1.5.3 主键返回

概念:在数据添加成功后,需要获取插入数据库数据的主键。

//会自动将生成的主键值,赋值给emp对象的id属性
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
        "values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert2(Emp emp);

默认情况下,执行插入操作时,是不会主键值返回的。如果我们想要拿到主键值,需要在Mapper接口中的方法上添加一个Options注解,并在注解中指定属性useGeneratedKeys=true和keyProperty=“实体类属性名”。

1.5.4 更新

@Mapper
public interface EmpMapper {
    

    @Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, " +
            "job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
            public void update(Emp emp);

}

测试:

@Test
    public void testUpdate(){
//要修改的员工信息
        Emp emp = new Emp();
        emp.setId(23);
        emp.setUsername("songdaxia");
        emp.setPassword(null);
        emp.setName("老宋");
        emp.setImage("2.jpg");
        emp.setGender((short)1);
        emp.setJob((short)2);
        emp.setEntrydate(LocalDate.of(2012,1,1));
        emp.setCreateTime(null);
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(2);
        emp.setId(1);
//调用方法,修改员工数据
        empMapper.update(emp);
    }

1.5.5 查询

@Select("select id, username, password, name, gender, image, job, " +
        "entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);

测试:

@Test
public void get(){
    Emp emp = empMapper.getById(2);
    System.out.println(emp);
}

我们看到查询返回的结果中大部分字段是有值的,但是deptId,createTime,updateTime这几个字段是没有值的,而数据库中是有对应的字段值的,这是为什么呢?

在这里插入图片描述

原因如下:
实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。

解决方案:

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

起别名:在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样 。

@Select("select id, username, password, name, gender, image, job, entrydate, " +
        "dept_id AS deptId, create_time AS createTime, update_time AS updateTime  " +
        "from emp where id=#{id}")
public Emp getById2(Integer id);

手动结果映射:通过 @Results及@Result 进行手动结果映射

@Results({
        @Result(column = "dept_id", property = "deptId"),
        @Result(column = "create_time", property = "createTime"),
        @Result(column = "update_time", property = "updateTime")
})
@Select("select id, username, password, name, gender, image, job, " +
        "entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById3(Integer id);

开启驼峰命名(推荐):如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射 。

# 在application.properties中添加:
mybatis.configuration.map-underscore-to-camel-case=true  

要使用驼峰命名前提是 实体类的属性 与 数据库表中的字段名严格遵守驼峰命名。

条件查询

对于sql包含模糊查询和范围查询的情况:

select id, username, password, name, gender, image, job, entrydate,
dept_id, create_time, update_time
from emp
where name like '%张%'
and gender = 1
and entrydate between '2010-01-01' and '2020-01-01 '
order by update_time desc;

方式一:

@Select("select * from emp " +
        "where name like '%${name}%' " +
        "and gender = #{gender} " +
        "and entrydate between #{begin} and #{end} " +
        "order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin,
                      LocalDate end);

以上方式注意事项:

  1. 方法中的形参名和SQL语句中的参数占位符名保持一致
  2. 模糊查询使用${…}进行字符串拼接,这种方式呢,由于是字符串拼接,并不是预编译的形式,所以效率不高、且存在sql注入风险。

方式二:

使用MySQL提供的字符串拼接函数:concat(‘%’ , ‘关键字’ , ‘%’)

@Select("select * from emp " +
        "where name like concat('%',#{name},'%') " +
        "and gender = #{gender} " +
        "and entrydate between #{begin} and #{end} " +
        "order by update_time desc")
public List<Emp> list2(String name, Short gender, LocalDate
        begin, LocalDate end);

执行结果:生成的SQL都是预编译的SQL语句 。

相关文章:

  • 7、vue3做了什么
  • Java 大视界 -- Java 大数据在智能家居设备联动与场景自动化中的应用(140)
  • 关系数据库设计理论
  • Android Fresco 框架兼容模块源码深度剖析(六)
  • 在鸿蒙Next中开发一个月历组件
  • AcWing 3533:查找第K小数 ← sort+unique
  • Linux并发程序设计(5):线程的相关操作
  • 高频SQL 50 题(持续更新)
  • Deepseek X 文心智能体:谐音梗广告创意大师
  • vue3 函数式弹窗
  • 文件管理系统
  • Spring Boot 配置属性 (Configuration Properties) 详解:优雅地管理应用配置
  • 创建多模块教程
  • ARMv8.x-M架构计算能力概览
  • react路由5和6新增及区别
  • 【论文阅读】FairCLIP - 医疗视觉语言学习中的公平性提升
  • 基于香橙派 KunpengPro学习CANN(2)——Ascend Extension for PyTorch 配置与安装
  • 深度学习框架PyTorch——从入门到精通(5)自动微分
  • Web3游戏行业报告
  • XML转义符详解:如何在XML中正确处理特殊字符
  • 倒计时1天:走进“中国荔乡”茂名,探寻农交文旅商融合发展新模式
  • 波兰总统选举投票开始,将是对亲欧路线的一次严峻考验
  • 俄需要达成怎样的特别军事行动结果?普京:包含四个方面
  • 美国新泽西客运公司遭遇罢工:40年来首次,35万人受影响
  • 日本一季度实际GDP环比下降0.2%
  • 上海市税务局:收到对刘某某存在涉税问题的举报,正依法依规办理