深入理解MyBatis(一)基础及工作原理
GitHub:https://github.com/JDawnF
一、MyBatis编程步骤
-
创建 SqlSessionFactory 对象。
-
通过 SqlSessionFactory 获取 SqlSession 对象。
-
通过 SqlSession 获得 Mapper 代理对象。
-
通过 Mapper 代理对象,执行数据库操作。
-
执行成功,则使用 SqlSession 提交事务。
-
执行失败,则使用 SqlSession 回滚事务。
-
最终,关闭会话。
当 Java 代码通过 JDBC 的 PreparedStatement 向 DB 发送一条 SQL 语句时,DBMS 会首先编译 SQL 语句,然后将编译好的 SQL 放入到 DBMS 的数据库缓存池中再执行。当 DBMS 再次接收到对该数据库操作的 SQL 时,先从 DB 缓存池中查找该语句是否被编译过,若被编译过,则直接执行,否则先编译后将编译结果放入 DB 缓存池,再执行。
二、#{}
和 ${}
的区别
${}
是 Properties 文件中的变量占位符,它可以用于 XML 标签属性值和 SQL 内部,属于字符串替换。例如将 ${driver}
会被静态替换为 com.mysql.jdbc.Driver
:
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
</dataSource>
${}
也可以对传递进来的参数原样拼接在 SQL 中(有sql注入的风险)。字符串拼接是将参数值以硬编码的方式直接拼接到了 SQL 语句中。字符串拼接就会引发两个问题:SQL 注入问题与没有使用预编译所导致的执行效率低下问题。
代码如下:
<select id="getSubject3" parameterType="Integer" resultType="Subject">
SELECT * FROM subject
WHERE id = ${id}
</select>
resultType 属性并非指查询结果集最后的类型,而是每查出 DB 中的一条记录,将该记录封装成为的对象的类型。resultMap 是对 resultType的增强。
#{}是 SQL 的参数占位符,Mybatis 会将 SQL 中的 #{}
替换为 ?
号,在 SQL 执行前会使用 PreparedStatement 的参数设置方法,按序给 SQL 的 ?
号占位符设置参数值,比如 ps.setInt(0, parameterValue)
。 所以,#{}是预编译处理,可以有效防止 SQL 注入,提高系统安全性。
另外,#{}
和 ${}
的取值方式非常方便。例如:#{item.name}
的取值方式,为使用反射从参数对象中,获取 item
对象的 name
属性值,相当于 param.getItem().getName()
。
#{ }:对指定参数类型属性值的引用。其底层是通过反射机制,调用实体类相关属性的 get 方法来获取值的。因为底层使用的是反射,所以这里使用的是类的属性名,而非表的字段名。
三、实体类中的属性名与表中的字段名绑定
第一种, 通过在查询的 SQL 语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。代码如下:
<select id="selectOrder" parameterType="Integer" resultType="Order">
SELECT order_id AS id, order_no AS orderno, order_price AS price
FROM orders
WHERE order_id = #{id}
</select>
-
1、数据库的关键字,统一使用大写,例如:
SELECT
、AS
、FROM
、WHERE
。 -
2、每 5 个查询字段换一行,保持整齐。
-
3、
,
的后面,和=
的前后,需要有空格,更加清晰。 -
4、
SELECT
、FROM
、WHERE
等,单独一行,高端大气。
第二种,是第一种的特殊情况。大多数场景下,数据库字段名和实体类中的属性名差,主要是前者为下划线风格,后者为驼峰风格。在这种情况下,可以直接配置如下,实现自动的下划线转驼峰的功能。
<setting name="logImpl" value="LOG4J"/>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
第三种,通过 <resultMap>
来映射字段名和实体类属性名的一一对应的关系。代码如下:
<resultMap type="me.gacl.domain.Order" id=”OrderResultMap”>
<!–- 用 id 属性来映射主键字段 -–>
<id property="id" column="order_id">
<!–- 用 result 属性来映射非主键字段,property 为实体类属性名,column 为数据表中的属性 -–>
<result property="orderNo" column ="order_no" />
<result property="price" column="order_price" />
</resultMap>
<select id="getOrder" parameterType="Integer" resultMap="OrderResultMap">
SELECT order_no
FROM orders
WHERE order_id = #{id}
</select>
四、Mybatis工作原理如下:
Dao 实现类: