MyBatis
官方网站: https://mybatis.org/mybatis-3/zh/index.html
基本配置文件
导包:
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
-
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="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>
-
BlogMapper.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"> <mapper namespace="org.mybatis.example.BlogMapper"> <select id="selectBlog" resultType="Blog"> select * from Blog where id = #{id} </select> </mapper>
常见问题
-
Maven 无法打包java目录下的xml配置文件
解决方法: pom.xml中添加以下配置
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> </resources> </build>
-
Mapper映射的 namespace和resultType 因为没有用使用全限定名, 导致无法找到对应的类
解决方法: namespace和resultType 使用全限定名
<?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"> <mapper namespace="com.xtyuns.dao.UserDao"> <select id="getUserList" resultType="com.xtyuns.pojo.User"> select * from user </select> </mapper>
-
每一个映射配置文件都需要在MyBatis的主配置文件中注册
<mappers> <mapper resource="com/xtyuns/dao/UserMapper.xml"/> </mappers>
-
Maven的编译环境为JDK1.5
解决方法: pom.xml中添加以下配置内容
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties>
-
DML 语句必须需要提交事务
核心配置文件
properties
<properties resource="db.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
property 插入的配置优先级低于 resource 文件中的配置项
设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
settings
<settings>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
- 自动将数据库中的下划线命名转换为驼峰命名进行映射, 如 a_col 会识别为 aCol
- 使用默认控制台打印日志
typeAliases
-
typeAlias
<typeAliases> <typeAlias alias="Author" type="domain.blog.Author"/> <typeAlias alias="Blog" type="domain.blog.Blog"/> <typeAlias alias="Comment" type="domain.blog.Comment"/> <typeAlias alias="Post" type="domain.blog.Post"/> <typeAlias alias="Section" type="domain.blog.Section"/> <typeAlias alias="Tag" type="domain.blog.Tag"/> </typeAliases>
-
package
<typeAliases> <package name="domain.blog"/> </typeAliases>
每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。
mybatis为常见的 Java 类型也设置了别名, 且它们都是不区分大小写的: https://mybatis.org/mybatis-3/zh/configuration.html#typeAliases
其他配置
暂时没用到, 略…
mappers
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<!-- 此时应在 **同级目录** 中创建与相应类 **同名** 的语句映射文件(AuthorMapper.xml等...) -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
另外两种方法不再赘述。
常用注解
@Select("select * from user where id = #{uid}")
User getUserById(@Param("uid") Long id);
*** 复杂关系映射
多对一: 关联(association), 多个学生关联到同一个老师
一对多: 集合(collection), 一个老师有多个学生
动态SQL
推荐阅读文章: MyBatis-DynamicSQL 动态SQL
if 标签 / 模糊查询
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = 'ACTIVE'
<if test="title != null">
AND title like concat('%', #{title}, '%')
</if>
<if test="author != null and author.name != null">
AND author_name like concat('%', #{author.name}, '%')
</if>
</select>
模糊查询可以使用sql中的 concat() 函数来实现
或者使用 bind 标签, 进行参数的二次赋值
<bind name="xxx" value="'%'+ id + '%'"/>
trim(where/set) 标签
where 标签
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
where 标签只会在子元素包含内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<where> 等同于 <trim prefix="WHERE" prefixOverrides="AND |OR ">
set 标签
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
这个例子中,set 标签会动态地在行首插入 SET 关键字, 并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
<set> 等同于 <trim prefix="SET" suffixOverrides=",">
个人感悟
where/set 只会帮你 去掉 多余的 前缀/后缀, 而 并不会帮你添加 它们
因此在 where 标签就看作是已经加上了
where 1=1
, 你可以从第一个自己写语句开始就加上AND
/OR
符号(反正多余的会帮你去掉)同理, 你需要在 set 的任意子标签中后面都加上
,
(因为Mybatis会帮你去掉最后一个语句的,
)这样才能够更好的体现 where/set 标签的作用。
缓存
一级缓存
本地的会话缓存, 默认开启, 无法关闭
作用域: SqlSession 级别, 仅在一个 sqlSession 的生命周期内缓存数据
二级缓存
全局缓存, 需要手动配置 mapper.xml
原理: sqlSession 关闭后, 一级缓存中的数据转存到二级缓存中(二级缓存也只能在同一个 namespace 中使用, 但是有一个 cache-ref 标签)
常见问题: 缓存的数据需要实现序列化, 否则缓存无法正常保存, 会抛出异常
<!-- 在指定的 mapper.xml 中开启二级缓存 -->
<cache/>
<!-- 自定义二级缓存的参数 -->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
缓存失效
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用, 当超过这个数值时 Mybatis 默认会使用最近最少使用算法(LRU, Least Recently Used)来清除不需要的缓存。
- 手动调用 sqlSession 对象的 clearCache() 方法。
缓存查询顺序
二级缓存 -> 一级缓存 -> 数据库