内容目录:
1. 动态SQL语句。
(1) Xml方式。
(2) Annotation方式。
2. MyBatis的缓存。
3. MyBatis的关联查询-多表查询。
4. MyBatis逆向工程。
1. 动态SQL语句
1.1. 动态SQL是什么
相对与固定SQL语句。根据参数不同组成不同结构的SQL语句。
这种根据参数的不同而不同的SQL语句,我们称为动态SQL语句。
1.2. 动态SQL有什么用
1.根据条件组装不同结构的SQL语句,可以提高SQL代码的重用性。
2.满足某些特定需求,如:条件判断查询。
1.3. 基于XML的实现
1.3.1. 标签包括
<sql>:用于声明SQL语句块,在操作标签中通过<include>标签引入。
<if>:类似java if(){},用于判断。
<foreach>:类似java的foreach循环,一般用于批量处理的SQL语句,如批量更新、插入、删除。
<trim>:切割标签,主要用于切割关键字的头和尾的字符。新版Mybatis的使用几率很少。
<set>:使用 set标签就是SQL语言的set关键字,可以在update 的时候,设置set 关键字后面的更新字段,逗号可以自动忽略。
<where>:使用where标签作为SQL语言的where关键字,如果where后面的条件都不成立,忽略where关键字。
<choose> <when><otherwise> : java的if else if... else。
1.3.2. 接口文件
package
1.3.3. 映射文件
<?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.cjw.mapper.UserMapper">
<!-- 多行查询
resultType : 只是返回的当行数据封装的对象类型,无论单行还是多行查询都必须返回对应的实体类型User
由于配置文件中已经设置了别名,所以这里使用别名
-->
<select id="selectByCondition" parameterType="User" resultType="User">
<!--
select * from tb_user where name like concat('%',#{name},'%') or age = #{age}
上述SQL语句的语义来说,是一个静态SQL语句,一开始已经确定SQL的语义
不管有没有数据,都会对全部数据进行修改,如果某一个数据没有,name会自动设置为null
不符合实际场景
解决方案: 使用MyBatis的动态SQL语句
-->
select * from tb_user
<!--
<include refid=""></include>
包含引入sql片段
refid :被引入的sql片段的id值
-->
<include refid="condition_sql"/>
</select>
<select id="selectTotalByCondition" parameterType="User" resultType="Long">
select count(1) from tb_user
<include refid="condition_sql"/>
</select>
<!--
<sql id=""></sql>
抽取sql片段
id属性:片段的唯一标识,以供其他地方使用
-->
<sql id="condition_sql">
<!-- 动态SQL语句
<where>标签
在where内部编写条件,
1,如果只要满足一个条件<where>标签会自动拼接 WHERE 关键字拼接上对应的条件
2,如果条件前面有 OR|AND 关键字,但是是第一个条件,那么会自动删除出这个关键字,以保证语法正确
3,如果一个条件都没有,那么就相当于查询所有数据
-->
<where>
<if test="name != '' and name != null">
name like concat('%', #{name}, '%')
</if>
<if test="age != '' and age != null">
and age = #{age}
</if>
<if test="email != '' and email != null">
and email = #{email}
</if>
<if test="password != '' and password != null">
and password = #{password}
</if>
</where>
<!--
另一种写法是使用trim标签:
<trim>标签,开发者可以自定义条件,既可以指定where条件也可以指定set关键字条件
<trim prefix="WHERE" prefixOverrides="AND | OR">
prefix : 前缀,
当前如果是条件就用 WERHE
如果使用修改就用 SET
prefixOverrides :在 WHERE 关键字后面的第一个条件,如果是 AND|OR 会自动去掉
-->
<!--<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="name != '' and name != null">
name like concat('%', #{name}, '%')
</if>
<if test="age != '' and name != null">
and age = #{age}
</if>
<if test="email != '' and email != null">
and email = #{email}
</if>
<if test="password != '' and password != null">
and password = #{password}
</if>
</trim>-->
</sql>
<update id="updateUserByNotNull" parameterType="User">
<!--
update tb_user set name = #{name}, password= #{password}, age = #{age} where id = #{id}
上述SQL语句的语义来说,是一个静态SQL语句,一开始已经确定SQL的语义
不管有没有数据,都会对全部数据进行修改,如果某一个数据没有,name会自动设置为null
不符合实际场景
解决方案: 使用MyBatis的动态SQL语句,<set>标签、<trim>标签
-->
<!-- set标签会自动的过滤掉多余的逗号 -->
<!--update tb_user
<set>
<if test="name != '' and name != null">name = #{name},</if>
<if test="age != '' and age != null">age = #{age},</if>
<if test="email != '' and email != null">email = #{email},</if>
<if test="password != '' and password != null">password = #{password}</if>
</set>
where id = #{id}-->
<!--
prefix : 前缀,
当前如果是 条件就用 WERHE
如果使用修改 就用 SET
prefixOverrides :如果在 WHRE 关子健 后面的第一个条件,如果是 AND|OR 会自动去掉
suffixOverrides :如果是最后一个条件, 如果是多余的逗号(,) 会自动去掉
-->
update tb_user
<trim prefix="SET" suffixOverrides=",">
<if test="name != '' and name != null">name = #{name},</if>
<if test="age != '' and age != null">age = #{age},</if>
<if test="email != '' and email != null">email = #{email},</if>
<if test="password != '' and password != null">password = #{password}</if>
</trim>
where id = #{id}
</update>
<delete id="deleteByIds" parameterType="List">
<!-- delete from tb_user where id in (1,2,3) -->
<!--
<foreach collection="" open="" close="" item="" separator="">标签体内容</foreach>
MyBatis的for循环标签
collection:循环集合
open:起始括号(
close:结束括号 )
item:集合每次循环的数据对应的变量
separator:分割符号: (1,2,3) 数值与数值之间的分隔符 ,逗号
-->
delete from tb_user
where id in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
<insert id="insertByBatch">
insert into tb_user (name, age, email, password)
values
<foreach collection="users" item="user" separator=",">
(#{user.name}, #{user.age}, #{user.email}, #{user.password})
</foreach>
</insert>
</mapper>
1.3.4. 测试代码
@Test
1.3.5测试结果
1.4. 基于注解方式实现
动态sql除了支持xml方式以外,还支持使用纯注解的方式。
主要一下五个注解对应动态sql语句的类文件。
1. @SelectProvider 动态查询SQL语句对应注解。
2. @InsertProvider 动态插入SQL语句对应注解。
3. @UpdateProvider 动态修改SQL语句对应注解。
4. @DeleteProvider 动态删除SQL语句对应注解。
5. @Param 动态获取参数
1.4.1. 接口映射文件
package
1.4.2. 动态sql语句文件
package
1.4.3. 测试代码
同上
1.4.4. 测试结果
同上
1.4.5. SQL类拼接动态sql语句
SQL类提供的API都是用于拼接SQL语句的,每一个方法对应一个子句,换句话说SQL类拼接SQL语句的单位是子句。
查询涉及的子句:select、from、join、left join、right join、where、group by、having、
order by、or、and。
更新涉及的子句:update、set、where。
插入涉及的子句:insert、values。
删除涉及的子句:delete、where。
在SQL类中对每一种子句都提供了一个对应的API。(详见Mybatis文档)
在实际开发中,95%的数据库操作都是查询操作,所以在sql语句的练习中,应该以查询sql语句为主。
1.4.6. 静态SQL语句和动态SQL语句的区别
静态SQL语句和动态SQL语句都可以通过XML配置文件和注解的形式实现。
使用xml配置文件时,需要在mybatis-config.xml文件的mappers标签中添加一个mapper标签,resource属性为配置文件路径。
使用注解时,需要在mybatis-config.xml文件的mappers标签中添加一个mapper标签,class属性值为XXXMapper映射类的全限定名。如下:
<mappers>
<!-- xml配置文件 -->
<mapper resource="org/cjw/mapper/UserMapper.xml"/>
<!-- 配置类 -->
<mapper class="org.cjw.mapper.UserProvider"/>
</mappers>
一个接口对应一个mapper标签,在开发中可能存在几十个上百个接口,现在通过mapper标签来注册接口是不现实的,所以可以使用package标签一次性注册一个包中的所有接口。如下:
<mappers>
<!-- 配置包扫描,自动找寻xml配置文件或者注解类 -->
<package name="org.cjw.mapper" />
</mappers>
静态SQL语句编码简单,但是灵活性不足。
动态SQL语句编码稍微复杂,但是灵活性强。
xml文件通过where、set、if、trim、sql、include标签来拼接动态SQL语句。
注解通过SQL类或原生Java代码来拼接动态SQL语句。
无论xml文件还是注解拼接动态SQL语句时,都需要使用OGNL语法来拼接,即xxx = #{XXX}的形式或者#{XXX}形式,切勿直接把参数值直接拼接到动态SQL上,否则会出现运行问题。
动态SQL语法仅仅只是拼接了SQL语句,在拼接完SQL语句后可以将其看做静态SQL语句,所以静态SQL语句的规范,动态SQL语句也需要遵循,即OGNL语法。
xml文件形式的动态SQL语句的拼接在XML文件中完成。
注解形式的动态SQL语句的拼接在一个java类的方法中完成。
2. 缓存
在Mybatis里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录,从而提高查询的效率。因为将数据库表中的记录读取到内存中需要经过IO,而IO操作的效率是很低,在开发中应该尽量避免IO操作,所以衍生出缓存机制。
缓存作用:提高查询的效率。
2.1. 一级缓存
Mybatis的缓存分为一级缓存、二级缓存。
一级缓存:所谓的一级缓存就是会话(SqlSesion对象)级别的缓存,同一个会话中,如果已经查询过的记录会保存一份在内存中,如果会话没有关闭,再次调用同样的查询方法,不会再查询数据库,而是直接从缓存中取出之前查询的记录(类似get请求的缓存机制)。
一级缓存默认是打开的,而且是关闭不了的。
2.1.1. 测试代码
@Test
通过日志信息来判断是否有缓存。
由图可以得知,执行了两次selectAll方法,但是只查询了一次数据库,验证了一级缓存。
如何清空一级缓存:
1.关闭会话close()。
2.进行了DML操作,提交了事务commit()。
3.手动清除缓存clearCache()。
@Test
@Test
@Test
2.2. 二级缓存
一级缓存是SqlSession对象级别,在每一次会话中有效。
二级缓存是 SqlSessionFactory级别,在整个应用都有效,可以在多个会话有效。
MyBatis本身并没有实现二级缓存二级缓存需要第三方缓存提供商的支持:
Ehcache -第三方缓存(Hibernate框架默认就是支持)
学习地址:http://www.mybatis.org/ehcache-cache/
2.2.1. 下载ehcache
https://github.com/mybatis/ehcache-cache/releases
2.2.2. 配置开启二级缓存
MyBatis开启二级缓存,新版本已经默认支持开启二级缓存。可以不改。
添加 <setting name="logImpl" value="STDOUT_LOGGING" />开启日志的配置。
<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 开启日志 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
2.2.3. 导入Ehcache.jar包
2.2.4. Ehcache依赖 slfj 日志框架,必须要导入slfj的两个jar包
2.2.5. 基于XML配置文件的二级缓存
基于XMl配置文件的时,需要使用XML配置。
【1】创建 ehcache.xml配置文件
Ehcache有自己的配置文件,在src下面创建ehcache.xml 配置文件,如下。
<ehcache>
<!-- 缓存的磁盘位置 -->
<diskStore path="D:/mybatis_cache"/>
<!-- 默认的缓存策略: 如果开发者在某一个需要缓存的文件配置了自定义缓存,就不使用默认的,如果没有配置,就使用默认缓存策略-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
【2】在映射文件中添加<cache>标签以及配置对应的缓存策略。
2.2.6. 缓存的命中率
命中率= 从缓存中获取数据的次数/查询的总次数
如 : 两次查询 从缓存中获取一次
0.5 = 1/2;
0.666666 = 2/3;
命中率越高缓存效果越好
因为ehcache是sqlSessionFactory级别的缓存,是针对不同的会话而言的缓存,所以如果想要测试ehcache的命中率,需要不断的关闭和开启会话进而模拟多个用户访问数据库。如果在同一个会话中执行相同的SQL语句,那么使用的mybatis自带的一级缓存,仅仅只对当前会话有效,所以会出现二级缓存的命中率一直为0.0,因为使用的一直是一级缓存。
如下:
@Test
测试结果:
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.0
Opening JDBC Connection
Created connection 1472465.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1677d1]
==> Preparing: select * from tb_user WHERE name like concat('%', ?, '%')
==> Parameters: 张(String)
<== Columns: id, name, age, email, password
<== Row: 1, 张三, 13, zhangsan@126.com, zhangsan123123
<== Row: 2, 张四, 14, zhangsi@163.com, zhangsi123123
<== Row: 3, 张五, 15, zhangwu@qq.com, zhangwu123123
<== Total: 3
DEBUG [main] - put added 0 on heap
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1677d1]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1677d1]
Returned connection 1472465 to pool.
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.5
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.6666666666666666
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.75
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.8
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.8333333333333334
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.8571428571428571
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.875
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.8888888888888888
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.9
从另外一方面来看,用户的每一个查询数据库的操作,都会首先经过二级缓存,如果二级缓存中没有对应的查询结果,那么就查询数据库,并将查询的记录通过一级缓存存储起来,如果还设置了二级缓存,那么也会往二级缓存中存储一份。
2.2.7. 基于注解的二级缓存
基于注解配置时,需要使用配置类。
在映射接口上打上@CacheNamespace(blocking = true)
package
2.2.8. 缓存命中率
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.0
Opening JDBC Connection
Created connection 84739718.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@50d0686]
==> Preparing: select * from tb_user where 1 = 1 and name like concat('%', ?,'%')
==> Parameters: 张(String)
<== Columns: id, name, age, email, password
<== Row: 1, 张三, 13, zhangsan@126.com, zhangsan123123
<== Row: 2, 张四, 14, zhangsi@163.com, zhangsi123123
<== Row: 3, 张五, 15, zhangwu@qq.com, zhangwu123123
<== Total: 3
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@50d0686]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@50d0686]
Returned connection 84739718 to pool.
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.5
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.6666666666666666
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.75
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.8
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.8333333333333334
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.8571428571428571
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.875
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.8888888888888888
Cache Hit Ratio [org.cjw.mapper.UserMapper]: 0.9
3. MyBatis的对象关系映射(难点重点)
在实际开发中,一个业务可能可能需要查询多个数据表,而多表查询就涉及连接查询(等值连接)。
等值连接:表与表之间有一个外键关联。
我们都知道一个表对应一个POJO对象,但是对象与对象之间是没有外键关系的,对象和对象之间只有依赖关系。
对象之间关系主要是四种
3.1. 准备多表,表之间有外键关系(员工表和部门表)
员工表
CREATE TABLE `employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`dept_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
部门表
CREATE TABLE `department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
3.2. 基于XML配置的关系映射
3.2.1. 多对一查询
一对一查询是多对一查询的特例,使用同一套代码。
3.2.1.1. N+1方式
N+1 : N 就是当前需要查询结果对应发送的SQL语句的条数
+1 关联查询数据需要额外多发一条SQL语句才能查询出对应的结果
3.2.1.1.1. POJO
package
3.2.1.1.2. 映射接口
package
3.2.1.1.3. 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.cjw.mapper.EmployeeMapper">
<!-- 查询主表一条sql -->
<select id="selectEmployeeByPrimaryKey" resultMap="emp_map">
select * from employee where id = #{emp_id}
</select>
<resultMap id="emp_map" type="Employee">
<id property="id" column="id"/>
<result property="name" column="name" />
<!--
association标签的作用:将主表某一列的值作为查询条件查询副表,并将查询结果封装成对象返回
properties属性:最后映射的对象名
column属性:副表查询条件
-->
<association property="dept" column="dept_id" select="org.cjw.mapper.EmployeeMapper.selectDeptById" />
</resultMap>
<!-- 查询副表N条sql -->
<select id="selectDeptById" resultType="Department">
select * from department where id = #{dept_id}
</select>
</mapper>
3.2.1.1.4. 测试代码
@Test
3.2.1.1.5. 测试结果
姓名:张三, 部门:销售部
3.2.1.2. 等值连接查询
3.2.1.2.1. 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.cjw.mapper.EmployeeMapper">
<!-- 查询主表一条sql -->
<select id="selectEmployeeByPrimaryKey" resultMap="emp_map">
select e.id e_id, e.name e_name, d.id d_id, d.name d_name from employee e left join department d on e.dept_id = d.id where e.id = #{emp_id}
</select>
<resultMap id="emp_map" type="Employee">
<id property="id" column="e_id"/>
<result property="name" column="e_name" />
<collection property="dept" ofType="Department">
<id property="id" column="d_id" />
<result property="name" column="d_name" />
</collection>
</resultMap>
</mapper>
3.2.1.2.2. 测试结果
姓名:张三, 部门:销售部
当<collection>标签需要映射的记录只有一条时,默认映射为泛型类型的对象,而不是一个集合。
3.2.2. 一对多查询
一对一查询是一对多查询的特例,使用同一套代码。
3.2.2.1. N+1方式
3.2.2.1.1. POJO
package
3.2.2.1.2. 映射接口
package
3.2.2.1.3. 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.cjw.mapper.DepartmentMapper">
<!-- 查询主表一条sql -->
<select id="selectDeptById" resultMap="dept_map">
select * from department where id = #{dept_id}
</select>
<resultMap id="dept_map" type="Department">
<id property="id" column="id"/>
<result property="name" column="name" />
<!--
association标签:用于将主表查询结果的某列数据值作为查询副表的查询条件
properties属性:需要映射的对象/集合
column属性:查询条件值
select属性:执行的查询语句
-->
<association property="emps" column="id" select="org.cjw.mapper.DepartmentMapper.selectEmpsByDeptId" />
</resultMap>
<select id="selectEmpsByDeptId" resultType="Employee">
select * from employee where dept_id = #{id}
</select>
</mapper>
3.2.2.1.4. 测试代码
@Test
3.2.2.1.5. 测试结果
张三
李四
3.2.2.2. 等值连接查询
3.2.2.2.1. 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.cjw.mapper.DepartmentMapper">
<!-- 查询主表一条sql -->
<select id="selectDeptById" resultMap="dept_map">
select d.id d_id, d.name d_name, e.id e_id, e.name e_name from department d left join employee e on d.id = e.dept_id where d.id = #{dept_id}
</select>
<resultMap id="dept_map" type="Department">
<id property="id" column="d_id"/>
<result property="name" column="d_name" />
<collection property="emps" column="id" ofType="Employee">
<id property="id" column="e_id"/>
<result property="name" column="e_name" />
<result property="deptId" column="d_id" />
</collection>
</resultMap>
</mapper>
3.2.2.2.2. 测试结果
张三
李四
3.3. 基于注解配置的关系映射
3.3.1. 多对一查询
3.3.1.1. N+1方式
3.3.1.1.1. POJO
package
3.3.1.1.2. 映射接口+注解配置
package
3.3.1.1.3. 测试代码
@Test
3.3.1.1.4. 测试结果
姓名:张三,部门:销售部
3.3.1.2. 等值连接查询
连接查询暂时未发现解决方案,有知道的朋友可以评论留言告诉我。
3.3.2. 一对多查询
3.3.2.0.1. POJO
package
3.3.2.0.2. 映射接口+注解配置
package
3.3.2.0.3. 测试代码
@Test
3.3.2.0.4. 测试结果
部门:销售部,雇员名:张三
部门:销售部,雇员名:李四
3.3.2.1. 等值连接查询
同上,有知道的小伙伴可以留言给我。
3.4. 对象管理映射个人理解
在开发中,一般pojo中的常见属性除了基本类型、包装类型、String之外,还可能出现对象属性、集合属性,对于基本、包装、String类型,可以直接进行映射,但是对象属性、集合属性并不能,因为内部还需要再指定字段和属性的映射关系。换言之,对象属性、集合属性本身就需要指定映射关系,而其又属于一个pojo对象,这个pojo对象本身也需要指定映射关系,因此对于存在pojo对象属性和集合类型属性的pojo对象的映射,咱们需要使用N+1策略或者等值连接策略。
N+1策略则是先把所有pojo对象查询出来,然后再根据外键字段去查询对象属性或者集合属性,使用association标签(property、column、select标签属性)。
等值连接策略则是通过连表查询,将pojo对象的属性相关信息都查询出来,然后在内存中根据指定的映射关系将字段值赋值到属性上,对于pojo对象属性和集合类型属性,使用collection标签(property、ofType属性)来指定字段值和其属性的映射关系。
N+1策略操作数据库次数为记录数+1次,等值连接策略操作数据库次数为1次。
4. MyBatis的逆向工程
MyBatis的逆向工程能自动帮开发者生成数据库表对应的pojo实体文件,自动生成映射文件
自动生成表的各种(CRUD)的sql语句,但是只能做单表操作,联合查询还得开发者自己改造。
使用逆向工程得先在Eclipse安装逆向工程的插件。
4.1. 插件安装步骤
判断是否安装成功
4.2. eclipse逆向工程步骤
4.2.1. 新建一个普通java项目,导入mybatis.jar包和数据库驱动包
4.2.2. 配置生成文件
配置生成文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="context1">
<!-- 注释构建 -->
<commentGenerator>
<!-- 去掉所有的注释 -->
<property name="suppressAllComments" value="true"/>
<property name="suppressDate" value="true"/>
</commentGenerator>
<!-- 数据库四要素 -->
<jdbcConnection connectionURL="jdbc:mysql://localhost:3306/mybatis"
driverClass="com.mysql.jdbc.Driver"
password="root"
userId="root" />
<!-- 实体类 : pojo
targetPackage : 实体类生成后存放的包
targetProject : 存放的目录一般都放在 src下面
-->
<javaModelGenerator targetPackage="cn.zj.mybatis.pojo" targetProject="mybatis-generator/src" />
<!-- 映射文件 -->
<sqlMapGenerator targetPackage="cn.zj.mybatis.mapper" targetProject="mybatis-generator/src" />
<!-- 操作接口
type 生成映射的形式
ANNOTATEDMAPPER : 纯注解的,没有xml映射
XMLMAPPER : 生成的有xml映射文件
-->
<javaClientGenerator targetPackage="cn.zj.mybatis.mapper" targetProject="mybatis-generator/src" type="XMLMAPPER" />
<!-- 要生成对应表的配置
tableName : 数据库表名
//如果下面全部是true,mybatis直接可以使用纯面向对象开发
enableCountByExample : 是否生成查询总数的 Example
enableDeleteByExample : 是否生成删除的 Example
enableSelectByExample : 是否生成查询集合的 Example
enableUpdateByExample : 是否生成修改的 Example
-->
<table tableName="user" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
<table tableName="employee" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
<table tableName="department" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
</context>
</generatorConfiguration>
4.2.3. 开始逆向工程
选中 generatorConfig.xml 逆向工程配置文件,点击鼠标右键。
4.3. idea的逆向工程步骤(基于maven)
4.3.1. 新建一个maven项目,依赖引入mybatis、mysql-connector-java、以及mybatis-generator-maven-plugin插件
<
4.3.2. 编写generatorConfig.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 配置驱动包的位置 -->
<classPathEntry
location="C:UsersJackMi.m2repositorymysqlmysql-connector-java5.1.38mysql-connector-java-5.1.38.jar" />
<context id="context1">
<!-- 注释构建 -->
<commentGenerator>
<!-- 去掉所有的注释 -->
<property name="suppressAllComments" value="true"/>
<property name="suppressDate" value="true"/>
</commentGenerator>
<!-- 数据库四要素 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="root"/>
<!-- 实体类 : pojo
targetPackage : 实体类生成后存放的包
targetProject : 存放的目录一般都放在 src下面
-->
<javaModelGenerator targetPackage="com.jackmi.pojo" targetProject="src/main/java"/>
<!-- 映射文件 -->
<sqlMapGenerator targetPackage="com.jackmi.mapper" targetProject="src/main/java"/>
<!-- 操作接口
type 生成映射的形式
ANNOTATEDMAPPER : 纯注解的,没有xml映射
XMLMAPPER : 生成的有xml映射文件
-->
<javaClientGenerator targetPackage="com.jackmi.mapper" targetProject="src/main/java"
type="XMLMAPPER"/>
<!-- 要生成对应表的配置
tableName : 数据库表名
domainObjectName:生成的pojo对象的名字
// 如果下面全部是true,mybatis直接可以使用纯面向对象开发
enableCountByExample : 是否生成查询总数的 Example
enableDeleteByExample : 是否生成删除的 Example
enableSelectByExample : 是否生成查询集合的 Example
enableUpdateByExample : 是否生成修改的 Example
-->
<table tableName="user" domainObjectName="User" enableCountByExample="false" enableDeleteByExample="false"
enableSelectByExample="true" enableUpdateByExample="false"></table>
<table tableName="employee" domainObjectName="Employee" enableCountByExample="false"
enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
<table tableName="department" domainObjectName="Department" enableCountByExample="false"
enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
</context>
</generatorConfiguration>
4.3.3. 双击mabatis-generator:generate插件
4.4. 逆向功能的缺点
逆向功能不能逆向多表,只能逆向单表操作,多表之间有外键对应java关联关系没办法映射,需要开发者手动编写对应代码。