MyBatis入门知识汇总

 为什么要使用MyBatis?

  我们都知道,在学习mybatis之前,要在Java中操作数据库,需要用到JDBC,但是在使用JDBC时会有许多缺陷。

比如:

  1、使用时需要先进行数据库连接,不用后要立即释放连接,这样对数据库进行频繁连接和关闭,会造成数据库资源浪费,同时并发量较大时,会影响数据库性能。

  解决方案:为了达到连接复用,使用数据库连接池管理数据库连接。

  2、将sql语句硬编码到java代码中,使得代码耦合度高,如果sql 语句修改,就需要重新编译java代码,不利于系统维护。

  解决方案:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译,只要在配置文件中修改。

  3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。

  解决方案:将sql语句及占位符号和参数全部配置在xml中。

  4、从resutSet中遍历结果集获取数据时,必须保证属性名正确,否则无法取出数据,因此将获取表的字段进行硬编码,不利于系统维护。

  解决方案:将查询的结果集,自动映射成java对象。

  下面是使用JBDC操作时的代码:

  为了方便我使用的是maven项目来编写的,所以在刚开始时需要在pom.xml文件中添加数据库的依赖

  <!--添加数据库依赖-->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.32</version>
  </dependency>

  下面就是代码部分。

public class JDBC {
    public static void main(String[] args) {
        // 数据库连接
        Connection connection = null;
        // 预编译的Statement,使用预编译的Statement提高数据库性能
        PreparedStatement preparedStatement = null;
        // 结果集
        ResultSet resultSet = null;
        try{
            //加载mysql驱动
            Class.forName("com.mysql.jdbc.Driver");
            String URL="jdbc:mysql://localhost:3306/test";
            String USER="root";
            String PASS="123456";
            // 通过驱动管理类获取数据库链接
            connection=DriverManager.getConnection(URL,USER,PASS);
            // 定义sql语句 ?表示占位符
            String sql="select * from student where SID=?";
            // 获取预处理statement
            preparedStatement= connection.prepareStatement(sql);
            // 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
            preparedStatement.setString(1,"2");
            //返回结果集
            resultSet=preparedStatement.executeQuery();
            // 遍历查询结果集
            while (resultSet.next()) {
                System.out.println(resultSet.getString("Sname")+"   "+
                        resultSet.getString("Sage"));
            }
        }catch (Exception e){
            e.getMessage();
        }finally {
            //关闭连接
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
JDBC代码

  通过上述代码可以看出,sql语句和Java语句是混合在一块编码的,这大大更加了代码耦合度,这样在修改sql语句时,都需要重新编译Java代码,不利于系统维护。而且在实际开发中也经常会出现修改或优化sql语句的情况,所以之后人们便更多的使用MyBatis来进行操作数据库。

一,MyBatis概述

  MyBatis 本是apache的一个开源项目iBatis,2010年6月由apache software foundation 迁移到了google code,并且改名为MyBatis,因为当时iBatis已经发布到3.x版本了,所以也可以理解为Mybatis实际就是ibatis 3.x的后续版。 

  MyBatis 是一款优秀的支持自定义 SQL 查询存储过程高级映射的持久层框架,消除了几乎所有的 JDBC 代码和参数的手动设置以及结果集的检索,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

  Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

  另外MyBatis 支持声明式数据缓存 。当 SQL 语句被标记为“可缓存”后,首次执行它时从数据库获取的所有数据会被存储在高速缓存中,后面再执行这条语句时就会从高速缓存中读取结果,而不是再次命中数据库,MyBatis 提供了默认情况下基于 Java的HashMap 缓存实现,以及用于与 OSCache Ehcache Hazeleast Memcached 连接的默认连接器,同时还提供了 API 供其他缓存实现使用。
二,MyBatis的流程图
三,Mybatis环境搭建及简单实例(从数据库查询id为6的学生信息)
1.准备开发环境:
 先新建一个项目, 添加依赖包:mybatis包、数据库驱动包(我使用的是mysql)、日志包(我使用的是log4j), 由于我的是maven项目, 那么添加依赖包就简单了,直接在pom.xml添加依赖即可。
pom.xml的文件配置:
 <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--添加mysql数据库依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.32</version>
    </dependency>
    <!--添加mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.2.6</version>
    </dependency>
    <!-- 添加log4j 日志依赖-->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
  </dependencies>
pom.xml

 2.添加全局配置文件(mybatis-cfg.xml)

<?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">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/StudentMapper.xml"></mapper>
    </mappers>
</configuration>
mybatis-cfg.xml

3.根据数据库中要访问的表的信息创建POJO类(Student.java)

public class Student {
    private int SID;
    private String Sname;
    private int Sage;
    private String Ssex;
    @Override
    public String toString() {
        return "Student{" +
                "SID=" + SID +
                ", Sname='" + Sname + '\'' +
                ", Sage=" + Sage +
                ", Ssex='" + Ssex + '\'' +
                '}';
    }
    public void setSID(int SID) {
        this.SID = SID;
    }
    public void setSname(String sname) {
        Sname = sname;
    }
    public void setSage(int sage) {
        Sage = sage;
    }
    public void setSsex(String ssex) {
        Ssex = ssex;
    }
    public int getSID() {
        return SID;
    }
    public String getSname() {
        return Sname;
    }
    public int getSage() {
        return Sage;
    }
    public String getSsex() {
        return Ssex;
    }
}
Student.java

4.创建Mapper接口文件(StudentMapper.java)

  这是一个接口类,里面封装了一些空方法,而方法的具体内容一般是在它的映射文件xml中用sql的语法来编写的。

  JDBC:       Dao(接口)    ------>    DaoImpl(实现类)

  MyBatis:   Mapper(接口)----->   xxxMapper.xml

public interface StudentMapper {
    public Student selectStudentById(int sid);
}
StudentMapper.java

5.添加Mapper.xml映射文件(StudentMapper.xml)

  注意写好的Mapper.xml映射文件一定要注册在全局配置文件(mybatis-cfg.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:名称空间
id:唯一标识
resultType:返回值类型
#{id}:从传过来的参数中取出id值
-->
<mapper namespace="MyBatisDemo.StudentMapper">
    <!--查询标签:select  注意此处id为该方法的方法名-->
    <select id="selectStudentById" resultType="MyBatisDemo.Student">
        select * from student where SID=#{sid}
    </select>
</mapper>
StudentMapper.xml

6.添加日志配置文件

## debug 级别
log4j.rootLogger=DEBUG,Console  
log4j.appender.Console=org.apache.log4j.ConsoleAppender  
log4j.appender.Console.Target=System.out  
log4j.appender.Console.layout = org.apache.log4j.PatternLayout  
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd-HH\:mm\:ss,SSS} [%t]  [%c] [%p] - %m%n  
log4j.logger.com.mybatis=DEBUG  /  

##输出sql 语句
log4j.logger.java.sql.Connection=DEBUG  
log4j.logger.java.sql.Statement=DEBUG  
log4j.logger.java.sql.PreparedStatement=DEBUG 
log4.properties

7.测试类

public class MyBatisTest {
    public static void main( String[] args ) {
        SqlSession openSession = null;
        try {
            //mybatis配置文件
            String resourse="mybatis-cfg.xml";
            //通过 Resources 工具类将 mybatis-config.xm 配置文件读入 Reader
            InputStream inputStream=Resources.getResourceAsStream(resourse);
            //通过 SqlSessionFactoryBuilder 建造类使用 Reader 创建 SqlSessionFactory工厂对象
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
            //通过SqlSessionFactory工厂得到SqlSession
            openSession = sqlSessionFactory.openSession();
            //通过反射机制来获取对应的Mapper实例
            StudentMapper mapper=openSession.getMapper(StudentMapper.class);
            //通过mapper调用实例下的方法
            Student student=mapper.selectStudentById(6);
            System.out.println(student);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //最后一定不要忘记关闭 SqlSession ,否则会因为连接没有关闭导致数据库连接数过多,造成系统崩旗
            openSession.close();
        }
    }
}

8.运行结果

四.MyBatis-全局配置文件

1.properties标签

  mybatis可以通过properties标签来引入外部properties配置文件的内容,包括两个路径下的资源,

  • resource:引入类路径下的资源
  • url:引入网络路径或者磁盘路径下的资源

  在使用properties标签之前,配置数据库是用下面的方法,由于是使用硬编码的方式,修改value参数值都需要动代码。在使用properties标签后,就可以将参数值封装到一个配置文件中,每次修改参数只需在配置文件中修改即可。

      

 使用properties的步骤:

  1.在mybatis-cfg.xml的同目录下创建一个db.properties文件,文件中存放数据库连接使用的一些值,下面是文件中的内容。

           

  2.在mybaties-cfg.xml中添加properties标签,双引号之间是db.properties文件名

  

  3.将mybaties-cfg.xml中的值替换成变量

    

最后需要注意:如果属性在不止一个地方进行了配置,那么MyBatis将按照下面顺序来加载

  • 在property元素体内指定的属性首先被读取
  • 然后根据properties元素中的resource属性读取类路径下属性文件或根据url属性指定的路径读取属性文件,并覆盖已读取的同名属性
  • 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性

2.settings标签

  下图是MyBatis中重要的调整设置,他们会改变Mybatis的运行时行为

举例:驼峰命名法

  为了保证查询的数据可以正常显示出来,我们在编写POJO类时,必须保证它内部定义属性名和数据库中的属性名必须相同,但我们在数据库中定义属性时一般习惯采用驼峰命名法A_B,而Java中又习惯采用aB这种格式命名,所以许多人在编写代码时都会因为格式不相同而无法正确查出数据,所以就有了驼峰命名法,这样即使格式不一样(属性名相同,仅格式不同),也可以正确查出数据。

驼峰命名法的使用方式:

  在mybatis-cfg.xml文件中添加settings标签即可。

      

   settings用来设置每一个设置项,name设置项名,value设置项取值

3.typeAliases标签(别名处理器)

   在mybatis中可以使用typeAliases来给变量取别名,这样对于一些变量名较长的变量,我们就可直接使用它的别名。(别名不区分大小写)

比如:我们每次在StudentMapper.xml中编写查询数据的代码时,都要指定数据返回类型,但又因为返回值类型的名字太长,每次编写时都不方便,所以我们就可以给这个返回值类型起一个简单易编写的别名。

       

 起别名的方法:

  1.在mybatis-cfg.xml文件中添加typeAliases标签

       

   2.将StudentMapper.xml映射文件中使用到MyBatisDemo.Student的地方都替换成TMS

  

 批量起别名的方法:

  1.在mybatis-cfg.xml文件中添加typeAliases标签

  

  2.在使用该包下的某个类时,就可直接使用类名(大小写都可),(不仅适应于返回值类型,也可适应参数类型)

  

   但是只用这种方法有个缺陷,就是当该A包底下还存在一个B包,该B包与A包存在相同的类名的类时,使用这种方法就无法区分要使用的是哪个类,所以为了避免这种情况,可结合@Alias注解

   3.给MyBatisDemo包下的类名冲突的子类添加注解

  

   4.将StudentMapper.xml映射文件中使用到MyBatisDemo.Student的地方都替换成TMS

  

4.typeHandlers标签(类型处理器)

  由于java类型与数据库类型之间的差异,无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都需要使用系统提供的类型处理器(也可以自定义类型处理器), 将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。

 

5.objectFactory标签

6.plugins标签

7.environments标签

 

8.databaseidProvider标签

  可以支持多个数据库厂商,使用该标签,可以在多个不同的数据库中进行查询数据。

  1.在mybatis-cfg.xml文件中添加databaseidProvider标签

  2.在StudentMapper.xml映射文件中修改select语句

  

  3.切换当前所使用的数据库环境

 

9.mappers标签

1.注册一个sql映射,其中resource来指定引用类路径下的sql映射,url用来引用网络路径或者磁盘路径下的sql映射

2.注册接口,使用注册接口的方法和注册sql映射的方法的作用是一样的。

 

 但是使用注册接口的方法,要保证接口的类名和sql映射的文件名相同,并且两个必须放到同一个包路径下。

另外如果没有映射文件,也可使用注册接口的方法,与上面不同的是,sql语句是利用注解写在接口上的,虽然这样利用注解也可以实现,但是sql和java代码的耦合度会更高。所以还是建议利用创建sql映射文件的方式

     

10.总结

  在mybatis-cfg.xml中配置上面的这些标签时,必须按照上面1-9的排列顺序配置,可以缺少某一个标签,但不允许顺序发生变化,否则会报错。

.XML映射文件的编写

  由于xml映射文件和接口文件是绑定的关系,所以每次在xml映射文件中添加sql语句,在接口中也就要添加响应的Java语句。

1.查询操作

接口文件:

  

sql映射文件:

  

测试类:

    

注意此查询仅支持返回一个结果集,如果返回有多个会报TooManyExection异常。所以如果返回结果有多条就需要将接口文件中方法返回值改为List/Map类型,但sql映射文件不变,如下所示。

1.1.List类型

接口文件:

   

sql映射文件:不变(注意返回类型仍为Student,不为List<Student>)

测试类:

 

1.2.Map类型(只返回一条记录)

  列名作为key,值就是查询的值。

接口文件:

 

sql映射文件:(返回多天记录时,返回值类型就为记录的类型,但返回一条就可写为map)

   

测试类:

 

1.3 Map类型(返回多条记录)

  将多条记录封装在一个Map中,并要求指定属性作为Key值,此处是以名字作为key。

接口文件:

   

sql映射文件:

    

测试类:

   

2.添加操作

接口文件:

  

sql映射文件:

  

注意:此处student()中的参数格式必须和数据库中的参数格式相同,values()中的#{}中参数必须和POJO类中的参数名相同。

测试类:

  

此处方法是无返回类型的,所以在返回值类型那块写void即可,如果想改为Boolean/int类型,可直接将void改为Boolean/int即可,其他sql映射代码无需在修改。

3.更新操作

接口文件:

 

sql映射文件:

 

注意:此处set后面的参数格式必须和数据库中的参数格式相同,#{}中的参数必须和POJO类中的参数名相同。

测试类:

  

4.删除操作

接口文件:

    

sql映射文件:

     

因为此处是使用(int)sid来查询删除的,参数不为student,所以#{}中可任意写。

测试类:

    

5.多参数查询

1.使用param来传参。因为在传参数时出现多个参数的情况时,这多个参数会被封装成Map集合,其中key存储为param1.param2....paramn,value存储就是参数的值,所以在sql映射文件中就需要使用param来取值。

接口文件:

   

sql映射文件:

    

2.命名参数。使用param来传参难免会有些不便,当参数多了,就会混淆,为了更好区分,我们可以在传参时,使用注解重新命名。这时候key存储为@Param(变量名1).@Param(变量名2)......,value存储就是参数的值,所以在sql映射文件中就需要使用param重新命的名来取值。

接口文件:

 

sql映射文件:

    

测试类:

   

3.如果多个参数正好都是POJO类中的变量,也可以使用POJO类来传参。

4.补充:

 6.${}取值与#{}取值的区别

1.#{}是预编译处理,$ {}是字符串替换。
2.MyBatis在处理#{}时,会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值;MyBatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。
3.使用 #{} 可以有效的防止SQL注入,提高系统安全性。

 7.自定义结果集映射(resultMap)

1.当POJO类中定义的属性名与数据库中的属性名格式不同时,我们除了可以开启驼峰命名法,还可采用resultMap来解决。

2. 当有两张表Student表和Course表,在学生表中存在课程表的id号的列,那如果想通过Student表即查出学生信息又查出专业信息,我们知道使用resultType是实现不了的,这时候就可使用resultMap来实现。

 除了上面这种使用方式,还可以借助association标签来实现。

 sql映射文件:

3.使用association标签来实现分布查询

步骤:使用select方法先查出Student的信息,其中包括Cid,然后又根据Cid在Course表中查出课程名。

 测试类:

 4.延迟加载

  通过查看打印结果可知,在上面的分步查询过程中,不过有没有调用student.getCourse()方法,在底层都会进行数据库的两次查询,这样就会降低执行效率,但是使用延迟加载,就可以保证当我们使用了student.getCourse()方法,底层才会取数据库进行查询课程。

开启延迟加载的方法:在全局配置文件(mybatis-cfg.xml)中,添加setting标签。

 5.collection标签

有一张teacher表,里面既有教师信息,也有教师授课的信息,如果想通教师号查到该教师所授的课程信息,由于是一对多的关系,因此就需要使用collection标签

 六.MyBatis动态SQL

1.if标签

举例:根据传入的学生信息在数据库中查找,如果输入的姓名不为null,就根据姓名查找,如果输入的id不为null,就根据id查找,如果都不为空,就查找两个信息都匹配的学生。

映射文件:

 测试类:

通过仔细观察上述代码,就会发现上述代码是存在问题的,如果传入的Sid为空,那么查询就变成了select * from student where and Sname=?,这明显是有语法问题的,那该怎么解决呢?

1.在where后添加1=1

2.将if标签放到where标签中,这样在查询时,就会自动省and,但必须要求and是在赋值语句前面的,如果在后面,必须使用trim标签。

3.在update时后边可能会多一个逗号,可以将更新语句放到set标签里,当然也可以使用trim标签。

2.trim(where,set)

prefix:给整个字符串添加一个前缀

prefixOverrides:去掉整个字符串前面多余的字符

suffix:给整个字符串去掉一个后缀

suffixOverrides:去掉整个字符串后面多余的字符

3.choose(when,otherwise)

对于if标签中举例的那个问题同样可以使用choose解决。

4.foreach 标签

separator:每个元素之间的分隔符。

open:给遍历所有的结果拼接一个开始的字符

close:给遍历出所有的结果拼接一个结束的字符

index:索引。遍历list的时候,index是索引,item就是当前值。遍历map的时候,index就是map的key,item就是map的值。

举例1:给一些id号,然后在数据库中查找与这些id号匹配的学生的信息。

接口文件:

sql映射文件:

 

测试类:

 举例2:批量添加学生信息

接口文件:

sql映射文件:

测试类:

 5.bind标签(可以给一个变量绑定上一些字符串)

举例:想通过字符串匹配的方法,通过输入' h ' 找到名字中包含h的学生。

 接口文件:

 sql映射文件:

 测试类:

 6.抽取重复的sql语句

 

posted @ 2020-05-19 14:26  小L要努力吖  阅读(720)  评论(1编辑  收藏  举报