使用
标签,逐一定义列名和对象属性名之间的映射关系;
使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME,对象属性名一般是 name;
有了列名与属性名的映射关系后,MyBatis 通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
延迟加载是指在需要访问某个对象的属性时,才去初始化该属性。在 MyBatis 中,延迟加载可以用于嵌套查询中避免产生大量的 SQL 查询语句,提高查询效率。
MyBatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 MyBatis 配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。
使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName() ,拦截器 invoke() 方法发现 a.getB() 是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName() 方法的调用。这就是延迟加载的基本原理。
使用 BatchExecutor 完成批处理。
批处理是指在执行数据库操作时,将多个 SQL 语句一次性发送到数据库中执行,而不是每次仅发送一个 SQL 语句。
批处理可以提高数据库操作的效率,因为它可以将多个数据库操作合并为一个事务来执行,从而减少了数据库连接和网络通信的开销。同时,批处理还可以减少锁表的时间,提高并发性能。在数据批量插入、更新、删除等场景中,批处理尤为重要,因为这些操作可能会涉及到大量的数据,如果使用逐条操作,效率会非常低下。
在 MyBatis 中,Executor 是 MyBatis 的执行器,用于执行 SQL 语句。它通过 SqlSession.getMapper(Class type) 方法获取指定 Mapper 的代理实现类,然后执行相应的方法,实现数据库的访问操作。在进行数据库操作时,Executor 的作用非常重要。MyBatis 中共有三种 Executor:
SimpleExecutor:每执行一次 update 或者 query 操作,就开启一个 Statement 对象,用完立刻关闭 Statement 对象,在返回结果之前,不会开启下一个 SQL 操作的 Statement 对象。
ReuseExecutor:缓存 Statement 对象,在下一次操作相同 SQL 语句时,从缓存中获取 Statement 对象,而不是新建一个 Statement 对象。
BatchExecutor:将多个 SQL 语句一次性发送到数据库中执行,以减少数据库连接、开销和锁表时间。
在 MyBatis 的配置文件中,可以通过设置
标签下的 defaultExecutorType
属性来设置默认的执行器类型,也可以通过 SqlSession 的方法来指定不同的执行器类型。
Executor 的作用不仅仅是执行 SQL 语句,还有以下几个方面:
封装数据库连接的获取和释放过程,屏蔽底层 JDBC API 的细节,使开发者专注于 SQL 操作。
处理缓存功能,避免因多次从数据库中查询同一个对象而导致的性能浪费。
处理返回结果集的类型和数量,对查询结果进行处理和封装,返回与 Mapper 方法声明相同类型的结果对象。
需要注意的是,不同的执行器类型有各自的优缺点,需要根据实际的业务场景和系统性能做出选择。简单来说,SimpleExecutor 适用于单线程的短时连接,系统并发度不高的场景;ReuseExecutor 适用于多线程、高并发、请求量大的场景;BatchExecutor 适用于数据量大、插入、更新、删除等批量操作。
在 MyBatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给 DefaultSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数。
MyBatis 可以映射 Enum 枚举类。
在 MyBatis 的 Mapper 文件中,可以声明一个 parameterType 或 resultMap,将 Enum 枚举类作为参数或返回结果:
在 Mapper 文件中,可以直接声明一个 Enum 枚举类的参数类型:
在 resultMap 中,可以配置对应枚举类的转换器类型,将数据库存储的字符串类型转换成相应的枚举类型:
其中,typeHandler 指定转换器的类型,GenderTypeHandler 是自定义的实现了 TypeHandler 接口的类型转换器类。需要注意的是,TypeHandler 的泛型类型需要和枚举类的类型保持一致:
public class GenderTypeHandler implements TypeHandler {
@Override
public void setParameter(PreparedStatement ps, int i, Gender parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.name());
}
@Override
public Gender getResult(ResultSet rs, String columnName) throws SQLException {
return Gender.valueOf(rs.getString(columnName));
}
@Override
public Gender getResult(ResultSet rs, int columnIndex) throws SQLException {
return Gender.valueOf(rs.getString(columnIndex));
}
@Override
public Gender getResult(CallableStatement cs, int columnIndex) throws SQLException {
return Gender.valueOf(cs.getString(columnIndex));
}
}
这样,MyBatis 就可以很好的支持枚举类型的映射了。
虽然 MyBatis 解析 xml 映射文件是按照顺序解析的,但是,被引用的 B 标签依然可以定义在任何地方,MyBatis 都可以正确识别。原理是,MyBatis 解析 A 标签,发现 A 标签引用了 B 标签,但是 B 标签尚未解析到,尚不存在,此时,MyBatis 会将 A 标签标记为未解析状态,然后继续解析余下的标签,包含 B 标签,待所有标签解析完毕,MyBatis 会重新解析那些被标记为未解析的标签,此时再解析 A 标签时,B 标签已经存在,A 标签也就可以正常解析完成了。
MyBatis 将所有 xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 xml 映射文件中,
标签会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象。
标签会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。每一个 标签均会被解析为 MappedStatement 对象,标签内的 sql 会被解析为 BoundSql 对象。
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 MyBatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。
MyBatis是一种半自动ORM映射工具,主要表现在以下两个方面:
MyBatis不会自动创建和管理数据库对象之间的映射关系,而是要求用户手动编写SQL语句。例如,下面的SQL语句查询订单以及订单对应的客户信息:
<select id="getOrder" resultType="Order">
SELECT o.*, c.name as customer_name, c.address as customer_address
FROM order o
LEFT JOIN customer c on o.customer_id = c.id
WHERE o.id = #{orderId}
select>
在这个例子中,用户需要自己手动编写SQL语句,并且指定查询结果的Java对象类型为Order。这就是MyBatis相对于Hibernate而言半自动的原因之一。
MyBatis通常使用XML配置文件或注解来定义Java对象和数据库表之间的映射关系。例如,下面是一个使用XML配置文件定义映射关系的例子:
<resultMap id="orderResultMap" type="Order">
<id property="id" column="id" />
<result property="orderName" column="order_name" />
<result property="customer" resultMap="customerResultMap" />
resultMap>
<resultMap id="customerResultMap" type="Customer">
<id property="id" column="id" />
<result property="name" column="customer_name" />
<result property="address" column="customer_address" />
resultMap>
在这个例子中,我们定义了两个resultMap,其中orderResultMap是Order对象和数据库表之间的映射关系,customerResultMap是Customer对象和数据库表之间的映射关系。需要注意的是,这里每个映射都需要手动指定相关字段之间的映射关系,这也是MyBatis相对于Hibernate而言半自动的原因之二。
相比之下,Hibernate是一种全自动的ORM映射工具,它使用对象关系映射(ORM)自动创建并管理Java对象和数据库表之间的映射关系。例如,下面的代码使用Hibernate查询订单以及订单关联的客户信息:
Order order = session.get(Order.class, orderId);
Customer customer = order.getCustomer();
在这个例子中,Hibernate会自动查询关联的客户对象并返回,因此是全自动的。
综上所述,MyBatis相对于Hibernate而言是一种半自动的ORM映射工具,需要用户手动编写SQL语句以及指定Java对象和数据库表之间的映射关系。