1. MyBatis-config.xml配置
1.1 properties属性读取外部资源
例:resource下添加资源文件.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis-44
username=root
password=root
在Mybatis-config.xml中引入jdbc.properties资源文件:
<!-- 引入外部资源文件,resource:相对路径,url:绝对路径(不建议使用) -->
<properties resource="jdbc.properties" />
通过properties引入外部资源文件之后,就可以通过${xxx}的方式使用资源文件里的参数了
1.2 settings设置
开启驼峰匹配:完成经典的数据库命名到java属性的映射
经典数据库命名:如果多个单词之间,通常使用下划线进行连接。
java中命名:第二个单词首字母大写。
驼峰匹配:相当于去掉数据中的名字的下划线,和java进行匹配
查询数据的时候,查不到userName的信息,原因:数据库的字段名是user_name,POJO中的属性名字是userName,两端不一致,造成mybatis无法填充对应的字段信息。修改方法:在sql语句中使用别名
解决方案1:在sql语句中使用别名
解决方案2:参考驼峰匹配 — mybatis-config.xml
mybatis-config.xml中开启驼峰匹配:
<settings>
<!-- 开启驼峰匹配:经典的数据库列名(多个单词下划线连接)映射到经典的java属性名(多个单词驼峰连接) -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
1.3 typeAliases类型别名
之前在映射文件中用到java类型时,都是使用类的全路径,书写起来非常麻烦
解决方案:
类型别名是为 Java 类型命名的一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。(官方文档)
1. 方式一:typeAlias (缺点:每个pojo类都要去配置)
<typeAliases>
<!-- 类型别名:type-pojo类的全路径,alias-别名名称(可随便写,推荐和类名一致) -->
<typeAlias type="cn.itcast.mybatis.pojo.User" alias="user" />
</typeAliases>
- 方式二:package
<!-- 开启别名包扫描,name:包路径,扫描的别名就是类名,并且大小写不敏感 -->
<package name="cn.itcast.mybatis.pojo"/>
1.4 environments(环境)
MyBatis 可以配置成适应多种环境,例如,开发、测试和生产环境需要有不同的配置;
尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一。
虽然,这种方式也可以做到很方便的分离多个环境,但是实际使用场景下,我们更多的是选择使用spring来管理数据源,来做到环境的分离
- 方式一:environments标签内指定default采用哪个环境
- 方式二:通过build方法的重载方法.用法:new SqlSessionFactoryBuilder().build(inputStream,”指定的环境”);
2.Mapper XML 文件(映射文件)
2.1 CRUD标签
- select标签: 查询的statement,
id:在同一namespace下的唯一标识,使用动态代理之后要求和接口的方法名一致,必须参数
resultType:结果集的包装类型,和resultMap二选一
parameterType:参数类型,可省略
内容:查询的sql
<select id="queryUserById" resultMap="userMap">
select * from tb_user where id = #{id}
</select>
- insert标签: 新增的statement
id:在同一namespace下的唯一标识,使用动态代理之后要求和接口的方法名一致,必须参数
parameterType:参数类型,可省略
useGeneratedKeys:开启主键回写
keyColumn:主键列名
keyProperty:主键的属性名
<insert id="insertUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id" >
INSERT INTO tb_user (
user_name,
password,
name,
age,
sex,
birthday,
created,
updated
)
VALUES
(
#{userName},
#{password},
#{name},
#{age},
#{sex},
#{birthday},
NOW(),
NOW()
);
</insert>
- update标签:
<update id="updateUser" parameterType="cn.itcast.mybatis.pojo.User">
UPDATE tb_user
SET
user_name = #{userName},
password = #{password},
name = #{name},
age = #{age},
sex = #{sex},
birthday = #{birthday},
updated = NOW()
WHERE
(id = #{id});
</update>
- delete标签:
<delete id="deleteUserById" parameterType="cn.itcast.mybatis.pojo.User">
delete from tb_user where id=#{id}
</delete>
2.3 parameterType传入参数
CRUD标签都有一个属性parameterType,statement通过它指定接收的参数类型。
接收参数的方式有两种:
1、 #{}预编译
2、${}非预编译(直接的sql拼接,不能防止sql注入)
参数类型有三种:
1、 基本数据类型
2、 HashMap(使用方式和pojo类似)
3、 Pojo自定义包装类型
- 使用
去接收参数信息,在一个参数时,默认情况下必须使用
{value}获取参数值,
而#{} 只是表示占位,与参数的名字无关,如果只有一个参数,可以使用任意参数名接收参数值,会自动对应
但是这并不是一种稳妥的解决方案,推荐在接口方法形参前使用@Param注解指定参数名
例:
public void queryUsers(@Param("userName")String userName);
- 在mybatis的mapper中,参数传递方式有两种,一种是#{}一种是${},两者有很大区别:
- ${}实现的是sql语句的直接拼接,不做数据类型的转换,需要自行判断数据类型,不能防止sql注入
- #{}实现的是sql语句的预处理参数,之后执行sql语句用?代替,使用时不需要关注数据类型,mybatis自动实现数据类型转换,并且可以防止sql注入
- 总结:#{}占位符,用于参数传递, ${}用于sql拼接
2.4 resultMap
resultMap是mybatis中最重要最强大的元素,使用resultMap可以解决两大问题:
- pojp属性名和表结构字段名不一致的问题(有些情况下也不是标准的驼峰格式),解决方案:使用resultMap自定义映射(autoMapping="true")
- 完成高级查询,如一对一,一对多,多对多
配置resultMap:自定义映射关系
id:唯一标识 .type:结果集的包装类型 . autoMapping:开启自动映射,如果开启了驼峰匹配,就以驼峰匹配的形式进行映射
子标签:
id:指定主键映射的,可以提高性能
result:其他的非主键字段
column-表中的字段名
property-对应的java属性名
<resultMap type="User" id="userMap" autoMapping="true">
<id column="id" property="id"/>
<!-- <result column="user_name" property="userName"/> -->
</resultMap>
2.5 sql片段(即sql语句的抽取)
- 使用方式一:sql标签可以定义一个sql片段,在需要使用该sql片段的地方,通过include标签来使用
<sql id="commonSql">
id,user_name,
password,
name,
age,
sex,
birthday,
created,
updated
</sql>
<select id="queryUsersLikeUserName" resultType="User">
select <include refid="commonSql"></include> from tb_user where user_name like '%' #{userName} '%'
</select>
- 使用方式二:很多时候同一个sql片段,可能在很多映射文件里都有使用,这就需要添加一个映射文件,用来统一定义sql片段。
如下,在resource目录下新增CommonSQL.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace(命名空间):映射文件的唯一标识 -->
<mapper namespace="CommonSQL">
<sql id="commonSql">
id,user_name,
password,
name,
age,
sex,
birthday,
created,
updated
</sql>
</mapper>
首先应该把该映射文件引入到mybatis的全局配置文件中(mybatis-config.xml)
最后在需要使用该sql片段的地方通过include标签的refId属性引用该sql片段:
<select id="queryUsersLikeUserName" resultType="User">
select <include refid="CommonSQL.commonSql"></include> from tb_user where user_name like '%' #{userName} '%'
</select>
3. 动态sql
mybatis的一个强大的特性之一通常是它的动态sql能力,提供了ognl表达式动态生成sql的功能,动态sql有:
- if
- choose,when,otherwise
- where,set
- foreach
select * from tb_user where sex=1
<!-- if:判断
test:OGNL表达式
-->
<if test="userName!=null and userName.trim()!=''">
and user_name like '%' #{userName} '%'
</if>
select * from tb_user where sex=1
<!-- choose:条件选择
when:test-判断条件,一旦有一个when成立,后续的when都不再执行
otherwise:所有的when都不成立时,才会执行
-->
<choose>
<when test="userName!=null and userName.trim()!=''">and user_name like '%' #{userName} '%'</when>
<when test="age != null">and age = #{age}</when>
<otherwise>and user_name = 'zhangsan' </otherwise>
</choose>
select * from tb_user
<!--
自动添加where关键字
有一定的纠错功能:去掉sql语句块之前多余的一个and|or
通常结合if或者choose使用
-->
<where>
<if test="userName!=null and userName.trim()!=''">user_name like '%' #{userName} '%'</if>
<if test="age!=null">and age = #{age}</if>
</where>
UPDATE tb_user
<!--
set自动添加set关键字
也有一定的纠错功能:自动去掉sql语句块之后多余的一个逗号
-->
<set>
<if test="userName!=null and userName.trim()!=''">user_name = #{userName},</if>
<if test="password!=null and password.trim()!=''">password = #{password},</if>
<if test="name!=null and name.trim()!=''">name = #{name},</if>
<if test="age!=null">age = #{age},</if>
<if test="sex!=null">sex = #{sex}</if>
</set>
WHERE
(id = #{id});
select * from tb_user where id in
<!--
foreach:遍历集合
collection:接收的集合参数
item:遍历的集合中的一个元素
separator:分隔符
open:以什么开始
close:以什么结束
-->
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
4. 缓存
4.1 一级缓存
在mybatis中,一级缓存默认是开启的,并且一直无法关闭,作用域:在同一个sqlSession下
在UserMapperTest中添加测试一级缓存的方法:
@Test
public void testCache(){
User user1 = this.userMapper.queryUserById(1l);
System.out.println(user1);
System.out.println("=================第二次查询======================");
User user2 = this.userMapper.queryUserById(1l);
System.out.println(user2);
}
由于一级缓存的存在,此时在log日志中,应该只会在第一次查询是执行sql语句,第二次查询时直接从缓存中命中,即不再执行sql语句。
使用:sqlSession.clearCache();可以强制清除缓存
在执行第二次查询之前清空缓存,再去执行查询。这时无法从缓存中命中,便会去执行sql从数据库中查询。
执行update、insert、delete的时候,会清空缓存
4.2 二级缓存
mybatis 的二级缓存的作用域:
1、 同一个mapper的namespace,同一个namespace中查询sql可以从缓存中命中。
2、 跨sqlSession,不同的SqlSession可以从二级缓存中命中
怎么开启二级缓存:
1、 在映射文件中,添加标签
2、 在全局配置文件中,设置cacheEnabled参数,默认已开启。
注意:
由于缓存数据是在sqlSession调用close方法时,放入二级缓存的,所以第一个sqlSession必须先关闭
二级缓存的对象必须序列化,例如:User对象必须实现Serializable接口。
开启二级缓存,在映射文件(UserMapper.xml)中添加:
在UserMapperTest中添加二级缓存的测试方法:
@Test
public void testCache2(){
User user1 = this.userMapper.queryUserById(1l);
System.out.println(user1);
// 注意:关闭sqlSession
sqlSession.close();
System.out.println("=================第二次查询======================");
// 重新打开一个sqlSession会话
SqlSession sqlSession2 = this.sqlSessionFactory.openSession();
// 通过sqlSession2重新实例化UserMapper
this.userMapper = sqlSession2.getMapper(UserMapper.class);
User user2 = this.userMapper.queryUserById(1l);
System.out.println(user2);
}