MyBatis

1 简介

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。

开发效率:Hibernate>Mybatis>JDBC

运行效率:JDBC>Mybatis>Hibernate

2 快速入手

  1. 依赖导入
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependencies>
  <!-- mybatis依赖 -->
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.11</version>
  </dependency>

  <!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! -->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.25</version>
  </dependency>

  <!--junit5测试-->
  <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.3.1</version>
  </dependency>
</dependencies>
  1. 准备Mapper接口和MapperXML文件
1
2
3
4
5
6
/*Mapper接口
*/
public interface EmployeeMapper {
    Employee selectEmployee(Integer empId);
    
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<!--MapperXML文件-->
<?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">
<!-- namespace等于mapper接口类的全限定名 -->
<mapper namespace="com.Xxx.EmployeeMapper">
    <!-- id对应方法名 resultType对应返回值类型-->
    <select id="selectEmployee" resultType="com.Xxx.Employee">
        select emp_id empId,emp_name empName, emp_salary empSalary from 
           t_emp where emp_id = #{empId}
    </select>
</mapper>
  1. 配置文件
 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
<!-- Mybatis配置文件 -->
<?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表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
  <environments default="development">
    <!-- environment表示配置Mybatis的一个具体的环境 -->
    <environment id="development">
      <!-- Mybatis的内置的事务管理器 -->
      <transactionManager type="JDBC"/>
      <!-- 配置数据源 -->
      <dataSource type="POOLED">
        <!-- 建立数据库连接的具体信息 -->
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>

  <mappers>
    <!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
    <!-- mapper标签:配置一个具体的Mapper映射文件 -->
    <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
    <!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
    <mapper resource="mappers/EmployeeMapper.xml"/>
  </mappers>

</configuration>
  1. 运行测试
 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
/**
*测试类
*/
public class MyBatisTest {

    @Test
    public void testSelectEmployee() throws IOException {
        // 1.创建SqlSessionFactory对象
        // ①声明Mybatis全局配置文件的路径
        String mybatisConfigFilePath = "mybatis-config.xml";
        // ②以输入流的形式加载Mybatis配置文件
        InputStream inputStream = Resources.getResourceAsStream(mybatisConfigFilePath);
        // ③基于读取Mybatis配置文件的输入流创建SqlSessionFactory对象
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        // 2.使用SqlSessionFactory对象开启一个会话
        SqlSession session = sessionFactory.openSession();

        // 3.根据EmployeeMapper接口的Class对象获取Mapper接口类型的对象(动态代理技术)
        EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);

        // 4. 调用代理类方法既可以触发对应的SQL语句
        Employee employee = employeeMapper.selectEmployee(1);

        System.out.println("employee = " + employee);

        // 4.关闭SqlSession
        session.commit(); //提交事务 [DQL不需要,其他需要]
        session.close(); //关闭会话

    }
}

3 具体参数

3.1 SQL传参

实际开发中,能用#{}实现的,肯定不用${}。

特殊情况: 动态的不是值,是列名或者关键字,需要使用${}拼接

1
2
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);

3.2 数据输入

  • 单个简单参数
1
Employee selectEmployee(Integer empId);
1
2
3
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee">
  select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}
</select>
  • 实体类
1
int insertEmployee(Employee employee);
1
2
3
<insert id="insertEmployee">
  insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
</insert>

img

Mybatis会根据#{}中传入的数据,加工成getXxx()方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到#{}解析后的问号占位符这个位置。

  • 多个简单类型
1
int updateEmployee(@Param("empId") Integer empId,@Param("empSalary") Double empSalary);
1
2
3
<update id="updateEmployee">
  update t_emp set emp_salary=#{empSalary} where emp_id=#{empId}
</update>
  • Map类型
1
int updateEmployeeByMap(Map<String, Object> paramMap);
1
2
3
<update id="updateEmployeeByMap">
  update t_emp set emp_salary=#{empSalaryKey} where emp_id=#{empIdKey}
</update>

3.3 数据输出

  • 单个简单类型
1
int selectEmpCount();
1
2
3
<select id="selectEmpCount" resultType="int">
  select count(*) from t_emp
</select>

resultType = “全限定符或者别名,如果是返回集合类型,写范型类型即可”

  • 返回实体类
1
Employee selectEmployee(Integer empId);
1
2
3
<select id="selectEmployee" resultType="Xxx.Employee">
  select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}
</select>

通过给数据库表字段加别名,让查询结果的每一列都和Java实体类中属性对应起来。

或者开启驼峰映射。

1
2
3
<settings>
  <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
  • Map
1
Map<String,Object> selectEmpNameAndMaxSalary();
1
2
3
<select id="selectEmpNameAndMaxSalary" resultType="map">
  SQL
</select>
  • List
1
List<Employee> selectAll();
1
2
3
4
<select id="selectAll" resultType="Employee">
  select emp_id empId,emp_name empName,emp_salary empSalary
  from t_emp
</select>
  • 返回主键值
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--主键自增-->
<!-- useGeneratedKeys属性字面意思就是“使用生成的主键” -->
<!-- keyProperty属性可以指定主键在实体类对象中对应的属性名,Mybatis会将拿到的主键值存入这个属性 -->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="empId">
  insert into t_emp(emp_name,emp_salary)
  values(#{empName},#{empSalary})
</insert>


<!-- 主键非自增 -->
<insert id="insertUser" parameterType="User">
    <!-- keyProperty 属性来指定查询到的 UUID 赋值给对象中的 id 属性-->
    <selectKey keyProperty="id" resultType="java.lang.String"
        order="BEFORE">
        SELECT UUID() as id
    </selectKey>
    INSERT INTO user (id, username, password) 
    VALUES (
        #{id},
        #{username},
        #{password}
    )
</insert>

3.4 多表映射

对一:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<resultMap id="selectOrderWithCustomerResultMap" type="order">
  <!-- 先设置Order自身属性和字段的对应关系 -->
  	<!-- 使用id标签设置主键列和主键属性之间的对应关系 -->
  	<!-- column属性用于指定字段名;property属性用于指定Java实体类属性名 -->
  <id column="order_id" property="orderId"/>
  <result column="order_name" property="orderName"/>
  <!-- 使用association标签配置“对一”关联关系 -->
  <!-- property属性:在Order类中对一的一端进行引用时使用的属性名 -->
  <!-- javaType属性:一的一端类的全类名 -->
  <association property="customer" javaType="customer">
    <!-- 配置Customer类的属性和字段名之间的对应关系 -->
    <id column="customer_id" property="customerId"/>
    <result column="customer_name" property="customerName"/>
  </association>
</resultMap>

<!-- Order selectOrderWithCustomer(Integer orderId); -->
<select id="selectOrderWithCustomer" resultMap="selectOrderWithCustomerResultMap">
  SELECT order_id,order_name,c.customer_id,customer_name
  FROM t_order o
  LEFT JOIN t_customer c
  ON o.customer_id=c.customer_id
  WHERE o.order_id=#{orderId}
</select>

对多:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 配置resultMap实现从Customer到OrderList的“对多”关联关系 -->
<resultMap id="selectCustomerWithOrderListResultMap"
  type="customer">
  <!-- 映射Customer本身的属性 -->
  <id column="customer_id" property="customerId"/>
  <result column="customer_name" property="customerName"/>
  <!-- collection标签:映射“对多”的关联关系 -->
  <!-- property属性:在Customer类中,关联“多”的一端的属性名 -->
  <!-- ofType属性:集合属性中元素的类型 -->
  <collection property="orderList" ofType="order">
    <!-- 映射Order的属性 -->
    <id column="order_id" property="orderId"/>
    <result column="order_name" property="orderName"/>
  </collection>
</resultMap>

<select id="selectCustomerWithOrderList" resultMap="selectCustomerWithOrderListResultMap">
  SELECT c.customer_id,c.customer_name,o.order_id,o.order_name
  FROM t_customer c
  LEFT JOIN t_order o
  ON c.customer_id=o.customer_id
  WHERE c.customer_id=#{customerId}
</select>
updatedupdated2023-11-132023-11-13