• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
tyrantblue
博客园    首页    新随笔    联系   管理    订阅  订阅
Java学习笔记 (十七) Mybatis

Mybatis

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

MyBatis本是Apache的一个开源项目iBatis, 2010年这个项目由apache迁移到了google code, 并且改名为MyBatis, 2013年11月迁移到Github

官网: https://mybatis.org/mybatis-3/zh/index.html

1. Mybatis入门

1.1 快速入门

要求: 使用Mybatis查询表内所有数据

步骤:

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

根据黑马程序员的这个视频p117

记录一下自己的问题: 运行时报错: ava.sql.SQLException: Access denied for user '11529'@'localhost' (using password: YES), 然后修改了对应封装的实体类的类型, 依然报错, 然后看到了一个问题, 在Application.properties中spring.datasource.url没有加上数据库名, 修改后依然报错, 最后才发现原来是spring.datasource.username=root写成了spring.datasource.name=root, 少了一个user, 服了呀

最后将入门程序运行起来了

1.2 配置SQL提示

默认在mybatis中编写SQL语句是不识别的, 可以做如下配置

选择sql语句, 右键选择Show Context Actions, 选中Inject Language or reference, 然后选择MySQL

然后会出现表报红, 因为IDEA没有和数据库建立连接, 不识别表信息

解决方式: 在IDEA中配置MySQL数据库连接(要连接相应的数据库, 要不然就需要选择数据库再选择表)

1.3 JDBC

Java DataBase Connectivity , 就是使用Java操作关系型数据库的一套API

本质:

  1. sun公司官方定义的一套操作所有关系型数据库的规范, 即接口
  2. 各个数据库厂商去实现这套接口, 提供数据库驱动jar包
  3. 我们可以使用这套接口(JDBC)编程, 真正的执行代码是驱动jar包中的实现类

1.4 数据库连接池

数据库连接池是个容器, 负责分配管理数据库连接

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

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

优势:

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

标准接口: DataSource

  • 官方(sun)提供的数据库连接池接口, 由第三方组织实现此接口
  • 功能: 获取连接 Connection getConnection() throws SQLException;

常见产品: C3P0 DBCP Druid Hikari

Druid(德鲁伊)

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

切换Druid数据库连接池

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

步骤:

  1. 导入起步依赖
  2. 设置application.properties中的配置

1.5 lombok

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

注解 作用
@Getter/@Setter 为所有的属性提供get/set方法
@ToString 会给类自动生成易阅读的toString方法
@EqualsAndHashCode 根据类所拥有的非静态字段自动重写equals方法和hashCode方法
@Data 提供了更综合的代码生成功能(@Getter + @Setter + @ToString + @EqualsAndHashCode)
@AllArgsConstructor 为实体类生成除了static修饰的字段之外带有各个参数的构造器方法
@NoArgsConstructor 为实体类生成无参的构造器方法

注意:

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

2. Mybatis基础操作

2.1 环境准备

和之前差不多, 创建springboot模块, 然后添加依赖, 然后配置数据库连接, 中间出了一点小问题, 就是数据库中有下划线的字段封装的时候不能转为驼峰命名的属性, 需要在applictaion.properties中加入以下代码:

#下划线转驼峰
mybatis.configuration.map-underscore-to-camel-case=true

这样就能正常封装了

2.2 删

SQL语句

delete from emp where id = 20;

接口方法:

    @Delete("delete from emp where id = #{id}")//#{id}传递参数
//预编译为 delete from emp where id = ?
    public void delete(Integer id);

注意: 如果mapper接口方法形参只有一个普通类型的参数, #{...}里面的属性名可以随便写, 如#{id}, #{value}

日志输出:

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

预编译

性能更高

防止SQL注入

SQL注入是通过操作输入来修改事先定义好的SQL语句, 以达到执行代码对服务器进行攻击的方法

参数占位符

{...}:

  • 执行SQL时, 会将#{...}替换为?, 生成预编译SQL, 会自动设置参数值
  • 使用时机: 参数传递, 都使用#{...}

${...}:

  • 拼接SQL, 直接将参数拼接在SQL语句中, 存在SQL注入问题
  • 使用时机: 如果对表名, 列表进行动态设置时使用

2.3 增

接口方法

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

主键返回

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

如: 添加套餐数据时, 还需要维护套餐菜品关系表数据

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

2.4 改

根据主键修改数据

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

2.5 查

2.5.1 根据ID查询

@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);

数据封装(解释了我在上面的问题)

  • 实体属性名和数据库表查询返回的字段名一致, mybatis会自动封装(大小写不同是可以封装的)
  • 如果实体类属性名和数据库表查询返回的字段名不一致, 不能自动封装

解决方案1: 给字段起别名

解决方案2: 通过@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);

解决方案3: 开启mybatis的驼峰命名的自动映射开关

mybatis.configuration.map-underscore-to-camel-case=true

2.5.2 根据条件查询

//条件查询//#{...}不能放在双引号内
@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> backList(String name, Short gender, LocalDate begin ,LocalDate end );

使用concat()函数解决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> backList(String name, Short gender, LocalDate begin ,LocalDate end );

我的版本多参数会报错, 需要加上@Param注解

    //条件查询
@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> backList(@Param("name") String name,@Param("gender") Short gender,@Param("begin") LocalDate begin ,@Param("end") LocalDate end );
}

2.6 XML配置文件

规范:

  1. XML映射文件的名称与Mapper接口名称一致, 并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
  2. XML映射文件的namespace属性为Mapper接口全限定名一致
  3. XML映射文件中sql语句的id与Mapper接口中的方法一致, 并保持返回类型一致

查询示例:

<?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.tyrant.mapper.EmpMapper">
    <select id="backList" resultType="com.tyrant.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>

resultType是返回单个的类型, 原Mapper类中方法的@Param注解要保留

安装插件mybatisx, 方便使用

2.7 动态SQL

随着用户的输入或外部条件的变化而变化的SQL语句, 我们称为动态SQL

2.7.1 < if >, < where >

< if >: 用于判断条件是否成立, 使用test属性进行条件判断, 如果条件为true, 则拼接SQL

< where >: where元素只会在子元素有内容的情况下才插入where子句, 而且会自动去除子句的开头的AND 或者 OR

<mapper namespace="com.tyrant.mapper.EmpMapper">

    <select id="backList" resultType="com.tyrant.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
        </where>

    </select>
</mapper>

2.7.2 < set >

< set >: 动态地在行首插入SET关键字, 并会删掉额外的逗号(用在update语句中)

    <update id="update2">
        <set>
            update emp set
            <if test="username != null">username = #{userName},</if>
            <if test="name != null">name = #{name},</if>
            <if test="gender != null">gender = #{gender},</if>
            <if test="job != null">job = #{job},</if>
            <if test="entrydate != null">entrydate = #{entryDate},</if>
            <if test="dept_id != null">dept_id = #{deptId},</if>
            <if test="update_time != null">update_time = #{updateTime}</if>
            where id = #{id}
        </set>
    </update>

2.7.3 < foreach >

    <!--动态删除员工
        collection : 遍历的集合
        item : 遍历出来的元素
        separator : 用什么分隔符
        open : 开始前拼接的SQL片段
        close: 结束后拼接的SQL片段-->
    <delete id="deleteByIds">
        delete where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

2.7.4 < sql > < include >

< sql >: 定义可重用的SQL片段

< include >: 通过属性refid, 指定包含的sql片段

    <!--抽取-->
    <sql id="commentSelect">
        select id, username, name, gender, job, entrydate, password, dept_id, create_time, update_time
        from emp
    </sql>

   <!--查询员工信息-->
    <select id="backList" resultType="com.tyrant.pojo.Emp">
        <include refid="commentSelect"/>
        <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
        </where>
    </select>

3. 案例

3.1 开发规范

Restful

REST(Representational State Transfer), 表述性状态转换, 它是一种软件架构风格

注意: REST是风格, 是约定方式, 约定不是规定, 可以打破

描述模块的功能通常使用复数, 也就是加s的格式来描述, 表示此类资源, 而非单个资源, 如: users, emps, books ...

统一响应结果

posted on 2023-04-15 22:26  雪化凛然  阅读(93)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3