mybatis笔记

什么是myBatis

mybatis是一个优秀的持久层框架,用于简化JDBC(JDBC白学)

JDBC的缺点

1.硬编码

  • 注册驱动和获取链接
  • sql语句

2.操作繁琐

  • 需要手动封装结果集ResultSet
  • preparedstatement手动设置参数

mybatis免除看几乎所有的JDBC代码以及设置参数和获取结果集的工作

myBatis快速入门

  1. 创建项目

  2. 新建maven模块

  3. 在pom.xml中配置mybatis的依赖

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>x.x.x</version>
    </dependency>

    x.x.x 为mybatis的版本号

  4. 因为项目业务需要,同时也要导入mysql的jar包

    1
    2
    3
    4
    5
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
    </dependency>
  5. 配置其他所需要的依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
    <scope>test</scope>
    </dependency>

    <!-- 添加slf4j日志api -->
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.20</version>
    </dependency>
    <!-- 添加logback-classic依赖 -->
    <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    </dependency>
    <!-- 添加logback-core依赖 -->
    <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
    </dependency>
  6. 编写mybatis核心配置文件–>替换连接信息,解决硬编码

    mybatis-config.xml文件配置的通用案例(其中部分已经替换)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "https://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    <environments default="development">
    <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
    <!--数据库连接信息-->
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
    <property name="username" value="root"/>
    <property name="password" value="1234"/>
    </dataSource>
    </environment>
    </environments>
    <mappers>
    <!--加载sql的映射文件-->
    <mapper resource="UserMapper.xml"/>
    <!--sql的映射文件的取名规则为xxMapper.xml-->
    </mappers>
    </configuration>
  7. 创建sql的映射文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?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="test">
    <select id="selectAll" resultType="com.xgfm.pojo.User">
    select * from tb_user;
    </select>
    </mapper>
  8. 创建对应的pojo文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    package com.xgfm.pojo;

    public class User {
    private Integer id;
    private String username;
    private String password;
    private String gender;
    private String addr;

    public Integer getId() {
    return id;
    }

    public void setId(Integer id) {
    this.id = id;
    }

    public String getUsername() {
    return username;
    }

    public void setUsername(String username) {
    this.username = username;
    }

    public String getPassword() {
    return password;
    }

    public void setPassword(String password) {
    this.password = password;
    }

    public String getGender() {
    return gender;
    }

    public void setGender(String gender) {
    this.gender = gender;
    }

    public String getAddr() {
    return addr;
    }

    public void setAddr(String addr) {
    this.addr = addr;
    }

    @Override
    public String toString() {
    return "Tb_user{" +
    "id=" + id +
    ", username='" + username + '\'' +
    ", password='" + password + '\'' +
    ", gender='" + gender + '\'' +
    ", addr='" + addr + '\'' +
    '}';
    }
    }

  9. 创建mian方法来执行mybatis

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package com.xgfm;

    import com.xgfm.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;

    public class MybatisDemo {
    public static void main(String[] args) throws IOException {
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //获取sqlSession对象
    SqlSession sqlSession=sqlSessionFactory.openSession();

    //执行sql语句
    List<User> users = sqlSession.selectList("test.selectAll");
    System.out.println(users);
    //释放资源
    sqlSession.close();
    }
    }

Mapper代理开发

在上述代码中

1
2
//执行sql语句
List<User> users=sqlSession.selectList("test.selectAll");

依旧存在硬编码的问题

为了解决这个问题,便使用mapper进行代理开发

使用Mapper代理开发的步骤

  1. 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下

  2. 设置SQL映射文件的namespace属性为Mapper接口全限定名

  3. 在Mapper接口中定义方法,方法名就是SQL映射文件sql语句中的id,并保持参数类型和返回值类型一致

  4. 进行编码

    • 通过SqlSession的getMapper方法获取Mapper接口的代理对象

      1
      UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    • 调用代理对象中的对应方法完成sql的执行

      1
      List<User> users=userMapper.selectAll();

完成!!

附MybatisDemo2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.xgfm;

import com.xgfm.mapper.UserMapper;
import com.xgfm.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MybatisDemo2 {
public static void main(String[] args) throws IOException {
//加载mybatis核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//获取sqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();

//执行sql语句
// List<User> users = sqlSession.selectList("com.xgfm.mapper.selectAll");
//3.1 获取UserMapper接口的代理对象
//代理对象的
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users=userMapper.selectAll();

System.out.println(users);
//释放资源
sqlSession.close();
}
}

UserMapper接口

1
2
3
4
5
6
7
8
9
10
package com.xgfm.mapper;

import com.xgfm.pojo.User;

import java.util.List;

public interface UserMapper {
List<User> selectAll();
}

UserMapper.xml文件

1
2
3
4
5
<mapper namespace="com.xgfm.mapper.UserMapper">
<select id="selectAll" resultType="com.xgfm.pojo.User">
select * from tb_user;
</select>
</mapper>

在mybatis-config.xml文件中标签中有时候有很多很多mapper需要加载,可以使用package进行扫描

1
2
3
4
<!--加载sql的映射文件--><!--sql的映射文件的取名规则为xxMapper.xml-->
<mapper resource="com/xgfm/mapper/UserMapper.xml"/>
<!--使用package进行Mapper的代理开发-->
<package name="com.xgfm.mapper"/>

可以对比两种加载映射文件的方法

  • mapper标签是一个一个xml进行加载,而package是一整个包进行扫描读取然后进行加载

MyBatis的核心配置文件

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息

  • environments(环境配置)

    • 在其中可以配置多个数据库,动态的切换数据源
  • 配置数据库连接环境信息,可以配置多个environment,通过default属性切换不同的environment

    • transactionManager是事务管理标签,type一般是JDBC,基本上不需要修改
    • dataSource数据库连接池,一般是POOLED连接池使用
    • dataSource中间配置的是property,是数据源配置的基本参数
  • typeAliases(类型别名配置)

    • 可以为java类型设置一个缩写的名字,仅仅用于XML配置,意在降低冗余的全限定类名书写

    • 例如

      1
      2
      3
      <typeAliases>
      <package name="com.xgfm.pojo"/>
      </typeAliases>

      在mybatis-config.xml文件中配置后,在各个mapper文件中的com.xgfm.pojo.xxx都可以用xxx代替,并且这个xxx是不区分大小写的

      例如

      1
      2
      3
      4
      5
      6
      7
      8
      9
      <select id="selectAll" resultType="User">
      select * from tb_user;
      </select>


      <!--修改前的xml是这样的-->
      <select id="selectAll" resultType="com.xgfm.pojo.User">
      select * from tb_user;
      </select>

mybatis-config.xml文件的配置是有约束的

其中标签的顺序一定要按照这样的顺序

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)

配置文档的顺序必须严格按照这个顺序否则将会报错

增删改查练习(练学)

  • 准备环境

    1. 数据库表tb_brand

    2. 实体类Brand

    3. 测试用例

    4. 安装MyBatisX插件

      myBatisX是为了效率而生的

查询

  • 练习-查询所有数据

    1. 编写接口方法
    2. 结果:List
    3. 编写SQL语句
    4. 执行方法,测试
  • 查询所有数据时候会发现输出以下数据

    1
    Brand{id=1, brandName='null', companyName='null', ordered=5, description='好吃不上火', status=0}

    会发现companyName,brandName输出的是null

    取别名

    数据库表的字段名称和实体类属性名称不一致,不能自动封装,这时候就要在mapper.xml文件改写sql语句,给查询的字段取别名

    • 缺点:很不方便
    1
    2
    3
    4
    <select id="selectAll" resultType="com.xgfm.pojo.Brand">
    select id, brand_name as brandName , company_name as companyName,ordered,description,status
    from tb_brand;
    </select>

    然后在查询中就可以找到这些数据了

    但是如果以后要用很多查询的时候每次都要起别名是很麻烦的

    sql片段

    可以在外面定义Sql片段

    1
    2
    3
    4
    5
    6
    7
    8
    <sql id="brand_column">
    id, brand_name as brandName , company_name as companyName,ordered,description,status
    </sql>

    <select id="selectAll" resultType="brand">
    select <include refid="brand_column"/>
    from tb_brand;
    </select>

    但是这样写,也不灵活

    使用resultMap

    1. resultMap定义resultMap
    2. 在select标签使用resultMap属性替换resultType属性(resultType的原来的type在resultMap中的type字段好像是一致的)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <resultMap id="brandResultMap" type="brand">
    <!--
    id:完成主键字段的映射
    column:表的列名
    property:实体类的属性名
    result:完成一般字段的映射
    column:表的列名
    property:实体类的属性名
    -->
    <result column="brand_name" property="brandName"/>
    <result column="company_name" property="companyName"/>
    </resultMap>

    <select id="selectAll" resultMap="brandResultMap">
    select *
    from tb_brand;
    </select>

    这样代替更加灵活,方便更改

  • 练习-查询-查看详情

    1. 编写接口方法
      • 参数:id
      • 结果:Brand
    2. 编写SQL语句
    3. 执行方法,进行测试
  • 参数占位符:

    • #{}

      会将其替换为? 为了防止SQL注入进行使用

    • ${}

      直接拼SQL,会存在SQL注入问题

    所以参数传递的时候都使用#{}

    而${}一般使用在表名或者列名不固定的情况,但也并不是很常用

  • 参数类型设置:parameterType,大多时候可以省略

  • 特殊字符的处理:

    因为sql是写在mapper.xml文件中的,如果在sql语句中使用<等类似的有占用情况的特殊字符,会报错,这时候有以下几种解决方法:

    1. 转义字符

      网上搜索对应的转义字符结果即可

    2. CDATA区

      1
      2
      3
      <![CDATA[

      ]]>

      直接输入特殊字符即可

  • 查询-多条件的查询

    1. 编写接口方法
      • 参数:所有的查询条件
      • 结果:List
    2. 编写SQL语句
    3. 执行方法,进行测试
    • 思考SQL语句写法
    • 参数传输
  • 多个查询条件进行参数传递

    1. 散装参数传递

    2. 对象参数传递

      对象的属性名称要和参数占位符名称一致,否则无法封装

    3. map集合参数传递

      map集合中的键的名称要和参数占位符名称一致,否则无法封装

动态条件查询(动态SQL)

Mybatis对动态SQL有很强大的支撑:

  • if

    多用于多条件的查询

    if:条件判断

    test:逻辑表达式

    if标签中的逻辑表达式的&&要用and来进行代替,非空字符串用!=’’

    逻辑表达式的字符用逻辑表达式中的数据

    • 可能会出现where后直接跟上and,然后出现sql语法错误的问题,这时候可以使用标签,或者在where后加入恒等式让所有条件格式一致
    • 建议使用where标签,更加高效合理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <select id="selectByCondition" resultMap="brandResultMap">
    select * from tb_brand
    <where>
    <if test="status!= null">
    status= #{status}
    </if>
    <if test="companyName != null">
    and company_name like #{companyName}
    </if>
    <if test="brandName!= null">
    and brand_name like #{brandName};
    </if>
    </where>

    </select>
  • choose(when,otherwise)

    从多个条件中选择其一

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <select id="selectByConditionSingle" resultMap="brandResultMap">
    select * from tb_brand
    <where>
    <choose> <!--相当于switch-->
    <when test="status!= null"><!--相当于 case-->
    status =#{status}
    </when>
    <when test="companyName != null and companyName != ''">
    company_name like #{companyName}
    </when>
    <when test="brandName != null and brandName != ''">
    brand_name like #{brandName}
    </when>
    <!-- <otherwise>--><!--相当于default-->
    <!-- 1=1-->
    <!-- </otherwise>-->
    </choose>
    </where>

    </select>
  • trim(where,set)

  • foreach

添加

  1. 编写接口方法:Mapper接口
    • 参数:除了id之外的所有数据,为了避免id主键重复
    • 结果:void(通过是否出现异常确认是否成功)
  2. 编写SQL语句:SQL映射文件

mybatis会自动将autocommit设置为false,导致需要手动提交事务

如果需要自动提交事务,可以在获取sqlSession对象的时候设置参数

1
SqlSession sqlSession=sqlSessionFactory.openSession(true);

添加-主键返回

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

  • 比如:添加订单和订单项

如果没有设置过主键返回

1
2
3
brandMapper.add(brand);
Integer id=brand.getId();
System.out.println(id);

运行这段代码后,id的值是null,因为id是mysql自增生成的,并没有setId放入brand实体类当中

这时候就要设置mapper中的insert代码的 useGeneratedKeys和keyProperty属性

添加 useGeneratedKeys=”true” keyProperty=”id”

1
2
3
4
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand (brand_name , company_name ,ordered,description , status)
values (#{brandName},#{companyName},#{ordered},#{description},#{status});
</insert>

这样之后再运行sout(id);就会成功输出实际的id编号了

修改

修改全部字段

  1. 编写Mapper接口方法

    参数:所有数据

    结果:void

    通过是否出现异常判断是否执行

  2. 编写SQL语句:SQL映射文件

  3. 执行方法,测试

要点与前面一致,根据业务逻辑编写SQL语句,Mapper代理运行SQL然后提交事务

修改动态字段

动态SQL进行修改语句

与动态条件查询类似,可以进行类比

不再赘述

删除

删除一个

  1. 编写Mapper接口方法

    参数:id

    结果:void

  2. 编写SQL语句:SQL映射文件

  3. 执行方法,测试

批量删除数据

因为批量删除需要的时候前端传输过来的一般多个数据,所以这时候获取的参数大概率是id数组

  1. 编写Mapper接口

    参数:id数组

    结果:void

  2. 编写SQL语句:SQL映射文件

  3. 执行方法,测试

批量删除数据和删除单条数据最大的区别在于SQL是动态的,因为批量删除数据时删除数据的数量是不确定的,在where id in (?,?,?) 这样的格式下面,?占位符 的数量是无法确定的,所有要使用动态SQL语句

mybatis会将传入的数组封装成Map集合

  • 默认:array = 数组的key名称

  • 使用@Param注解改变map集合的默认key的名称,比如传入参数的时候使用

    (@Param(“ids”)int[] ids)

例子:

1
2
3
4
5
6
7
8
9
<delete id="deleteByIds">
delete from tb_brand
where
id in (
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
);
</delete>

事务

1
2
3
4
5
6
sqlSession.setAutoCommit(false);
//false表示关闭自动提交,true为自动提交
sqlSession.commit;
//提交事务
sqlSession.rollback();
//关闭事务

MyBatis参数传递

MyBatis接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理

单个参数类型:

  1. POJO类型:直接使用类型,属性名和参数占位符一致

  2. Map集合:直接使用类型,键名和参数占位符一致

  3. Collection:封装为Map集合

    map.put(“arg0”,collection集合);

    map.put(“collection”,collection集合);

  4. List:封装为Map集合

    map.put(“arg0”,list集合);

    map.put(“collection”,list集合);

    map.put(“list”,list集合);

  5. Array:封装为Map集合

    map.put(“arg0”,数组);

    map.put(“array”,数组);

  6. 其他类型:可以直接使用,因为会直接调用这个参数放入到参数占位符的地方

多个参数类型:

封装成Map集合

map.put(“arg0”,参数值1)

map.put(“Param1”,参数值1)

map.put(“arg1”,参数值2)

map.put(“Param2”,参数值2)

如果使用@Param注解,来替换argX的键名

不要用默认的名称,使用@Param注解修改默认的键名,并且使用修改后的名称获取值,这样代码的可阅读性会更加高

注解开发

注解可以简化一些简单的SQL语句,但是复杂的SQL语句依旧是要用xml进行配置,不然会导致SQL语句从复杂变成混乱

可以直接在Mapper接口中这样写

1
2
@Select("select * from tb_user where id = #{id}")
User selectById(int id);

这样可以直接代替在xml文件中写select标签

但是为了防止出现驼峰命名和_命名导致出现null的问题

需要在mybatis-config.xml文件配置以下设置,开启驼峰命名识别

1
2
3
<settings>  
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>

完结

刚刚做综合练习

顺便附上我的servlet和jsp的maven坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>

mybatis笔记
http://example.com/2023/04/20/mybatis笔记/
作者
星光浮梦
发布于
2023年4月20日
许可协议