MybatisNotes

1.mybatis简介

2.mybatis的使用

1.导入相应的依赖包

            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>


        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.6</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

2.配置mybatis配置文件,mybatis.xml文件的标签是有顺序的

<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--配置mybatis运行环境-->

    <!--启用log4j日志-->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <!--起别名-->
    <typeAliases>
        <package name="cn.ty.pojo"/>
    </typeAliases>

    <!--数据连接-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisTest? useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

     <!--注册UserMapper.xml-->
    <mappers>
        <mapper resource="cn/ty/mapper/UserMapper.xml"></mapper>
    </mappers>
</configuration>

3.编写实体类,属性与数据库列名一致

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private int age;
}

4.创建mapper接口与对应的xml文件,并将其注册到mybatis.xml文件中

    //查询全部用户信息
    List<User> queryAllUser();
}

<?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="cn.ty.mapper.UserMapper">   
      <!-- 注意这里的id要与接口的方法名相同 -->
    <select id="queryAllUser" resultType="user">   
        select *from user
    </select>

</mapper>
这条sql语句相当于原生jdbc中的
String sql = select *from user;
PreparedStatement ps = conn.prepareStatement(sql);

5.测试,SqlSession 提供了在数据库执行 SQL 命令所需的所有方法,获得SqlSession,可以将其封装成一个工具类

   //获得SqlSessionFactory对象
    private static SqlSessionFactory sqf;
    static {
       String resource = "mybatis.xml";
       InputStream ips = GetSession.class.getClassLoader().getResourceAsStream(resource);
       sqf = new SqlSessionFactoryBuilder().build(ips);
   }
    //获得SqlSession
    public static SqlSession getSession(){
        return sqf.openSession();
    }
}
使用junit进行测试
public class MybatisTest01 {
    @Test
    public void test(){
        SqlSession session = GetSession.getSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        List<User> users = userMapper.queryAllUser();
        for (User user:users) {
            System.out.println(user);
        }
    }
}

3.mapper.xml文件

  • mapper中主要用于数据库操作,对应select、delete、update、insert标签,每写完一个mapper.xml文件都要注册到mybatis.xml文件中

  • parameterType:方法参数类型 ,参数名要与实体类中一致,若不一致用@Param("属性名")来标识

    1.基本数据类型和String类型,要与接口方法参数对应
        <select id="queryByName" parameterType="String" resultType="user">
            select  *from user where name=#{name}
        </select>
    
    2.包装类Integer、Long、Double等用 parameterType="java.lang.Long" 
    3.javaBean类型
       <update id="update" parameterType="user"> 
           update user set name= #{name},age = #{age} where id = #{id}
       </update>
    
    4.若有多个参数则可省略parameterType属性,可以用arg获取参数,0表示第一个参数
       <select id="findByNameAndAge" resultType="user">  
          select * from user where name= #{arg0} and age = #{arg1} 
       </select
    
    5.map集合类型,如用于分页查询时传入一个Map集合
     接口方法:` List<User> queryByPage(Map<String,Integer> map);`
        <select id="queryByPage" parameterType="map" resultType="user">
            select *from user limit #{startIndex},#{pageSize}
        </select>
     
    测试:
                   @Test
                    public void test04(){
                        SqlSession session = GetSession.getSession();
                        UserMapper userMapper = session.getMapper(UserMapper.class);
                        Map<String,Integer> map = new HashMap<>();
                        map.put("startIndex", 0);
                        map.put("pageSize", 2);
                        List<User> users = userMapper.queryByPage(map);
                        for (User user: users) {
                            System.out.println(user);
                        }
                    }
                //map传入的key的名称一定要与sql中的对应
    
  • ${}和#{}获取参数的区别

    1、#相当于对数据 加上 双引号,$相当于直接显示数据。
    2、#{} : 根据参数的类型进行处理,比如传入String类型,则会为参数加上双引号。#{} 传参在进行SQL预编译时,会把参数部分用一个占位符 ? 代替,这样可以防止 SQL注入。
    3、${} : 将参数取出不做任何处理,直接放入语句中,就是简单的字符串替换,并且该参数会参加SQL的预编译,需要手动过滤参数防止 SQL注入。
    4、因此 mybatis 中优先使用 #{};当需要动态传入表名或列名时,再考虑使用 ${},$他的应用场景是需要动态传入表名或列名时使用,MyBatis排序时使用order by排序时使用$
    
  • resultType:结果类型

    1.基本数据类型和String类型,增删改返回值类型都为int类型,可以省略
              <select id="queryNameById" parameterType="int" resultType="String">
                  select name from user where id=#{id}
              </select>
          
    2.包装类Integer、Long、Double等
          //统计用户总数
              Integer queryCount();
         
             <select id="queryCount" resultType="Integer">
                  select count(id) from user
             </select>
         
    3.javaBean类型
            <select id="findByNameAndAge" resultType="user">  
                select * from user where name= #{arg0} and age = #{arg1} 
            </select
    
  • resultMap

    1.多对一关系
          表结构:
    

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public class Student {
            private int id;
            private String name;
            private Teacher teacher;
        }
        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public class Teacher {
        private int id;
        private String name;
        }
        StudentMapper:
        //查询全部学生及其对应老师的信息
        List<Student> queryStudentAndTeacher();
        StudentMapper.xml:
            <!--多对一,结果嵌套查询-->
                  <select id="queryStudentAndTeacher" resultMap="studentTeacher">
                      --     单独这句sql查出的teacher属性为null
                            select s.id sid,s.name sname ,t.id tid ,t.name tname  from student s,teacher t where s.tid=t.id
                  </select>
                  <!--id为resultMap的值  type是上面语句要查出的对象-->
                  <resultMap id="studentTeacher" type="student">
                        <!--主键用id标签,其余用result标签-->
                        <id property="id" column="sid"></id>
                        <result property="name" column="sname"></result>
                        <!--property为pojo中的属性名 ,javaType指pojo中特定的属性的类型    -->
                        <association property="teacher" javaType="teacher">
                             <id property="id" column="tid"></id>
                             <result property="name" column="tname"></result>
                        </association>
                  </resultMap>
               <!--======================================-->
                  <!--多对一,查询嵌套处理 类似与子查询-->
                  <select id="queryStudentAndTeacher2" resultMap="studentTeacher2">
                      select *from student
                  </select>
                  <select id="queryTeacher" resultType="teacher">
                      select *from teacher where id=#{tid}
                  </select>
                  <resultMap id="studentTeacher2" type="student">
                      <!-- 属性名与数据库列名一致,这里可以省略id和result标签-->
                      <!--property是pojo中的属性,column为表中的列名,javaType是属性的类型,select是从queryTeacher这个查询语句中进行子查询,比结果嵌套查多了column-->
                      <association property="teacher" column="tid" javaType="teacher" select="queryTeacher">
                      </association>
                  </resultMap>
  2.一对多关系
        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public class Student1 {
            private int id;
            private String name;
            private int tid;
        } 
        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public class Teacher1 {
            private int id;
            private String name;
            List<Student1> student1;
        }  
        Teacher1Mapper:
              public interface Teacher1Mapper {
                  //查询所有老师及其学生的信息
                  List<Teacher1> queryTeacherAndS();

                  //查询所有老师及其学生的信息
                  List<Teacher1> queryTeacherAndS1();
              }  
        Teacher1Mapper.xml:
                  <!--一对多,结果嵌套查询-->
                  <select id="queryTeacherAndS" resultMap="teacherStudent">
                      select t.id tid ,t.name tname,s.name sname from teacher1 t,student1 s where t.id=s.tid order by tid
                  </select>

                  <resultMap id="teacherStudent" type="teacher1">
                       <id property="id" column="tid"></id>
                  <result property="name" column="tname"></result>
                  <!--对象用association,集合用collection 结集合中的泛型用ofType获取-->
                      <collection property="student1" ofType="Student1">
                            <result property="name" column="sname"></result>
                      </collection>
                  </resultMap>
              <!--======================================-->

                  <!--一对多 ,子查询-->
                  <select id="queryTeacherAndS1" resultMap="teacherStudent1">
                      select *from teacher1
                  </select>
                  <select id="queryStudent" resultType="student1">
                      select *from student1 where tid =#{id}
                  </select>
                  <resultMap id="teacherStudent1" type="teacher1">
                      <!--property为pojo里的属性名,column时要传入子查询的类名 javaType是pojo属性类型 ofType为集合泛型类型-->
                      <collection property="student1" column="id" javaType="ArrayList" ofType="student1" select="queryStudent"></collection>
                  </resultMap> 

4.动态sql

- if标签 
      <select id="queryByIdAndAge" resultType="user">
          select *from user where
          <if test="id!=0">
              id=#{id}
          </if>
          <if test="age!=0">
              and  age=#{age}
          </if>
      </select> 
  根据条件表达式的结果来判断是否将对应的语句加入到sql中,但是如果id为0且age不为0的话,sql中where后紧跟着and会出错,所以if常与where标签一起使用
- where标签  
        <select id="queryByIdAndAge1" resultType="user">
            select *from user
            <where>
                 <if test="id!=0">
                     id=#{id}
                 </if>
                 <if test="age!=0">
                     and  age=#{age}
                 </if>
             </where>
         </select>
  where标签会自动判断是否删除sql中的and关键字,若and与where直接相连则删除and
- choose、when、otherwise标签
          <select id="queryUser" resultType="user">
                select * from user 
                <where>
                    <choose>
                        <when test="id!=0">
                            id=#{id}
                        </when>
                        <when test="name!=null">
                            name=#{name}
                        </when>
                        <when test="age!=0">
                            age=#{age}
                        </when>
                        <otherwise>
                
                        </otherwise>
                    </choose>
                </where>
            </select>
   choose是or的含义,当满足when标签的一个时则choose结束,全不满足时执行<otherwise>标签,if时and的含义,只要test表达式为真就执行
- trim标签
        trim标签中的prefix和suffix属性会被用与生成实际的sql语句,如果语句前后出现了prefixOverrides或者suffixOverrides属性中的值,会将其自动删除
        <select id="findByUser" parameterType="User" resultType="User">  
             select * from user  
             <trim prefix="where" prefixOverrides="and">    
                  <if test="id!=0">          
                      id = #{id}     
                  </if>   
                  <if test="name!=null">   
                       and name = #{name}   
                  </if>          
                  <if test="age!=0">    
                      and age = #{age}     
                  </if>   
               </trim>
         </select>
- set标签
        set标签主要用与update操作
        <update id="update" parameterType="cn.ty.user"> 
           update user
           <set>      
                <if test="name!=null">   
                      name = #{name},
                </if>     
                <if test="age!=0"> 
                   age = #{age}       
                </if>  
          </set> 
                 where id = #{id} 
        </update>
- foreach标签
        mapper:
        //遍历查询student
        List<Student> queryStudentForeach(Map map);  
        mapper.xml                       
        <select id="queryStudentForeach" parameterType="map" resultType="student">
            select *from student
            <where>
       -- collection要遍历的集合名称,相当于select *from student where(id=? or id=?)
                <foreach collection="ids" item="id" open="(" close=")" separator="or">
                    id=#{id}
                </foreach>
            </where>
         </select>
        测试:
         @Test
            public void test11(){
                SqlSession session = GetSession.getSession();
                StudentMapper mapper = session.getMapper(StudentMapper.class);
                Map map = new HashMap();
                List ids = new ArrayList();
                ids.add(1);
                ids.add(2);
                map.put("ids", ids);
                List<Student> students = mapper.queryStudentForeach(map);
                for (Student student : students) {
                    System.out.println(student);
                }
                session.close();
            }

5.二级缓存

  是基于一个namespace的,不同的mapper共用一个缓存
  开启步骤:
        1.在mybatis.xml中开启全局缓存
        ` <setting name="cacheEnabled" value="true"/>`
        2.在mapper.xml中配置缓存信息 <cache/>

6.mybatis运行原理

首先由Resources加载全局配置文件,然后new 一个SqlSessionFactoryBuilder对象,它是SqlSessionFactory的构建者,由SqlSessionFactory的实现类DefaultSqlSessionFactory实例化一个 对象,在实例化之前由XMLConfigbuilder解析全局配置文件,并将解析的结果放入Configuration中,然后把 Configuration传入DefaultSqlSessionFactory中,到此SqlSessionFactory工厂创建完成,再由工厂创建SqlSession,每次创建SqlSession时,都需要由TransactionFactory 创建Transaction对象,同时还要创建SqlSession的执行器Excutor,最后实例化DefaultSqlSession,传递给SqlSession接口。

posted @ 2020-05-06 21:53  shallMe  阅读(153)  评论(0)    收藏  举报