zoukankan      html  css  js  c++  java
  • Mybatis框架---概述(2)

    MyBatis

    1. 动态SQL语句

    1.1. 动态SQL是什么

    就是相对与固定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>:类似javaforeach循环,一般用户批量处理的SQL语句

    <trim> :切割标签,主要用于切割关键字的头和尾的字符.新版的Mybatis使用的几率很少.

    <set>:使用 set标签就是SQL语言的set关键字,可以在update 的时候set 关键字后面的,逗号可以自动忽略

    <where>:使用where标签作为SQL语言的where关键字,好处如果where后面的条件都不成立,忽略where关键字.

    <choose> <when> <otherwise> :  javaswithc case

    1.3.2. 接口文件

    package cn.zj.mybatis.mapper;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    
    import cn.zj.mybatis.pojo.User;
    
    public interface UserMapper {
        
        /**
         * 根据条件查询结果
         * @param user
         * @return
         */
        List<User> selectByCondition(User user);
        
        /**
         * 根据提交查询总数
         * @param user
         * @return
         */
        Long selectTotalByCondition(User user);
        
        /**
         * 修改用户
         * @param user
         * @return
         */
        int updateUserByNotNull(User user);
        
        /**
         * 批量删除用户
         * @param ids
         * @return
         */
        int deleteByIds(@Param("ids")Integer[] ids);
        
        /**
         * 批量插入
         * @param users
         * @return
         */
        int insertByBatch(@Param("users")List<User> users);
        
    }

    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 配置 mybatis 表的映射
        namespache :命名空间(和对应映射的接口的 全限定名一样),通俗讲,当前映射文件的唯一标识
            全限定名 : 包名+接口名/类名
     --> 
    <mapper namespace="cn.zj.mybatis.mapper.UserMapper">
    
        
        <!-- sql片段 -->
        <sql id="condition_sql">
            <!-- where 标签 -->
            <where>
                <if test="name !=null">
                    name like  concat('%',#{name},'%')
                </if>
                <if test="password !=null">
                    and password = #{password}
                </if>
                <if test="age !=null">
                    and age = #{age}
                </if>
            </where>
            
        </sql>
        
        <!-- 多条件查询 -->
        <select id="selectByCondition" parameterType="cn.zj.mybatis.pojo.User" resultType="cn.zj.mybatis.pojo.User">
            select * from user 
            <!-- 引入sql片段 -->
            <include refid="condition_sql"/>
        </select>
        
        <!-- 多条件查询总数 -->
        <select id="selectTotalByCondition" parameterType="cn.zj.mybatis.pojo.User" resultType="long">
            select count(*) from user 
            <!-- where 标签 -->
            <include refid="condition_sql"/>
        </select>
        
        <!-- 修改用户信息(数据不为空的修改) -->
        <update id="updateUserByNotNull" parameterType="cn.zj.mybatis.pojo.User">
            update user 
            <set>
                <if test="name !=null">
                    name = #{name},
                </if>
                <if test="password !=null">
                    password = #{password},
                </if>
                <if test="age !=null">
                    age = #{age},
                </if>
            </set>
            where id = #{id}
        </update>
        
        <!-- 批量删除 -->
        <delete id="deleteByIds" parameterType="integer">
            <!-- sql : delete from user where id in (1,2,3,4) -->
            delete from user where id in 
            
            <!-- 动态sql语句值 foreach -->
            
            <foreach collection="ids" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </delete>
        
        <!-- 批量插入 -->    
        <delete id="insertByBatch" parameterType="list">
            <!-- insert into user (name,password,age) values (xx,xx,xx),(xx1,xx1,xx1) -->
            
            insert into user (name,password,age) values
            
            <foreach collection="users" item="user" separator="," >
                (#{user.name},#{user.password},#{user.age})
            </foreach>
        </delete>
    </mapper>

    1.3.4. 测试代码

      1 package cn.zj.mybatis.test;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 import org.apache.ibatis.session.SqlSession;
      7 import org.junit.Test;
      8 
      9 import cn.zj.mybatis.mapper.UserMapper;
     10 import cn.zj.mybatis.pojo.User;
     11 import cn.zj.mybatis.util.MyBatisUtil;
     12 
     13 public class UserMapperTest {
     14 
     15     @Test
     16     public void testSelectByCondition() throws Exception {
     17         // 1.创建SqlSession对象
     18         SqlSession session = MyBatisUtil.openSession();
     19 
     20         // 2.创建UserMapper接口的代理对象
     21         UserMapper userMapper = session.getMapper(UserMapper.class);
     22 
     23         User user = new User();
     24         // user.setAge(30);
     25         user.setName("哥");
     26         List<User> users = userMapper.selectByCondition(user);
     27         for (User user2 : users) {
     28             System.out.println(user2);
     29         }
     30         
     31         Long totalCount = userMapper.selectTotalByCondition(user);
     32         System.out.println(totalCount);
     33         
     34         //关闭sesison
     35         session.close();
     36     }
     37 
     38     @Test
     39     public void testInsert() throws Exception {
     40 
     41         // 1.创建SqlSession对象
     42         SqlSession session = MyBatisUtil.openSession();
     43 
     44         // 2.创建UserMapper接口的代理对象
     45         UserMapper userMapper = session.getMapper(UserMapper.class);
     46         User user1 = new User(null, "西门吹雪", "xmcx", 25);
     47         User user2 = new User(null, "东方不败", "dfbb", 30);
     48 
     49         List<User> users = new ArrayList<>();
     50         
     51         users.add(user1);
     52         users.add(user2);
     53         // 3. 执行UserMapper的批量插入方法
     54         int row = userMapper.insertByBatch(users);
     55         System.out.println(row);
     56         
     57         
     58         // 4.提交事务(MyBatis是手动提交事务)
     59         session.commit();
     60 
     61         // 5.关闭Session
     62         session.close();
     63     }
     64 
     65 
     66     @Test
     67     public void testUpdate() throws Exception {
     68         // 1.创建SqlSession对象
     69         SqlSession session = MyBatisUtil.openSession();
     70         // 2.创建UserMapper接口的代理对象
     71         UserMapper userMapper = session.getMapper(UserMapper.class);
     72 
     73         User user = new User(1, null, "xf", null);
     74         // 3.执行修改方法
     75         int row = userMapper.updateUserByNotNull(user);
     76         System.out.println(row);
     77         // 4.提交事务
     78         session.commit();
     79 
     80         // 5.关闭session
     81         session.close();
     82     }
     83 
     84     @Test
     85     public void testDelete() throws Exception {
     86         // 1.创建SqlSession对象
     87         SqlSession session = MyBatisUtil.openSession();
     88         // 2.创建UserMapper接口的代理对象
     89         UserMapper userMapper = session.getMapper(UserMapper.class);
     90 
     91         Integer[] ids = { 2, 3, 5 };
     92 
     93         // 3.执行修改方法
     94         int row = userMapper.deleteByIds(ids);
     95         System.out.println(row);
     96         // 4.提交事务
     97         session.commit();
     98 
     99         // 5.关闭session
    100         session.close();
    101     }
    102 
    103 }

    1.4. 基于注解方式实现

    动态sql除了支持xml方式以外,还是支持使用纯注解的方式

    主要一下四个注解+对应动态sql语句的类文件

    1. @SelectProvider  动态查询SQL语句对应注解
    2. @InsertProvider  动态插入SQL语句对应注解
    3. @UpdateProvider  动态修改SQL语句对应注解
    4. @DeleteProvider  动态删除SQL语句对应注解

     

    1.4.1 接口映射文件

     1 package cn.zj.mybatis.mapper;
     2 
     3 import java.util.List;
     4 
     5 import org.apache.ibatis.annotations.DeleteProvider;
     6 import org.apache.ibatis.annotations.InsertProvider;
     7 import org.apache.ibatis.annotations.Param;
     8 import org.apache.ibatis.annotations.SelectProvider;
     9 import org.apache.ibatis.annotations.UpdateProvider;
    10 
    11 import cn.zj.mybatis.pojo.User;
    12 import cn.zj.mybatis.pojo.UserProvider;
    13 
    14 public interface UserMapper {
    15     
    16     
    17     /*
    18      * @SelectProvider(type=UserProvider.class,method="")
    19      * @SelectProvider 查询动态sql语句的 注解
    20      * type : 编写动态sql语句的类对应的字节码
    21      * method : 编写动态sql语句类对应的方法名称
    22      *     此方法返回的是一个String字符串,字符串就是拼接sql语句
    23      */
    24     @SelectProvider(type=UserProvider.class,method="selectByCondition")
    25     List<User> selectByCondition(User user);
    26     
    27     /**
    28      * 根据条件查询总数
    29      * @param user
    30      * @return
    31      */
    32     @SelectProvider(type=UserProvider.class,method="selectTotalByCondition")
    33     Long selectTotalByCondition(User user);
    34     
    35     
    36     /**
    37      * 修改用户信息,参数不为空的数据才会修改
    38      * @param user
    39      * @return
    40      */
    41     @UpdateProvider(type=UserProvider.class,method="updateByNotNull")
    42     int updateByNotNull(User user);
    43     
    44     
    45     /**
    46      * 批量删除
    47      * @param ids
    48      * @return
    49      */
    50     @DeleteProvider(type=UserProvider.class,method="deleteByIds")
    51     int deleteByIds(@Param("ids")List<Integer> ids);
    52     
    53     /**
    54      * 批量插入
    55      * @param users
    56      * @return
    57      */
    58     @InsertProvider(type=UserProvider.class,method="batchInsert")
    59     int batchInsert(@Param("users")List<User> users);
    60 }

    1.4.2. 动态sql语句文件

      1 package cn.zj.mybatis.pojo;
      2 
      3 import java.util.List;
      4 
      5 import org.apache.ibatis.annotations.Param;
      6 
      7 /*
      8  * UserMapper接口映射对应的动态SQL语句的的类
      9  */
     10 public class UserProvider {
     11     
     12     /**
     13      * 返回条件查询对应的动态sql语句
     14      * @param user  条件参数
     15      * @return sql
     16      */
     17     public String selectByCondition(User user) {
     18         StringBuilder sb = new StringBuilder();
     19         sb.append("select * from user WHERE 1 = 1 ");
     20         //动态拼接SQL语句
     21         if(user.getName() !=null) {
     22             //使用OGNL表达式获取 对象属性的值
     23             sb.append("AND name like  concat('%',#{name},'%')");
     24         }
     25         if(user.getAge() !=null) {
     26             sb.append("AND age = #{age}");
     27         }
     28         
     29         return sb.toString();
     30     }
     31     
     32     public String selectTotalByCondition(User user) {
     33         StringBuilder sb = new StringBuilder();
     34         sb.append("select count(1) from user WHERE 1 = 1 ");
     35         //动态拼接SQL语句
     36         if(user.getName() !=null) {
     37             //使用OGNL表达式获取 对象属性的值
     38             sb.append("AND name like  concat('%',#{name},'%')");
     39         }
     40         if(user.getAge() !=null) {
     41             sb.append("AND age = #{age}");
     42         }
     43         
     44         return sb.toString();
     45     }
     46     
     47     
     48     
     49     public String updateByNotNull(User user) {
     50         StringBuilder sb = new StringBuilder();
     51         sb.append("update user set ");
     52         
     53         if(user.getName() !=null) {
     54             sb.append("name = #{name},");
     55         }
     56         if(user.getPassword() !=null) {
     57             sb.append("password = #{password},");
     58         }
     59         if(user.getAge() !=null) {
     60             sb.append("age = #{age},");
     61         }
     62         //删除最后一个多余的逗号
     63         sb.deleteCharAt(sb.length()-1);
     64         
     65         sb.append(" where id = #{id}");
     66         
     67         return sb.toString();
     68     }
     69     
     70     
     71     public String deleteByIds(@Param("ids")List<Integer> ids) {
     72         StringBuilder sb = new StringBuilder();
     73         //delete from user where id in (1,3,5,6);
     74         sb.append("delete from user where id in (");
     75         
     76         for (int i = 0; i < ids.size(); i++) {
     77             //使用OGNL 表达式获取集合的每一个数据  #{ids[0]} #{ids[1]} #{ids[2]}...
     78             sb.append("#{ids["+i+"]},");
     79         }
     80         
     81         //删除最后一个多余的逗号
     82         sb.deleteCharAt(sb.length()-1);
     83         
     84         sb.append(")");
     85         return sb.toString();
     86     }
     87     
     88     public String batchInsert(@Param("users")List<User> users) {
     89         StringBuilder sb = new StringBuilder();
     90 //        insert into user (name,password,age) values
     91 //            (xxx,x,xx),(xxx1,x1,xx1),(xxx2,x2,xx2),
     92         sb.append("insert into user (name,password,age) values ");
     93         
     94         for (int i = 0; i < users.size(); i++) {
     95             sb.append("(");
     96             //姓名
     97             sb.append("#{users["+i+"].name},");
     98             //密码
     99             sb.append("#{users["+i+"].password},");
    100             //年龄
    101             sb.append("#{users["+i+"].age}");
    102             sb.append("),");
    103         }
    104         //删除最后一个多余的逗号
    105         sb.deleteCharAt(sb.length()-1);
    106         System.out.println("SQL :"+sb.toString());
    107         return sb.toString();
    108     }
    109 }

    1.4.3. 测试代码

      1 package cn.zj.mybatis.test;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 import org.apache.ibatis.session.SqlSession;
      7 import org.junit.Test;
      8 
      9 import cn.zj.mybatis.mapper.UserMapper;
     10 import cn.zj.mybatis.pojo.User;
     11 import cn.zj.mybatis.util.MyBatisUtil;
     12 
     13 public class UserMapperTest {
     14 
     15     @Test
     16     public void testSelectByCondition() throws Exception {
     17         // 1.创建SqlSession对象
     18         SqlSession session = MyBatisUtil.openSession();
     19 
     20         // 2.创建UserMapper接口的代理对象
     21         UserMapper userMapper = session.getMapper(UserMapper.class);
     22 
     23         User user = new User();
     24         // user.setAge(30);
     25         user.setName("哥");
     26         List<User> users = userMapper.selectByCondition(user);
     27         for (User user2 : users) {
     28             System.out.println(user2);
     29         }
     30 // 查询总数
     31         Long totalCount = userMapper.selectTotalByCondition(conditionUser);
     32         System.out.println("totalCount:" + totalCount);
     33         // 关闭session
     34         session.close();
     35     }
     36 
     37     @Test
     38     public void testInsert() throws Exception {
     39 
     40         // 1.创建SqlSession对象
     41         SqlSession session = MyBatisUtil.openSession();
     42 
     43         // 2.创建UserMapper接口的代理对象
     44         UserMapper userMapper = session.getMapper(UserMapper.class);
     45         User user1 = new User(null, "西门吹雪", "xmcx", 25);
     46         User user2 = new User(null, "东方不败", "dfbb", 30);
     47 
     48         List<User> users = new ArrayList<>();
     49         
     50         users.add(user1);
     51         users.add(user2);
     52         // 3. 执行UserMapper的批量插入方法
     53         int row = userMapper.insertByBatch(users);
     54         System.out.println(row);
     55         
     56         
     57         // 4.提交事务(MyBatis是手动提交事务)
     58         session.commit();
     59 
     60         // 5.关闭Session
     61         session.close();
     62     }
     63 
     64     @Test
     65     public void testUpdate() throws Exception {
     66         // 1.创建SqlSession对象
     67         SqlSession session = MyBatisUtil.openSession();
     68         // 2.创建UserMapper接口的代理对象
     69         UserMapper userMapper = session.getMapper(UserMapper.class);
     70 
     71         User user = new User(5, null, "xf", null);
     72         // 3.执行修改方法
     73         int row = userMapper.updateUserByNotNull(user);
     74         System.out.println(row);
     75         // 4.提交事务
     76         session.commit();
     77 
     78         // 5.关闭session
     79         session.close();
     80     }
     81 
     82     @Test
     83     public void testDelete() throws Exception {
     84         // 1.创建SqlSession对象
     85         SqlSession session = MyBatisUtil.openSession();
     86         // 2.创建UserMapper接口的代理对象
     87         UserMapper userMapper = session.getMapper(UserMapper.class);
     88 
     89         Integer[] ids = { 2, 3, 5 };
     90 
     91         // 3.执行修改方法
     92         int row = userMapper.deleteByIds(ids);
     93         System.out.println(row);
     94         // 4.提交事务
     95         session.commit();
     96 
     97         // 5.关闭session
     98         session.close();
     99     }
    100 }

    2. 缓存

    Mybatis里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录.从而提高查询的效率.

    缓存作用

    提高查询的效率.

    2.1. 一级缓存

    Mybatis的缓存分为一级缓存 二级缓存

    一级缓存:所谓的一级缓存就是会话(SqlSesion对象)级别的缓存,就是同一个会话,如果已经查询过的数据会保存一份在内存中,如果会话没有关闭,再次调用同样的方法查询,不会再查询数据库,而是直接从缓存中取出之前查询的数据.

    一级缓存默认是打开的,而且是关闭不了的.

    如何清空一级缓存.

    1.关闭会话.close()

    2.进行了操作(增删改),提交了commit();

    3.手工清除缓存clearCache()

    2.1.1. 测试代码

     1 @Test
     2 public void testselectAll() {
     3     // 1.创建SqlSession对象
     4     //SqlSesion对象默认就开启了一级缓存,将已经查询过的数据就缓存到SqlSession的缓存区域
     5     //在此会话中如果再次发送同样的请求,那么直接从缓存区域获取数据,不会再发送SQL语句了
     6     
     7     SqlSession session1 = MyBatisUtil.openSession();
     8     //SqlSession session2 = MyBatisUtil.openSession();
     9     // 2.创建UserMapper接口的代理对象
    10     UserMapper mapper1 = session1.getMapper(UserMapper.class);
    11     
    12     //UserMapper mapper2 = session2.getMapper(UserMapper.class);
    13     //3.执行查询方法
    14     List<User> users1 = mapper1.selectAll();
    15     
    16     //手动清理缓存
    17     session1.clearCache();
    18     
    19     List<User> users2 = mapper1.selectAll();
    20 }

    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开启二级缓存新版本已经默认支持开启二级缓存.可以不改

    1 <settings>
    2     <!-- 开启二级缓存 -->
    3     <setting name="cacheEnabled" value="true"/>
    4 </settings>

    1.1.1. 导入Ehcachejar

     

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

     

    1.1.3. 创建 ehcache.xml配置文件

    Ehcache有自己的配置文件,src下面创建ehcache.xml 配置文件

    <ehcache>
    
    <!-- 缓存的磁盘位置 -->
    
    <diskStore path="D:/mybatis_cache"/>
    
    <!-- 默认的缓存策略: 如果开发者在某一个需要缓存的文件配置了自定义缓存,就不使用默认的,如果没有配置,就使用默认缓存策略-->
    
        <defaultCache
    
            maxElementsInMemory="10000"
    
            eternal="false"
    
            timeToIdleSeconds="120"
    
            timeToLiveSeconds="120"
    
            overflowToDisk="true"
    
          />
    
    </ehcache>

    在映射文件中配置<cache>以及配置对应的缓存策略

    <mapper namespace="cn.zj.mybatis.dao.UserMapper">
    
    <!-- 当前表的映射开启支持二级缓存,并设置相关的缓存提供商,以及缓存的相关配置 -->
    
    <cache type="org.mybatis.caches.ehcache.EhcacheCache" >
    
           <!--最大的空闲时间  -->
    
           <property name="timeToIdleSeconds" value="10000"/>
    
           <!-- 最大的在线时间 -->
    
           <property name="timeToLiveSeconds" value="20000"/>
    
           <!-- 内存的大小 b字节 m1 =1024k 1k=1024b -->
    
           <property name="maxEntriesLocalHeap" value="2000000"/>
    
           <!-- 文件的大小 b字节-->
    
           <property name="maxEntriesLocalDisk" value="20000000"/>
    
           <!-- 算法 LRU:最少使用优先, "LFU" or "FIFO:先进先出 -->
    
           <property name="memoryStoreEvictionPolicy" value="LRU"/>
    
        </cache>
    
    <select id="selectAll" resultType="User">
    
    select * from user
    
    </select>
    
    </mapper>

    1.1.4. 缓存的命中率因为二级缓存可以缓存到文件(将对象序列化到本地),涉及到对象序列化,那么对应的javaBean对象就必须实现

    public class User implements Serializable{
    
    private static final long serialVersionUID = -8366151150155170110L;
    
    }
    命中率= 从缓存中获取数据的次数/ 查询的总次数
    
    如 : 两次查询 从缓中获取一次
    
    0.5 =  1/2;
    
    0.666666 = 2/3;
    
    命中率越高缓存效果越好
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.0
    
    DEBUG [main] - ==>  Preparing: select * from user where id = ?
    
    DEBUG [main] - ==> Parameters: 3(Integer)
    
    DEBUG [main] - <==      Total: 1
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.5
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.6666666666666666
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.75
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8333333333333334
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8571428571428571
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.875
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8888888888888888
    
    DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.9
    在实际开发中,一个业务可能涉及到多个数据表的查询,那么多表查询就涉及连接查询(等值连接), 等值连接 表与表之间有一个外键关键
    
     
    
    但是程序中最终获取的表封装的对象, 对象与对象之间是没有外键关系的,对象和对象之间只有依赖关系
    
     
    
    对象之间关系主要是四种
    
     
    
    一对一 关系
    一个人对应身份证id,一个QQ号对应一个QQ空间
    
    一对多 关系
    
        一个部门对应多个员工
    
    多对一 关系
    
       多个员工对应一个部门
    
    多对多 关系
    
       多个学生对应多个老师,多个学生对应多个课程
    
    什么关系应该从哪个对象作为中心点来看
    
    一对多, 以one方作为中心点
    
     
    
    MyBatis框架支持多表查询封装对象之间关系
    
     
    
    <collection> 一对多查询
    
    <association>多对一和一对一查询
    
     

    2.1. 准备多表,表之间有外键关系(员工表和部门表)2. MyBatis的对象关系映射(难点重点)

    员工表

    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;

    2.2. 多对一查询

    public class Employee {

    private Integer id;

    private String name;

    //以员工为中心 :

                          多个员工对应一个部门,多对一关系,many2one

    //员工与部门的对象关系

    private Department dept;

    public Integer getId() {

    return id;

    }

    public void setId(Integer id) {

    this.id = id;

    }

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    public Department getDept() {

    return dept;

    }

    public void setDept(Department dept) {

    this.dept = dept;

    }

    @Override

    public String toString() {

    return "Employee [id=" + id + ", name=" + name + ", dept=" + dept + "]";

    }

    }

    public class Department {

    private Integer id;

    private String name;

    public Integer getId() {

    return id;

    }

    public void setId(Integer id) {

    this.id = id;

    }

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    @Override

    public String toString() {

    return "Department [id=" + id + ", name=" + name + "]";

    }

    }

    Man2oneMapper.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">

     <!-- 映射配置

      namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称

      -->

    <mapper namespace="cn.zj.mybatis.mapper.Many2OneMapper">

    <select id="selectByEmpId" parameterType="Integer" resultMap="emp_map">

    select * from employee where id = #{id}

    </select>

    <resultMap type="cn.zj.mybatis.pojo.Employee" id="emp_map">

    <id column="id" property="id"/>

    <result column="name" property="name"/>

    <!--

        需要映射部门对象属性

    private Department dept;

       解决方案,使用关联查询

       <association property="dept" column="dept_id" select=""/>

        property :需要映射的属性

        column :要映射属性对应的外键列

        select :对应的查询方案, 对应查询的命名空间+.+功能id

     -->

    <association property="dept" column="dept_id" 

    select="cn.zj.mybatis.mapper.Many2OneMapper.findDeptById"/>

    </resultMap>

    <!-- 根据部门Id查询对应的部门对象 -->

    <select id="findDeptById" parameterType="Integer" resultType="cn.zj.mybatis.pojo.Department">

    select * from department where id = #{dept_id}

    </select>

    </mapper>

    2.3. 一对多查询

    以部门为中心查询部门的所有信息(包括员工),一个部门对应多个员工

    Pojo对象

    public class Department {

    private Integer id;

    private String name;

    //以部门为中心:一个部门对应多个与员工  一对多关系 (one2many)

    private List<Employee> emps;

    public Integer getId() {

    return id;

    }

    public void setId(Integer id) {

    this.id = id;

    }

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    public List<Employee> getEmps() {

    return emps;

    }

    public void setEmps(List<Employee> emps) {

    this.emps = emps;

    }

    @Override

    public String toString() {

    return "Department [id=" + id + ", name=" + name + ", emps=" + emps + "]";

    }

    }

    public class Employee {

    private Integer id;

    private String name;

    public Integer getId() {

    return id;

    }

    public void setId(Integer id) {

    this.id = id;

    }

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    @Override

    public String toString() {

    return "Employee [id=" + id + ", name=" + name + "]";

    }

    }

    2.3.1. N+1方式

    N+1 N 就是当前需要查询结果对应发送的SQL语句的条数

           +1 关联查询数据需要额外多发一条SQL语句才能查询出对应的结果

    2.3.1.1. 映射代码

    <?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">

     <!-- 映射配置

      namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称

      -->

    <mapper namespace="cn.zj.mybatis.mapper.One2ManyMapper">

    <select id="selectDeptById" parameterType="Integer" resultMap="dept_map">

    select * from department where id = #{id}

    </select>

    <!-- 手动映射 -->

    <resultMap type="cn.zj.mybatis.pojo.Department" id="dept_map">

    <id column="id" property="id"/>

    <result column="name" property="name"/>

    <!-- private List<Employee> emps;

    集合属性映射

     <collection property="emps" column="id" select=""/>

      property:需要映射得集合 emps

      column : 部门的主键 id

      select : 关联查询,去根据部门id查询出对应的员工

       值关联查询功能的  命名空间+.+功能id

     -->

     <collection property="emps" column="id" select="cn.zj.mybatis.mapper.One2ManyMapper.selectUsersByDeptId"/>

    </resultMap>

    <!-- 关联查询的功能

    根据部门的id查询所有的员工

     -->

    <select id="selectUsersByDeptId" parameterType="integer" resultType="cn.zj.mybatis.pojo.Employee">

    select * from employee where dept_id = #{id}

    </select>

    </mapper>

    2.3.1.2. 运行结果

     

    2.3.2. 等值连接查询

    2.3.2.1. 映射代码

    <?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">

     <!-- 映射配置

      namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称

      -->

    <mapper namespace="cn.zj.mybatis.mapper.One2ManyMapper">

    <select id="selectDeptById" parameterType="Integer" resultMap="dept_map">

    select e.id e_id ,e.name e_name,d.id d_id,d.name d_name

    from department d JOIN employee e ON d.id = e.dept_id WHERE d.id = #{id};

    </select>

    <!-- 手动映射 -->

    <resultMap type="Department" id="dept_map">

    <id column="d_id" property="id"/>

    <result column="d_name" property="name"/>

    <!-- private List<Employee> emps;

    集合属性映射

     <collection property="emps" column="id" select=""/>

      property:需要映射得集合 emps

      column : 部门的主键 id

      ofType : 需要映射集合的泛型的类型

     -->

     

     <collection property="emps" ofType="Employee">

      <!-- 集合泛型类型对应的pojo的主键列映射 ,Employee的主键列映射 -->

      <id column="e_id" property="id"/>

      <!-- 集合泛型类型对应的pojo的非主键列映射 ,Employee的非主键列映射 -->

      <result column="e_name" property="name"/>

     </collection>

    </resultMap>

    </mapper>

    2.3.2.2. 运行结果

    只会发送一条SQL语句

    DEBUG [main] - ==>  Preparing: select e.id e_id ,e.name e_name,d.id d_id,d.name d_name from department d JOIN employee e ON d.id = e.dept_id WHERE d.id = ?;

    DEBUG [main] - ==> Parameters: 1(Integer)

    DEBUG [main] - <==      Total: 2

    Department [id=1, name=总经办, emps=[Employee [id=1, name=乔峰], Employee [id=3, name=段誉]]]

    3. MyBatis的逆向工程

    MyBatis的逆向工程能自动帮开发者生成数据库表对应的 pojo实体文件,自动生成映射文件

    自定生成表的各种(CRUD)sql语句, 但是只能做单表操作,联合查询还得开发者自己动

    使用逆向工程得先在Eclipse安装逆向工程的插件

    3.1. 插件安装步骤

     

     

     

    判断是否安装成功

     

    3.2. 逆向工程步骤

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

     

    3.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="admin" 

        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>

    3.2.3. 开始逆向工程

    选中 generatorConfig.xml 逆向工程配置文件,点击鼠标右键

     

    3.3. 逆向功能的缺点

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

  • 相关阅读:
    [置顶] 当今世界最受人们重视的十大经典算法
    Android入门:调用WebService
    Android入门:实现一个File存储的辅助类
    多线程下载辅助类实现
    在Java程序中设置代理
    配置EditPlus使其可以编译运行java程序
    Android入门:文件上传
    Resource is out of sync with the file system
    【入门算法】思维导图
    sharepoint2010 重建服务器场的方法
  • 原文地址:https://www.cnblogs.com/meizhoulqp/p/11139621.html
Copyright © 2011-2022 走看看