JavaWeb——后端之Mybatis

四、Mybatis

概念: Mybatis是一款持久层(Dao层)框架,用于简化JDBC(Sun操作数据库的规范,较繁琐)的开发

历史: Apache的一个开源项目iBatis,2010年由apache迁移到了google code,并改名MyBatis。2013年11月迁移到Github

1. 入门程序

1)创建Spring module;创建的时候勾选MyBatis Framework和MySql service(对应数据库的类型)

2)准备数据以及数据库环境

3)定义一个实体类,实体类的变量要与表中的数据类型以及名称对应,实体类变脸阿哥使用包装类,命名使用驼峰命名

4)创建Mybatis的环境,在模块的application.properties中声明

java 复制代码
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://124.221.237.48(地址):3306/test(数据库名)
#连接数据库的用户名
spring.datasource.username=xy
#连接数据库的密码
spring.datasource.password=123456

5)定义mapper,就是使用Sql语句的类,要使用Mapper进行注解,这样运行时,会自动生成该接口的实现类对象(代理对象),并将该对象交给IOC容器管理。

在类中定义抽象方法,如果是查询就使用@Select()注解,括号中指定sql查询语句

注:要想有sql语法提示

选中Sql语句右键Show Context Actions------>inject language------>MySql(要想提示表名,要将数据库连接到IDEA------使用IDEA连接数据库)

6)在测试启动类中编写测试方法,因为要使用mapper接口中的方法,所以使用Autowired,从IOC中获取bean对象

2. 数据库池连接

使用配置文件进行配置之后,SpringBoot底层就会自动使用数据库连接池技术管理和分配连接

概念:

  • 数据库连接池是个容器,负责分配、管理数据库连接
  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重建一个
  • 释放空闲时间超过最大空闲事件的连接,来避免因为没有释放连接而一起的数据库连接遗漏

优势:

  • 资源重用
  • 提升系统响应速度
  • 避免数据库连接遗漏

产品:

Druid

引入依赖(版本要对应调整)

xml 复制代码
# Spring2
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.2.8</version>
</dependency>

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

配置数据库连接池类型(可以不)

Hikari(springboot默认)

3. lombok工具包

原有问题: 数据库中的数据要对应一个实体类,并为其生成构造器,getter/setter,toString等方法

lombok: 一个实用的java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发,提高效率

准备工作: 添加依赖

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

注: Lombok会在编译时,自动生成对应的java代码。我们使用lombok时,还需要安装一个lombok的插件(idea自带)

4. Mybatis基础操作

1)删除

EmpMapper.java

java 复制代码
@Mapper
public interface EmpMapper {
    // 根据ID删除数据
    @Delete("delete from emp where id= #{id}")
    public void delete(Integer id);
}
// #{}是占位符,生成的就是预编译的SQL语句

测试方法

java 复制代码
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
    @Autowired
    private EmpMapper empMapper;
    @Test
    public void testDelete() {
        empMapper.delete(17);
    }
}

想要查看执行的日志信息可以配置==>预编译SQL

xml 复制代码
# 配置mybatis日志,指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

参数占位符

2)新增

接口方法

java 复制代码
// 插入数据
@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);  // 参数太多,使用实体类进行封装

测试方法

java 复制代码
@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);
    }

主键返回

插入数据成功后,想要获取这个插入数据的主键

java 复制代码
@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 insert(Emp emp);

3)更新

根据主键id查询回显

然后修改对应数据

@Update(更新的SQL语句)

4)查询

java 复制代码
// 根据ID查询数据
@Select("select  * from emp where id = #{id}")
public Emp getById(Integer id);
java 复制代码
@Test
public void testGetById() {
    Emp emp = empMapper.getById(1);
    System.out.println(emp);
}

数据封装

  • 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装
  • 如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装(数据库属性命名是下划线分隔,实体类变量命名是驼峰)

解决数据封装问题

方案一:给数据库字段起别名

方案二:通过@Results,@Result注解手动映射封装

java 复制代码
// 通过@Results和@Result注解进行封装
@Results({
        @Result(column = "dept_id", property = "deptId"),
        @Result(column = "create_time", property = "createTime"),
        @Result(column = "update_time", property = "updateTime")
})
@Select("select  * from emp where id = #{id}")
public Emp getById(Integer id);

方案三:开启Mybatis的驼峰命名自动映射开关(前提:数据库字段名字和Java中的属性名命名都是严格按照规范的)

java 复制代码
# 开启mybatis的驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true

条件查询

java 复制代码
// 条件查询
//    @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);
// 为了防止SQL注入
@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> list(String name, Short gender, LocalDate begin, LocalDate end);
java 复制代码
@Test
public void testSelect() {
List<Emp> empList = empMapper.list("张", (short)1, LocalDate.of(2010, 1, 1), LocalDate.of(2020, 1, 1));
System.out.println(empList);
}

5. XML映射文件(配置SQL语句)

条件查询的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.itheima.mapper.EmpMapper">
    <!--第一个参数是方法名,第二个参数是查询返回的单条语句的全类名-->
    <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp where name like concat('%', #{name}, '%') and gender=#{gender} and entrydate between #{begin} and #{end} order by update_time desc
    </select>
</mapper>

MybatisX是一款基于IDEA的快速开发Mybatis的插件,为效率而生

使用注解来映射简单的语句会使代码更加简洁,但是稍微复杂一点,就混乱不堪。------>如果做一些复杂的操作,最好使用XML来映射语句

6. 动态SQL

概念: 随着用户的输入或者外部条件的变化而变化的SQL语句

6.1 <if>

xml 复制代码
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--第一个参数是方法名,第二个参数是查询返回的单条语句的全类名-->
    <select id="list" resultType="com.itheima.pojo.Emp">
        select *
        from emp
        where
        <if test="name != null">
            name like concat('%', #{name}, '%')
        </if>
        <if test="gender != null">
            and gender = #{gender}
        </if>
        <if test="begin != null and end != null">
            and entrydate between #{begin} and #{end}
        </if>
        order by update_time desc
    </select>

</mapper>
java 复制代码
@Test
public void testSelect() {
    // List<Emp> empList = empMapper.list("张", (short)1, LocalDate.of(2010, 1, 1), LocalDate.of(2020, 1, 1));
    List<Emp> empList = empMapper.list("张", null, null, null);
    System.out.println(empList);
}

问题: 如果第一个为空,wher就会紧跟着and,不合规的SQL

解决: 使用<where></where> 代替where

  • 动态生成where关键字
  • 自动去除条件前的and和or
xml 复制代码
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--第一个参数是方法名,第二个参数是查询返回的单条语句的全类名-->
    <select id="list" resultType="com.itheima.pojo.Emp">
        select *
        from emp
        <where>
        <if test="name != null">
            name like concat('%', #{name}, '%')
        </if>
        <if test="gender != null">
            and gender = #{gender}
        </if>
        <if test="begin != null and end != null">
            and entrydate between #{begin} and #{end}
        </if>
        </where>
        order by update_time desc
    </select>

</mapper>

<set></set>

  • 去掉字段之后多余的逗号

6.2 <foreach>

xml 复制代码
<!--批量删除-->
<!--
collection:遍历的集合
item:遍历的元素
separator:分隔符
open:遍历开始前拼接的SQL片段
close:遍历结束后拼接的SQL片段
-->
<delete id="deleteByIds">
    delete from emp where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>
java 复制代码
// 批量删除
public void deleteByIds(List<Integer> ids);
java 复制代码
@Test
public void testDeletByIds() {
    List<Integer> ids = Arrays.asList(13, 14, 15);
    empMapper.deleteByIds(ids);
}

6.3 <sql><include>

重复SQL片段------》代码复用性差

相关推荐
小灰灰要减肥1 小时前
装饰者模式
java
张铁铁是个小胖子1 小时前
MyBatis学习
java·学习·mybatis
Yan.love2 小时前
开发场景中Java 集合的最佳选择
java·数据结构·链表
椰椰椰耶2 小时前
【文档搜索引擎】搜索模块的完整实现
java·搜索引擎
大G哥2 小时前
java提高正则处理效率
java·开发语言
智慧老师2 小时前
Spring基础分析13-Spring Security框架
java·后端·spring
lxyzcm2 小时前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
V+zmm101343 小时前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
Oneforlove_twoforjob3 小时前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
xmh-sxh-13143 小时前
常用的缓存技术都有哪些
java