MyBatis框架快速上手

1.1 软件开发常用结构
1.1.1 三层架构
三层架构包含的三层:
界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据
访问层(Data access layer)

三层的职责
        1. 界面层(表示层,视图层):主要功能是接受用户的数据,显示请求的处理结果。使用 web 页面和用户交互,手机 app 也就是表示层的,用户在 app 中操作,业务逻辑在服务器端处理。
        2. 业务逻辑层:接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
        3. 数据访问层:与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库.

        每一层对应着一个框架:

                 (1)界面层---SpringMVC框架

                 (2)业务层---Spring框架

                (3)持久层---MyBatis框架

三层的处理请求的交互:

        用户---> 界面层--->业务逻辑层--->数据访问层--->DB 数据

为什么要使用三层?
        1,结构清晰、耦合度低, 各层分工明确
        2,可维护性高,可扩展性高
        3,有利于标准化
        4,开发人员可以只关注整个结构中的其中某一层的功能实现
        5,有利于各层逻辑的复用

使用JDBC编程的基本代码步骤:

public void findStudent() { 
    Connection conn = null; 
    Statement stmt = null; 
    ResultSet rs = null; 
    try { 
        //注册mysql 驱动 
        Class.forName("com.mysql.jdbc.Driver"); 
        //连接数据的基本信息 url ,username,password 
        String url = "jdbc:mysql://localhost:3306/springdb"; 
        String username = "root"; 
        String password = "123456"; 
        //创建连接对象 
        conn = DriverManager.getConnection(url, username, 
password); 
        //保存查询结果 
        List<Student> stuList = new ArrayList<>(); 
        //创建Statement, 用来执行sql 语句 
        stmt = conn.createStatement();
//执行查询,创建记录集, 
        rs = stmt.executeQuery("select * from student"); 
        while (rs.next()) { 
            Student stu = new Student(); 
            stu.setId(rs.getInt("id")); 
            stu.setName(rs.getString("name")); 
            stu.setAge(rs.getInt("age")); 
            //从数据库取出数据转为Student 对象,封装到List 集合 
            stuList.add(stu); 
        } 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } finally { 
        try { 
            //关闭资源 
            if (rs != null) ; 
            { 
                rs.close(); 
            } 
            if (stmt != null) { 
                stmt.close(); 
            } 
            if (conn != null) { 
                conn.close(); 
            } 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    } 
}

使用JDBC缺陷

        1. 代码比较多,开发效率低
        2. 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
        3. 对 ResultSet 查询的结果,需要自己封装为 List
        4. 重复的代码比较多,业务代码和数据库的操作混在一起

MyBatis 解决的主要问题

        1. 注册数据库的驱动,例如 Class.forName(“com.mysql.jdbc.Driver”))
        2. 创建 JDBC 中必须使用的 Connection , Statement, ResultSet 对象
        3. 从 xml 中获取 sql,并执行 sql 语句,把 ResultSet 结果转换 java 对象

MyBatis实现步骤

        0.创建student表(id,name,email,age)

        1.新建maven项目

        2.修改pom.xml 

           1)加入依赖 mybatis依赖, mysql驱动, junit

     <!--mybatis-->
       <dependency>
           <groupId>org.mybatis</groupId>
           <artifactId>mybatis</artifactId>
           <version>3.5.2</version>
       </dependency>
       <!--mysql-->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>5.1.47</version>
       </dependency>
       <!--juint-->
       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>4.13.2</version>
       </dependency>

           2)在<build>加入资源插件

                需要在pom.xml中的<build>中加入下面这个插件,这样在dao目录下可以直接创建对应 的.xml文件,否则需要在resouces目录中创建和dao接口对应的目录,在对应的目录下面创建对应的.xml文件

  <build>
    <!--资源插件: 处理src/main/java目录中的xml-->
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>

        3.创建实体类Student。定义属性, 属性名和列名保持一致

        4.创建Dao接口, 定义操作数据库的方法。

        5.创建xml文件(mapper文件), 写sql语句。 

           <mapper namespace="com.rk.mapper.UserMapper">:通过<mapper>标签的namespace找                 到UserMapper

           mybatis框架推荐是把sql语句和java代码分开

           mapper文件:定义和dao接口在同一目录, 一个表一个mapper文件。

        6.创建mybatis的主配置文件(xml文件):有一个, 放在resources目录下

           1)定义创建连接实例的数据源(DataSource)对象

           2)   指定其他mapper文件的位置

           在Mybatis-com.xml映射UserMapper.xml:

             <mapper resource="com/rk/mapper/UserMapper.xml"/>:注意这里是/ UserMapper.xml用 的是 .   如果想用点则使用class属性:<mapper class="com.rk.mapper.UserMapper"></mapper>

       通过mybatis-config.xml中的<mappers>  ----->  找到UserMapper.xml -----> UserDao  

        创建mybatis的主配置文件和mapper文件需要导入约束,约束在mybatis官网有,代码如下

主配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration  
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  "http://mybatis.org/dtd/mybatis-3-config.dtd">

mapper文件:

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

打印执行日志的插件(放在mybatis的主配置中):

  <!--设置mybatis输出日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

mybatis实现步骤:

        1、读取配置文件

        2、利用SqlSessionFactoryBuilder()对象加载读取的配置文件获取factory

        3、利用factory的openSession方法获取SqlSession对象,factory.openSession(true),设置参 数为true为自动提交事务,这样后面不需要手动提交session.commit()

        4、SqlSession创建Dao接口的代理对象

        5、使用代理对象执行方法

        6、释放资源

         //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        SqlSession session = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        UserDao userDao = session.<UserDao>getMapper(UserDao.class);
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        for(User user : users){
            System.out.println(user);
        }
        //6.释放资源
        session.close();
        in.close();

Mybatsi的工具类

public class MyBatisUtil { 
        //定义  SqlSessionFactory 
        private static SqlSessionFactory factory = null; 
        static { 
                //使用 静态块 创建一次  SqlSessionFactory 
              try{ 
                        String config = "mybatis-config.xml"; 
                        //读取配置文件 
            InputStream in = Resources.getResourceAsStream(config); 
                        //创建SqlSessionFactory 对象 
            factory = new SqlSessionFactoryBuilder().build(in); 
                }catch (Exception e){ 
                        factory = null; 
                        e.printStackTrace(); 
                } 
        } 
 
        /*  获取SqlSession 对象  */ 
        public static SqlSession getSqlSession(){ 
                SqlSession session = null; 
                if( factory != null){ 
                        session = factory.openSession(); 
                } 
                return session; 
        } 

 使用mybatis代理要求

        (1)mapper文件中的namespace 一定dao接口的全限定名称

        (2)mapper文件中 标签的id是dao接口方法名称

        Dao 接口中方法的参数只有一个简单类型(java 基本类型和 String),占
        位符 #{ 任意字符 },和方法的参数名无关。

多个参数的传递:

方式一:

        当 Dao 接口方法多个参数,需要通过名称使用参数。 在方法形参前面加
       入@Param(“自定义参数名”),mapper 文件使用#{自定义参数名}。

dao接口方法:   

    List<Student> selectMultiParam(@Param("personName") String name,
@Param("personAge") int age);

mapper 文件:
      

 <select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{personName} or age=#{personAge}
</select>

方式二:使用对象
创建保存参数值的对象 QueryParam

  package com.bjpowernode.vo;
        public class QueryParam {
            private String queryName;
            private int queryAge;
            //set ,get 方法
        }

接口方法:

List<Student> selectMultiObject(QueryParam queryParam);

mapper 文件:
 

<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{queryName} or age=#{queryAge}
</select>

方式三:按位置

       参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0},
       第二个是#{arg1}

接口方法:

List<Student> selectByNameAndAge(String name,int age);

mapper 文件:

<select id="selectByNameAndAge"resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{arg0} or age=#{arg1}
</select> 

        #:占位符,告诉 mybatis 使用实际的参数值代替。并使用PrepareStatement 对象执行 sql 语句, #{...}代替 sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法

        $ 字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置。使用Statement 把 sql 语句和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。

        resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType 和 resultMap不能同时使用。

         1. 调用com.bjpowernode.domain.Student的无参数构造方法,创建对象。Student student = new Student(); //使用反射创建对象
        2. 同名的列赋值给同名的属性。
            student.setId( rs.getInt("id"));
            student.setName(rs.getString("name"));
        3. 得到java对象, 如果dao接口返回值是List集合, mybatis把student对象放入到List合。

实体类属性名和列名不同的处理方式 :

        1、使用别名:

<select id="selectUseFieldAlias"resultType="com.bjpowernode.domain.PrimaryStudent">
    select id as stuId, name as stuName,age as stuAgefrom student where name=#{queryName} or age=#{queryAge}
</select>

        2、使用<resultMap>

        1. 接口方法
                List<PrimaryStudent> selectUseDiffResultMap(QueryParam param);

        2. mapper 文件:
        

        <!-- 创建resultMap
        id:自定义的唯一名称,在<select>使用
        type:期望转为的java 对象的全限定名称或别名
        -->
        <resultMap id="primaryStudentMap"
        type="com.bjpowernode.domain.PrimaryStudent">
        <!-- 主键字段使用id -->
        <id column="id" property="stuId" />
        <!--非主键字段使用result-->
        <result column="name" property="stuName"/>
        <result column="age" property="stuAge" />
        </resultMap>

        <!--resultMap: resultMap 标签中的id 属性值-->
        <select id="selectUseDiffResultMap" resultMap="primaryStudentMap">
        select id,name,email,age from student
        where name=#{queryName} or age=#{queryAge}
        </select> 

 模糊查询like
        模糊查询的实现有两种方式 

        一是 java 代码中给查询数据加上“%” ;

        二是在 mapper 文件 sql 语句的条件位置加上“%”

<select id="selectLikeSecond" resultType="com.bjpowernode.domain.Student"> 
        select id,name,email,age from student 
        where name like '%${studentName}%' 
</select>

MyBatis 框架动态 SQL

         动态sql: 同一个dao的方法, 根据不同的条件可以表示不同的sql语句, 主要是where部分有变化使用mybatis提供的标签,实现动态sql的能力

        在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。
        特别是对于小于号(<),在 XML 中是绝不能出现的。否则解析 mapper文件会出错。

        <if>:对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接
到其所在的 SQL 语句中。

语法:<if test=”条件”> sql 语句的部分 </if>

mapper 文件:

        <select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
            select id,name,email,age from student
            where 1=1
            <if test="name != null and name !='' ">
            and name = #{name}
            </if>
            <if test="age > 0 ">
            and age &gt; #{age}
            </if>
        </select>

<where>:<if/>标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1的子句。因为,若 where 后的所有<if/>条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL 出错。所以,在where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会严重影响查询效率。
        使用<where/>标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加 where 子句。需要注意的是,第一个<if/>标签中的SQL 片断,可以不包含 and。不过,写上 and 也不错,系统会将多出的 and去掉。但其它<if/>中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错

语法:<where> 其他动态 sql </where>

<foreach>:<foreach/>标签用于实现对于数组与集合的遍历

注意:

                collection 表示要遍历的集合类型, list ,array 等。
                open、close、separator 为对遍历内容的 SQL 拼接。

语法:
        <foreach collection="集合类型" open="开始的字符" close="结束的字符"
                item="集合中的成员" separator="集合成员之间的分隔符">
                #{item 的值}
        </foreach>

案例:

        需求:查询学生 id 是 1002,1005,1006

        接口方法:
                List<Student> selectStudentForList(List<Integer> idList);

        mapper 文件:

<select id="selectStudentForList" 
resultType="com.bjpowernode.domain.Student"> 
        select id,name,email,age from student 
        <if test="list !=null and list.size > 0 "> 
                where id in 
                <foreach collection="list" open="(" close=")"   
    item="stuid" separator=","> 
                        #{stuid} 
                </foreach> 
        </if> 
</select> 

        测试方法:

@Test 
public void testSelectForList()    { 
        List<Integer> list = new ArrayList<>(); 
        list.add(1002); 
        list.add(1005); 
        list.add(1006); 
 
        List<Student> studentList = studentDao.selectStudentForList(list); 
        studentList.forEach( stu -> System.out.println(stu)); 
}

 mybatis主配置文件中的mappers:

<mappers>
    <!--第一种方式, resources="mapper文件的路径"
        优点:文件清晰。 加载的文件是明确的。
              文件的位置比较灵活。
        缺点:文件比较多, 代码量会比较大, 管理难度大
    -->
    <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
    <mapper resource="com/bjpowernode/dao/OrderDao.xml"/>
    <!--
       第二种方式,使用<package>
       name:包名, mapper文件所在的包名。
       特点: 把这个包中的所有mapper文件,一次加载。

       使用要求:
        1. mapper文件和dao接口在同一目录
        2. mapper文件和dao接口名称完全一样。
    -->
    <package name="com.bjpowernode.dao" />
    <package name="com.bjpowernode.dao1" />
</mappers>

Mybatis 通用分页插件 PageHelper

使用步骤:

(1)maven 坐标(加入依赖)

<dependency> 
    <groupId>com.github.pagehelper</groupId> 
    <artifactId>pagehelper</artifactId> 
    <version>5.1.10</version> 
</dependency> 

 (2)加入 plugin 配置

   在主配置文件<environments>之前加入

        <plugins>
              <plugin interceptor="com.github.pagehelper.PageInterceptor" />
        </plugins>

(3)PageHelper 对象

在select语句之前,调用PageHelper.startPage(页码, 每页大小)

        查询语句之前调用 PageHelper.startPage 静态方法。除了PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个MyBatis 查询方法会被进行分页

@Test 
public void testSelect() throws IOException { 
        //获取第1 页,3 条内容 
        PageHelper.startPage(1,3); 
        List<Student> studentList = studentDao.selectStudents(); 
        studentList.forEach( stu -> System.out.println(stu)); 
} 

        

猜你喜欢

转载自blog.csdn.net/m0_46979453/article/details/120404620