1 多对一关联查询
需求:查询某个员工时查询他所在的部门
1.1准备工作
1.加入部门表t_dept:
2. 改造员工表,给员工表t_employee添加外键字段d_id
3.插入测试数据
4.在domain包中加入Dept类,改造Employee类(加入Dept属性)
1.2使用resultType映射查询结果集(理解)
由于sql语句是多表的连接查询,结果集中的部门的2个字段不能直接封装到Employee对象上,resultType=”employee”不可用,如果你非要用resultType,则
需要用VO思想对Employee类进行扩展
1.2.1创建EmployeeVo类
EmployeeVo类中扩展部门相关的属性
public class EmployeeVo extends Employee {
//部门相关的属性
private Integer did;
private String dname;
1.2.2创建EmployeeMapper接口
1.2.3 配置EmployeeMapper.xml
1.2.4测试
1.3使用resultMap映射查询结果集(掌握)
多对一或一对一都使用association标签映射关联对象,有两种做法:
1.3.1 使用resultMap结果嵌套
配置EmployeeMapper.xml,将关联对象的查询结果嵌套在resultMap中,步骤如下:
- A.定义resultMap
<resultMap type="employee" id="empMap">
<id column="eid" property="eid"/>
<result column="ename" property="ename"/>
<result column="salary" property="salary"/>
<!-- association映射关联的对象,javaType不可省略 -->
<association property="dept" javaType="Dept">
<id column="did" property="did"/>
<result column="dname" property="dname"/>
</association>
</resultMap>
- B.引用resultMap
<select id="queryEmp" resultMap="empMap">
select t1.eid,t1.ename,t1.salary,t2.did,t2.dname from t_employee t1 JOIN t_dept t2 on t1.d_id=t2.did
where t1.eid=#{id}
</select>
1.3.2使用resultMap查询嵌套
查询嵌套即在association中使用select嵌套一个sql查询,将整个查询分成了2步,又叫分步查询.步骤如下:
- A.定义resultMap
<resultMap type="employee" id="empStepMap">
<id column="eid" property="eid"/>
<result column="ename" property="ename"/>
<result column="sex" property="sex"/>
<result column="salary" property="salary"/>
<!-- association映射关联的对象 ,column:指定将哪个列的值传给查询方法
select:指定一个satement的唯一标识,定位查询方法 -->
<association property="dept" javaType="dept" select="cn.sxt.mapper.DeptMapper.queryDept" column="d_id">
</association>
</resultMap>
其中association的select的值引用DeptMapper.xml中的一个select
- B.引用resultMap
<select id="queryEmpPlus" resultMap="empStepMap">
select * from t_employee
where eid=#{id}
</select>
1.3.3测试
2 一对多关联查询
需求:查询某个部门时查询该部门的所有员工
2.1准备工作
1)改造Dept类,加入一个List集合(Set也可)
- .在DeptMapper接口中添加一个方法
2.2使用resultMap映射查询结果集(掌握)
2.2.1 使用resultMap结果嵌套
对 DeptMapper.xml中进行配置,步骤如下:
- A.定义resultMap
resultMap中使用collection标签映射关联的集合
<resultMap type="dept" id="deptMap">
<id column="did" property="did" />
<result column="dname" property="dname" />
<!-- collection:映射集合类型的属性 ofType:指定集合中元素的类型 javaType:集合类型(可以省略) -->
<collection property="emps" ofType="employee" javaType="list">
<id column="eid" property="eid" />
<result column="ename" property="ename" />
<result column="salary" property="salary" />
</collection>
</resultMap>
- B.引用resultMap
<select id="queryDeptPlus" resultMap="deptMap">
select d.did,d.dname ,
e.eid,e.ename,e.salary from t_dept d LEFT JOIN
t_employee e on
d.did=e.d_id where d.did=#{id}
</select>
2.2.2 使用resultMap查询嵌套
类似于多对一查询嵌套,又叫分步查询。步骤如下:
- A.定义resultMap
<resultMap type="dept" id="deptStepMap">
<id column="did" property="did"/>
<result column="dname" property="dname"/>
<!-- select:指定一个satement的唯一标识,定位查询方法 -->
<collection property="emps" ofType="employee" select="cn.sxt.mapper.EmployeeMapper.queryEmpsByDeptId" column="did"></collection>
</resultMap>
其中collection 的select的值引用EmployeeMapper.xml中的一个select
<select id="queryEmpsByDeptId" resultType="employee">
select eid,ename,salary,sex from t_employee where d_id=#{id}
</select>
- B.引用resultMap
<select id="queryDeptByStep" resultMap="deptStepMap">
select * from t_dept where did=#{id}
</select>
2.2.3测试
3 resultType和resultMap总结
resultType: 如果查询的结果集只需要封装为一个对象 (没有级联查其关联对象或集合),使用resultType
resultMap: 如果查询的结果集中包含主对象还要包含其关联的对象时,必须用resultMap来映射结果集;如果表的字段和属性名不一致,也要用resultMap.
4 懒加载(延迟加载)
使用resultMap分步查询时,默认在查询Employee时,将部门对象也一起查出来了。我们希望部门信息在需要用的时候才去查询,此时可以使用延迟加载策略
5.1开启懒加载
在主配置文件的settings标签中,配置如下:
<settings>
<!-- true:启用延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- false:每种属性将会按需要加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
5.2测试
5 动态sql
如果你有使用 JDBC 或其他相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空格或在列表的最后省略逗号。动态 SQL 可以彻底处理这种痛苦。
通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语 言来改进这种情形,这种语言可以被用在任意映射的 SQL 语句中。
6.1 if标签
类似于jsp里的c:if标签
select * from t_employee where
<if test="eid!=null">
eid=#{eid}
</if>
<if test="ename!=null">
and ename li
6.2 where标签
使用where将所有查询条件包含在内,mybatis会将拼接后SQL的首个and去掉
select * from t_employee
<where>
<if test="eid!=null">
and eid=#{eid}
</if>
<if test="ename!=null">
and ename like #{ename}
</if>
<if test="sex!=null">
and sex= #{sex}
</if>
</where>
6.3 choose标签
有些时候,我们不想用到所有的条件语句,而只想从中选择一个。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 s例如:
select * from t_employeewitch 语句。
<where>
<choose>
<when test="eid!=null">
and eid=#{eid}
</when>
<when test="ename!=null">
and ename like #{ename}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
如果用户提供了eid就按eid查, 提供了ename值就按ename查,否则就走otherwise
6.4 set标签
使用set标签引出修改的条件,会智能的去掉多余的逗号
<update id="updateEmp">
update t_employee
<set>
<if test="ename!=null">ename=#{ename},</if>
<if test="sex!=null">sex=#{sex}</if>
</set>
where eid=#{eid}
</update>
6.5 foreach标签
foreach 元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。
<select id="queryEmps" resultType="employee">
<!--
collection:指定要遍历的集合(数组),值为array表示传过来的参数是数组,值为list表示参数是List集合类型
item:将当前遍历出的元素赋值给某个变量
separator:每个元素之间的分隔符
open:遍历出所有结果拼接一个开始的字符
close:遍历出所有结果拼接一个结束的字符
-->
select * from t_employee where eid in
<foreach collection="list" item="item_id" separator="," open="(" close=")">
#{item_id}
</foreach>
</select>
7 mybatis的一二级缓存(了解)
7.1mybatis一级缓存
在SqlSession范围内。当查询相同对象时,会使用缓存中的数据,而不会再次查询。
Mybatis默认开启了一级缓存
7.2mybatis二级缓存
mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper通常情况下有不同的namespace,就都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的。为了更加清楚的描述二级缓存,先来看一个示意图:
从图中可以看出:
1) sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询到的数据存储到该UserMapper的二级缓存中。
2) 如果SqlSession3去执行相同 mapper下sql,执行commit提交,则会清空该UserMapper下二级缓存区域的数据。
3) sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
二级缓存与一级缓存区别在于二级缓存的范围更大,多个sqlSession可以共享一个mapper中的二级缓存区域。mybatis是如何区分不同mapper的二级缓存区域呢?它是按照不同mapper有不同的namespace来区分的
在使用二级缓存之前,首先得开启二级缓存的开关,方法是在主配置文件的settings中加入:
<setting name="cacheEnabled" value="true"/>
然后在你要缓存数据的Mapper.xml中加入一个cache:
注意:需要缓存数据的实体类要实现可序列化接口
8 注解
Mybatis允许我们在mapper.xml中去映射每个Mapper接口的方法,也允许直接在
Mapper接口方法上使用相应的注解来取代XML配置。常用注解:
1).@Insert: 对应的是Mapper.xml中的insert标签
2).@Update
3).@Delete
4).@Select:对应select标签
5).@Param:指定参数的名称
@Param注解用于指定传给占位符的参数名字,此时占位符里面的xxx就必须与注解的参数名一致。通常用在方法的形参前,给该参数指定名字
注解不能完全代替XML配置的,如果查询结果需要使用resultMap来映射,那么不要用注解,如果要执行动态SQL,也不能用注解。Mybatis允许注解和Mapper.xml配置共存,只要你愿意用。
9 逆向工程
9.1什么是逆向工程
MyBatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(包括mapper.xml、mapper.java、po..)。一般在开发中,常用的逆向工程方式是由数据库的表生成JAVA代码。 (powerDesigner工具快速生成数据表)
9.2 使用逆向工程
使用MyBatis的逆向工程,需要导入逆向工程的jar包,我用的是mybatis-generator-core-1.3.2.jar,下面说一下MyBatis逆向工程的使用步骤
- .新建一个java工程
这个工程专门用来使用逆向工程生成代码的。有些人可能会问,为什么要新建一个工程呢?直接在原来工程中你想生成不就可以了么?确实是这样,可以在原来的工程中生成,但是有风险,因为MyBatis是根据配置文件来生成的(下面会说到),如果生成的路径中有相同的文件,那么就会覆盖原来的文件,这样会有风险。所以开发中一般都会新建一个java工程来生成,然后将生成的文件拷贝到自己的工程中,这也不麻烦,而且很安全。加入mybatis-generator-core-1.3.2.jar,mybatis-3.2.8.jar,驱动包
- .配置逆向工程的配置文件
打开mybatis-generator-core-1.3.2目录下的docs里的index.html,里面有模板。
我们用带了中文注释的配置文件generatorConfig.xml,放到项目根路径下。
配置文件主要做的几件事是:
a,连接数据库,这是必须的,要不然怎么根据数据库的表生成代码呢?
要根据实际情况去改模板里的连接数据库的参数
b,指定要生成代码的位置,要生成的代码包括po类,mapper.xml和mapper.java
c,指定要对哪些表逆向生成相应的java代码(po类,Mapper接口及Mapper.xml)
3.运行逆向工程生成java代码
执行以下程序即可生成代码了,生成的java程序,下载的逆向工程文档中都有示例,如下:
public class GeneratorSqlmap {
public void generator() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
// 指定逆向工程配置文件
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) throws Exception {
try {
GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
generatorSqlmap.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行完了后刷新一下工程,就可以看到最新生成的代码了。
到这里就生成好了,下面我们就把生成的代码拷贝到自己的工程使用了。