title: 1-MyBatis基本使用
toc: true
tags:


学习思路


  1. 学会怎么用
  2. 为什么这样用

使用步骤

  1. 创建 “mybatis-config.xml” 配置文件
  2. 创建好 “mapper.xml映射文件”,并在 “mybatis-config.xml”配置文件中配置好 mapper.xml 的路径
  3. 使用 SqlSessionFactoryBuilder创建—->sqlSessionFactory—-> sqlSession
  4. 调用 sqlSession(“mapper.xml中的id,如果有 namespace 则使用 namespace.id。”,”需要传递的参数“) 进行 CRUD

基本使用例子

try {
// 1.创建SqlSessionFactoryBuilder对象
     SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new 			SqlSessionFactoryBuilder();
// 2.创建SqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
// 3.创建SqlSession对象
    SqlSession  sqlSession = sqlSessionFactory.openSession();
// 4.执行SQL
    
    
    int count = sqlSession.insert("insertCar");
    
    
    
    System.out.println("更新了几条记录:" + count);
// 5.提交
    sqlSession.commit();
    
    
} catch (Exception e) {
            // 回滚
if (sqlSession != null) {
sqlSession.rollback();
}
            e.printStackTrace();
} finally {
            // 6.关闭
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}

①、一些基本使用方法

1.切换环境

sqlSessionFactoryBuilder.build(Resources.getResourceAsStream(“mybatis-config.xml”), ==”environmentID”==);

// 使用指定数据库
        SqlSessionFactory sqlSessionFactory1 = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "dev");
        SqlSession sqlSession1 = sqlSessionFactory1.openSession(true);
        int count1 = sqlSession1.insert("insertCar", car);
        System.out.println("插入了几条记录:" + count1);

②、各个环节详细解释

1.mybatis-config.xml 配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--默认使用开发环境-->
    <!--<environments default="dev">-->
    <!--默认使用生产环境-->
    <environments default="production">
        <!-- -->
        <!--开发环境-->
        <environment id="dev">
==========================================
            <!--配置事务管理-->
            <transactionManager type="JDBC"/>
===========================================     
             <!--配置dataSoure数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
        <!--生产环境-->
        <environment id="production">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
==========================================
     <!--配置 mapper.xml文件-->
    <mappers>
        <mapper resource="CarMapper.xml"/>
    </mappers>
</configuration>

注意

  1. default 配置默认的 environment id

  2. 事务管理器

    1. 采用JDBC的原生事务机制:

      • 开启事务:conn.setAutoCommit(false);
      • 处理业务……
      • 提交事务:conn.commit();
    2. MANAGED 交给容器去管理事务 —>一般可以交给 spring 或者 springboot 去管理,当 mybatis 找不到容器支持时:也是没有事务。

    3. 不区分大小写

  3. 可以 使用 properties 外部文件

    1. 导入文件

       <!--引入外部属性资源文件-->
          <properties resource="jdbc.properties">
              <property name="jdbc.username" value="root"/>
              <property name="jdbc.password" value="root"/>
          </properties
      
      1. properties 有两个属性 resource 和 url
        1. resource 从类的根路径开始找
        2. url 则从指定的url加载,假设文件放在d:/jdbc.properties,这个url可以写成:file:///d:/jdbc.properties。注意是三个斜杠哦。
    2. 使用 变量

      ${parametersName}
      <dataSource type="POOLED">
      <!--${key}使用-->
      <property name="driver" value="${jdbc.driver}"/>
      <property name="url" value="${jdbc.url}"/>
      <property name="username" value="${jdbc.username}"/>
      <property name="password" value="${jdbc.password}"/>
                  </dataSource>
      
  4. mappers 也有两个属性 与 properties 相同。

    1. resource 从类的根路径开始找
    2. url 则**从指定的url加载

1.1重要 修改数据源

但凡为 程序提供 Connection 对象的都叫做数据源

<dataSource type="POOLED">
   

type 设置类别三选一 type=”[UNPOOLED|POOLED|JNDI

2.mapper.xml 文件配置 与使用 配置传入参数


使用步骤


传参

类别

按数量划分


一、多参数
方案:一、直接传参

​ 底层原理:

在多个参数的情况下,mybatis 会在底层创建一个 mapper 集合。

将传入的参数 封装为 arg0/param0 为key的集合。

#{xxx}

xxx应该写 arg0 按传入参数的下表开始。

select * from t_student where name = #{arg0} and sex = #{arg1}

是好处也是痛处 —->解决方案 @Param 注解 来写名字

案例分析

需求:通过name和sex查询。

    /**
     * 根据name和sex查询
     * @param name
     * @param sex
     * @return
     */
    List<Student> selectByNameAndSex(String name, Character sex);
@Test
public void testSelectByNameAndSex(){
    List<Student> students = mapper.selectByNameAndSex("张三", '女');
    students.forEach(student -> System.out.println(student));
}
<select id="selectByNameAndSex" resultType="student">
  select * from t_student where name = #{name} and sex = #{sex}
</select>

执行结果:

img

异常信息描述了:name参数找不到,可用的参数包括[arg1, arg0, param1, param2]

修改StudentMapper.xml配置文件:尝试使用[arg1, arg0, param1, param2]去参数

<select id="selectByNameAndSex" resultType="student">
  <!--select * from t_student where name = #{name} and sex = #{sex}-->
  select * from t_student where name = #{arg0} and sex = #{arg1}
</select>

运行结果:

img

再次尝试修改StudentMapper.xml文件

<select id="selectByNameAndSex" resultType="student">
  <!--select * from t_student where name = #{name} and sex = #{sex}-->
  <!--select * from t_student where name = #{arg0} and sex = #{arg1}-->
  <!--select * from t_student where name = #{param1} and sex = #{param2}-->
  select * from t_student where name = #{arg0} and sex = #{param2}
</select>

通过测试可以看到:

实现原理:实际上在mybatis底层会创建一个map集合,以arg0/param1为key,以方法上的参数为value,例如以下代码:

Map<String,Object> map = new HashMap<>();
map.put("arg0", name);
map.put("arg1", sex);
map.put("param1", name);
map.put("param2", sex);

// 所以可以这样取值:#{arg0} #{arg1} #{param1} #{param2}
// 其本质就是#{map集合的key}

注意:使用mybatis****3.4.2之前的版本时:要用#{0}和#{1}这种形式。

@Param注解—–>解决方案一的痛点

可以不用arg0 arg1 param1 param2吗?这个map集合的key我们自定义可以吗?当然可以。使用@Param注解即可。这样可以增强可读性。


实际上在mybatis底层会创建一个map集合,以arg0/param1为key,以方法上的参数为value.


可以通过 @Param 指定 传入参数 在 mybatis 底层创建 的mapper 对应的 keyName。

​ 使用方法

@Param("keyName")

使用案例

List<Student> selectByNameAndAge(@Param(value="name") String name, @Param("age") int age);

注意

使用 @param 直接后,arg0 和 argxxx 会失效,但 param0 和 param1 还可以使用。

注解的原理。

image-20230206235943191

方案:二、使用mapper集合
方案:三、使用 pojo(domain) 类
二、单参数

直接传入参数即可,mybatis 会直接将传入的值添加到 对应的地方。

底层是 将占位符 #{xxx} 直接转换为 ?然后调用 selectOne 方法。即xxx里填什么都没关系。

③、一些技巧

1.使用 sql 自动生成的主键,并将其保存到一个地方。

前提是:主键是自动生成的。

业务背景:一个用户有多个角色。

E9F189EB-F5E2-465f-828C-127DB34968FE.png

插入一条新的记录之后,自动生成了主键,而这个主键需要在其他表中使用时。

插入一个用户数据的同时需要给该用户分配角色:需要将生成的用户的id插入到角色表的user_id字段上。


第一种方式:可以先插入用户数据,再写一条查询语句获取id,然后再插入user_id字段。【比较麻烦】

第二种方式:mybatis提供了一种方式更加便捷。

方法步骤

2.结果映射


1).使用 resultmapper

② 使用驼峰命名自动映射。、

使用这种方式的前提是:属性名遵循Java的命名规范,数据库表的列名遵循SQL的命名规范。

Java命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式。

SQL命名规范:全部小写,单词之间采用下划线分割。

比如以下的对应关系:

实体类中的属性名 数据库表的列名
carNum car_num
carType car_type
produceTime produce_time

3.创建 大 maper

4.模糊查询


两种拼接方法

1.双引号大法  ---> 单引号不行,已经试过了。
"%"#{} "#"
2.concat 拼接大法
concat('#',#{band},'%')

需求:查询奔驰系列的汽车。【只要品牌brand中含有奔驰两个字的都查询出来。】

使用${}

/**
     * 根据品牌进行模糊查询
     * @param likeBrank
     * @return
     */
List<Car> selectLikeByBrand(String likeBrank);
<select id="selectLikeByBrand" resultType="Car">
  select
  id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
  from
  t_car
  where
  brand like '%${brand}%'
</select>
@Test
public void testSelectLikeByBrand(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = mapper.selectLikeByBrand("奔驰");
    cars.forEach(car -> System.out.println(car));
}

执行结果:

img

使用#{}

第一种:concat函数

<select id="selectLikeByBrand" resultType="Car">
  select
  id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
  from
  t_car
  where
  brand like concat('%',#{brand},'%')
</select>

执行结果:

img

第二种:双引号方式

<select id="selectLikeByBrand" resultType="Car">
  select
  id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
  from
  t_car
  where
  brand like "%"#{brand}"%"
</select>

img

④、底层原理

一、getMapper 的原理


简要描述:

​ 通过 javassit 生成 dao 接口的代理类。然后 使用字符拼接的方式实现 dao 接口 要实现的方法体。


细节。

mybatis基本程序
// 1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2.创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
// 3.创建SqlSession对象           
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4.执行SQL
int count = sqlSession.insert("insertCar");

抽离核心
SqlSession sqlSession = sqlSessionFactory.openSession();
int count = sqlSession.insert("insertCar");
这两部每一个都不一样,其他1 2部相同。
    
// 获取sqlId(这里非常重要:因为这行代码导致以后namespace必须是接口的全限定接口名,sqlId必须是接口中方法的方法名。)

String sqlId = daoInterface.getName() + "." + methodName;
// 获取SqlCommondType
String sqlCommondTypeName = sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType().name();
if ("SELECT".equals(sqlCommondTypeName)) {
methodStr.append("org.apache.ibatis.session.SqlSession sqlSession = com.powernode.bank.utils.SqlSessionUtil.openSession();");
methodStr.append("Object obj = sqlSession.selectOne(\"" + sqlId + "\", arg0);");
methodStr.append("return (" + returnTypeName + ")obj;");
} else if ("UPDATE".equals(sqlCommondTypeName)) {
    methodStr.append("org.apache.ibatis.session.SqlSession sqlSession = com.powernode.bank.utils.SqlSessionUtil.openSession();");
methodStr.append("int count = sqlSession.update(\"" + sqlId + "\", arg0);");
methodStr.append("return count;");
            }    

String sqlId = daoInterface.getName() + “.” + methodName;

==这一步 限定了 mapper 文件里 的namespacce必须为接口的全类名,id为方法名。==

eg:

<mapper namespace="mapper.salgradeMapper"> -->接口的全类名
    <insert id="insert"→方法名 </insert> useGeneratedKeys="true" keyProperty="grade" >
      insert into
          salgrade(grade,losal,hisal)
        values
            (null,#{losal},#{hisal})

    </insert>
   
</mapper>

⑤动态 SQL

1.拼接 where


一个技巧

where 1=1 不会影响条件