Mybatis常用知识点简介
入门
利用maven构建项目,需要引入相应的mybatis依赖。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
Mybatis主要是一个持久层框架,持久层的主要工作就是对数据进行增删改查等操作。对数据库的任何操作之前都需要拿到一个与数据库的会话。Mybatis应用总主要是利用sqlSessionFactory这个类为核心,为每次操作创建需要的sqlSession会话。在Mybatis的官方文档中有说明:
SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
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 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>
其中的<configuration>标签在Mybatis框架中有一个对应的类,该类中还有environment属性(就是上面<environment>标签对应的类),environment标签中还有配置数据源的标签<dataSource>和配置事务管理的标签<transactionManager>,就是框架的数据库数据源。mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。
XML映射文件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="Board">
select * from Blog where id = #{id}
</select>
</mapper>
在准备一下实体类与实体对应的表和字段就可以运行了,代码如下:
import com.mybatis.po.Board;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class mybatis01 {
public static void main(String[] args) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
Board board = (Board) sqlSession.selectOne("org.mybatis.example.BlogMapper.selectBlog", 7);
System.out.println(board);
}
}
映射器
映射器包括映射器接口和映射文件,一般情况下接口的全路径就是映射文件的namespace属性值,接口中定义的方法,方法名与映射文件中<insert>、<select>、<delete>、<update>等元素的id属性值相同。
在核心配置文件中的<mapper>标签是配置映射器的,也就是找到相应的SQL映射语句,这些映射语句就是我们要mybatis框架执行的SQL语句。我们一般会将对某个表进行操作的sql语句(select,delete,update和insert等)都放同一个映射文件中。如何找到映射文件,mybatis提供了一下四种方式:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
参数
mysql中写参数有两种方式:
- #{param}:这种参数会采用预编译的方式,先用占位符替换替换参数(可防止sql注入),在实际执行时再将解析后的参数替换掉占位符。这种参数的书写方式只能写在SQL语句中的WHERE关键字后面。
- ${param}:这种参数方式是直接赋值的,不会预编译用占位符替换(可能出现sql注入的情况)。这种参数方式不一定要放在SQL语句中的WHERE关键字后面才能执行。这种方式可以用来查询不同条件下查询不同表的数据。如:SELECT * FROM ${tableName}。根据上次调用传入参数不同查询不同的数据表。
动态SQL标签
- <if test = "boardName != null and boardName != ’ ’ ">:判断传入属性的是否满足条件,为真则执行|标签对内的语句。
- <choose>, <when test = "boardName != null and boardName != ’ ’ ">,<otherwise>标签,用于多判断分支的情况。逻辑类似Java中的switch(case和default)关键字的语法。
<choose>
<when test = "boardName != null and boardName != ''">
select id,name from table where boardName = #{boardName}
</when>
<when test = "boardNo != null and boardNo != 0">
select id,name from table where boardId = #{boardId}
</when>
<otherwise>
select id,name from table
</otherwise>
</choose>
- <where>标签:可以自动的将第一个满足条件的语句前面的逻辑运算符(or ,and)去掉。
select deptno,dname,loc from dept
<where>
<if test = "deptNo != null and deptNo != 0">
or deptNo = #{deptNo}
</if>
<if test = "dname != null and dname != ''">
and dname like '%' #{dname} '%'
</if>
</where>
- <set>标签:在update语句中会使用这个标签。<set>标签会自动将最后一个满足更新条件的字段后面的逗号“,”去掉。若 dname属性满足条件,而loc属性条件不满足,则会被解析成:update dept dname = #{dname} where deptno = #{deptNo}
update dept
<set>
<if test="dname!=null and dname!=''">
dname = #{dname},
</if>
<if test="loc!=null and loc!=''">
loc = #{loc}
</if>
</set>
where deptno = #{deptNo}
- <trim>标签:自定义第一个满足条件前部的代替内容,还可以自定义最后一个满足条件后面的代替内容。
- <foreach>标签:foreach标签用于对集合内容进行遍历,将得到内容作为SQL语句的一部分.在实际开发过程中主要用于in语句的构建和批量添加操作。
foreach元素的属性主要有 item,index,collection,open,separator,close。
collection:表示传进来的集合类型。可以是:List,Set,Map和Array等集合。一般我们在传入map集合时,collection会这样写: collection=“myMap.values” 取map集合的value值,collection=“myMap.keys” 取map集合的key值。myMap的变量名和dao层传入的map类型的变量名相同。
item:表示集合中每个元素进行迭代的别名。
index:集合迭代时的索引。
open:可以指定集合遍历后得到的SQL语句是以什么字符开头的。
close:可以指定集合遍历后得到的SQL语句是以什么字符结尾的。
separator:每个迭代过的元素之间的分隔符。最后一个元素后面不会加上分隔符。
<insert id = "insertDept">
insert into dept(dname,loc)
values
<foreach collection="list" item="dept" separator=",">
(#{dept.dname},#{dept.loc})
</foreach>
</insert>
--------------------------------------------------
// 传入的list集合如下:
Dept dept = new Dept();
dept.setdName("研发部");
dept.setLoc("杭州");
Dept dept2 = new Dept();
dept2.setdName("算法部");
dept2.setLoc("杭州");
List<Dept> deptList = new ArrayList<>();
deptList.add(dept);
deptList.add(dept2);
deptDao.insertDept(deptList);
------------------------------------
// 那么foreach标签拼装后的sql如下
insert into dept(dname,loc) values (?,?), (?,?)
// 插入后的查询语句
<select id = "findDept">
select dname,loc,deptno from dept
where deptno in
<foreach collection="array" item="deptno" open="(" separator="," close=")">
#{deptno}
</foreach>
</select>
-----------------------------------------------------
// 拼装后的sql如下,其中 "(" 是open属性指定的开始符号,")"是close属性指定的结束符号,占位符之间的逗号","就是separator属性指定的
select dname,loc,deptno from dept where deptno in (?,?)
Mybatis级联操作
在实际开发中,我们操作的表往往不是一个独立个体.它们往往根据业务依赖关系,形成一对一,一对多,多对多关联关系.为了保证业务数据的完整性.我们在操作某一张表的时候也要对与这张表关联其它表进行操作.这样的操作就成为级联操作。
- 一对多的查询
<resultMap id="deptMap" type="dept">
<id column="dept_deptno" property="deptNo" />
<result column="dname" property="dname" />
<result column="loc" property="loc" />
<!-- collection集合标签中的column属性应该填写select返回字段中来自于一方表的主键对应的字段名 -->
<collection property="empList" ofType="employee" column="dept_deptno">
<id column="empno" property="empNo"></id>
</collection>
</resultMap>
<!-- 查询当前部门下所有职员信息及当前部门的基本信息 -->
<select id="deptFindById" resultMap="deptMap">
select d.deptno as dept_deptno, d.dname, d.loc,
e.empno, e.ename, e.job, e.sal
from dept d
left join emp e
on d.deptno = e.deptno
where d.deptno = #{deptno}
</select>
上述映射文件中对应的dept实体类如下(employee类省略):
public class Dept {
private Integer deptNo;
private String dname;
private String loc;
private List<Employee> empList;
// setter和getter方法省略
}
- 多对一的查询
<resultMap id="empMap" type="employee">
<id column="empno" property="empNo"></id>
<result column="ename" property="ename" />
<result column="job" property="job" />
<result column="sal" property="sal" />
<!-- association用来表示关联的实体 -->
<association property="dept" javaType="Dept">
<result column="dept_deptno" property="deptNo" />
<result column="dname" property="dname" />
<result column="loc" property="loc" />
</association>
</resultMap>