mybatis list 对象 <foreach>_快速入门MyBatis第二天(共两天)

内容目录:

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。

5d9f5198df7f543b1d221d4227219292.png

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测试结果

38e9e69c222ac13226af028acfd69cfa.png

d735d6b85e940428e16047dec924b674.png

d465f17eea0c04e4121ae607d3002ede.png

c1b627526f7dbfd0b39707552513c281.png

9acbee75b280c9235e088b33d9dad82b.png

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

通过日志信息来判断是否有缓存。

21851b2bf439668564017faa33d9d198.png

由图可以得知,执行了两次selectAll方法,但是只查询了一次数据库,验证了一级缓存。

如何清空一级缓存:

1.关闭会话close()。

2.进行了DML操作,提交了事务commit()。

3.手动清除缓存clearCache()。

@Test

10cc452530a78891fd62d5f281780cec.png
@Test

35bbc2c9d04f614d0e05c938f95b9bf3.png
@Test

74c58d9242e83bbfe4d086422e7ce2ac.png

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包

6fdbad7dff25298f9018ce77a3149ada.png

2.2.4. Ehcache依赖 slfj 日志框架,必须要导入slfj的两个jar包

b2b2eac1eef0c2f14e50f52cb7b27b51.png

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. 插件安装步骤

fe6d62a3246d8973a6948522658f4dca.png

a10ab3558421384cc65d009a33110728.png

9c65294718ef1ea5c83cafbd48a92b01.png

判断是否安装成功

0489a5c16c6ee2df2a99b3cb9cc4cd37.png

4.2. eclipse逆向工程步骤

4.2.1. 新建一个普通java项目,导入mybatis.jar包和数据库驱动包

c42bf4a116fe79f945d11f81dda20e77.png

4.2.2. 配置生成文件

d72348409605594e1dc64280ee853416.png

配置生成文件

<?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 逆向工程配置文件,点击鼠标右键。

24174f866cf3d166104f500cfc363521.png

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插件

fec51136a02102194c7bea43632d15c8.png

687a0cbd24e0662e3fe7886e44e6f921.png

4.4. 逆向功能的缺点

逆向功能不能逆向多表,只能逆向单表操作,多表之间有外键对应java关联关系没办法映射,需要开发者手动编写对应代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值