Mybatis学习笔记


MyBatis 框架

前言

以下笔记内容来自B站动力节点MyBatis教程实战精讲的课程内容,我自己跟着视频的内容对原有笔记进行了适当的增改,仅供参考

第一章 框架的概述

1.三层架构

mvc:web开发中,使用mvc架构模式。 m:数据, v:视图, c:控制器。

? c控制器: 接收请求,调用service对象,显示请求的处理结果。 当前使用servlet作为控制器

? v视图: 现在使用jsp, html,css,js。 显示请求的处理结果,把m中数据显示出来。

? m数据: 来自数据库mysql, 来自文件,来自网络

mvc作用:

? 1)实现解耦合。

? 2)让mvc 各负其职。

? 3)使得系统扩展性更好,更容易维护。

三层架构:

1.界面层(视图层、表现层):接收用户的请求,调用service, 显示请求的处理结果的。 包含了jsp,html,servlet等对象。 对应的包controller,

2.业务逻辑层:处理业务逻辑, 使用算法处理数据的。 把数据返回给界面层。 对应的是service包,和包中的很多的XXXService类。 例如: StudentService , OrderService, ShopService

3.持久层(数据库访问层):访问数据库,或者读取文件,访问网络。获取数据。 对应的包是dao。 dao包中很多的StudentDao, OrderDao, ShopDao等等。

2. 三层架构请求的处理流程

用户发起请求---->界面层----->业务逻辑层---->持久层---->数据库(mysql)

3. 为什么要使用三层?

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

4. 三层架构模式和框架

每一层对应着一个框架

1)界面层---SpringMVC框架

2)业务层---Spring框架

3)持久层---MyBatis框架

5 .框架

  1. 什么是框架(framework)

框架:就是一个软件, 完成了部分的功能。 软件中的类和类之间的方法调用都已经规定好了。 通过这些可以完成某些功能。 框架看做是模版。

框架是可以升级的,改造的。 框架是安全的。

框架是对某一个方面有用的,不是全能的。

6. 框架解决的问题

1)框架能实现技术的整合。

2)提供开发的效率。 降低难度。

7. jdbc访问数据库的优缺点

优点:

  1. 直观,好理解

缺点:

  1. 创建很多对象 Connection ,Statement, ResultSet
  2. 注册驱动
  3. 执行sql语句
  4. 把ResultSet转为 Student , List集合。
  5. 关闭资源
  6. sql语句和业务逻辑代码混在一起

8 MyBatis框架

什么 mybatis: 是一个持久层框架, 原名是ibatis, 2013改名为 MyBatis. MyBatis可以操作数据库,对数据执行增删改查。 看做是高级的jdbc。 解决jdbc的缺点。

mybatis能做什么?

1) 注册驱动 。

2) 创建jdbc中使用的Connection, Statement,ResultSet

  1. 执行sql语句, 得到ResultSet

  2. 处理ResultSet, 把记录集中的数据转为java对象, 同时还能把java对象放入到List集合。

5)关闭资源

6)实现sql语句和java代码的解耦合。

mybatis的文档: https://mybatis.org/mybatis-3/zh/index.html

第二章 MyBatis入门

2.0.1 maven中的配置文件

这里需要注意一下mysql驱动的版本

    
	
        org.mybatis
        mybatis
        3.5.9
    
    
    
        mysql
        mysql-connector-java
        8.0.16
    




    
    
        
            src/main/java
            
                **/*.properties
                **/*.xml
            
            false
        
    
 

2.1 第一个例子

实现步骤:

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

1.新建maven项目


  org.mybatis
  mybatis
  3.5.9

2.修改pom.xml

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


        org.mybatis
        mybatis
        3.5.9



    mysql
    mysql-connector-java
    8.0.16

2)在加入资源插件



    
        src/main/java
        
            **/*.properties
            **/*.xml
        
        false
    

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

public class Student {
    private Integer id;
    private String name;
    private String email;
    private Integer age;

    @Override
    public String toString() {
        return "StudentDao{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }

    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 String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

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

public interface StudentDao {
    List selectStudents();
}

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

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

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

<?xml version="1.0" encoding="UTF-8" ?>



    
    


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

该主配置文件不用过多关心,后续不用

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

  1. 指定其他mapper文件的位置
<?xml version="1.0" encoding="UTF-8" ?>


    
        
            
            
            
                
                
                
                
                
                
            
        
    
    
    
        
        
    

7.创建测试的内容。

使用main方法,测试mybatis访问数据库

也可以使用junit 访问数据库

//1.mybatis 主配置文件
String config = "mybatis-config.xml";
//2.读取配置文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建 SqlSessionFactory 对象,目的是获取 SqlSession
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//4.【重要】获取 SqlSession,SqlSession 能执行 sql 语句
SqlSession session = factory.openSession();
//5.【重要】执行 SqlSession 的 selectList()    sql语句:映射文件中的namespace+"."+标签的id值
List studentList =
    session.selectList("dao.StudentDao.selectStudents");
//6.循环输出查询结果
studentList.forEach( student -> System.out.println(student));
//7.关闭 SqlSession,释放资源
session.close();

8.配置日志功能

在mybatis主配置文件中加入


 

2.2 概念

1.自动提交:当你的 sql语句执行完毕后, 提交事务。 数据库更新操作之间保存到数据

2.手动(手工)提交事务:在你需要提交事务的位置, 执行方法,提交事务或者回顾事务。

2.3 MyBatis的一些对象

1) Resources : mybatis框架中的对象, 一个作用读取 主配置信息。

InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

2)SqlSessionFactoryBuilder:负责创建SqlSessionFactory对象

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

3)SqlSessionFactory: 重要对象

SqlSessionFactory是重量级对象:创建此对象需要使用更多的资源和时间。 在项目中有一个就可以了。

SqlSessionFactory接口:作用是SqlSession的工厂, 就是创建SqlSession对象。

DefaultSqlSessionFactory实现类

public class DefaultSqlSessionFactory implements SqlSessionFactory { } 

SqlSessionFactory接口中的方法

openSession(): 获取一个默认的SqlSession对象, 默认是需要手工提交事务的。

openSession(boolean): boolean参数表示是否自动提交事务。

? true: 创建一个自动提交事务的SqlSession

? false: 等同于没有参数的openSession

  1. SqlSession对象

SqlSession对象是通过SqlSessionFactory获取的。 SqlSession本身是接口

DefaultSqlSession: 实现类

public class DefaultSqlSession implements SqlSession { }

SqlSession作用是提供了大量的执行sql语句的方法:

selectOne:执行sql语句,最多得到一行记录,多余1行是错误。
selectList:执行sql语句,返回多行数据
selectMap:执行sql语句的,得到一个Map结果
insert:执行insert语句
update:执行update语句
delete:执行delete语句
commit:提交事务
rollback:回顾事务

注意SqlSession对象不是线程安全的, 使用的步骤:

①:在方法的内部,执行sql语句之前,先获取SqlSession对象

②:调用SqlSession的方法,执行sql语句

③:关闭SqlSession对象,执行SqlSession.close()

2.4 使用工具类和模版

1)创建工具类

public class MyBatisUtils { 
    //定义  SqlSessionFactory
    private static SqlSessionFactory factory = null;
    //使用 静态块 创建一次  SqlSessionFactory 
    static {
        String config = "mybatis-config.xml";
        InputStream in = null;
        try {
            in = Resources.getResourceAsStream(config);
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取session对象
     * @return session对象
     */
    public static SqlSession getSqlSession(){
        SqlSession session = null;
        if (factory != null){
            session = factory.openSession(true);
        }
        return session;
    }
}

2 )创建模版,mapper文件模版和mybatis主配置文件模版

创建模版的步骤:

image-20201019094212830

创建模版文件:

image-20201019094359625

创建文件选择使用的模版:

image-20201019094616208

第三章 MyBatis的Dao代理(核心)

3.1 dao代理(动态代理)

3.1.1 mybatis提供代理:

mybatis创建Dao接口的实现类对象, 完成对sql语句的执行。 mybatis创建一个对象代替你的 dao实现类功能。

3.1.2 使用mybatis代理要求

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

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

3.1.3 mybatis代理实现方式

使用SqlSession对象的方法 getMapper(dao.class)

例如: 现在有 StudentDao接口。

SqlSession session  = MyBatisUtils.getSqlSession();
StudentDao dao  = session.getMapper(StudentDao.class);
Student student = dao.selectById(1001);


//上面代码中
StudentDao dao  = session.getMapper(StudentDao.class);
等同于
StudentDao dao  = new StudentDaoImpl();

3.2 理解参数

理解参数是: 通过java程序把数据传入到mapper文件中的sql语句。 参数主要是指dao接口方法的形参

3.2.1 parameterType(可以不写)

parameterType:表示参数的类型, 指定dao方法的形参数据类型。 这个形参的数据类型是给mybatis使用。 mybatis在给sql语句的参数赋值时使用。 PreparedStatement.setXXX( 位置, 值)

第一个用法: java类型的全限定类型名称   parameterType="java.lang.Integer"
第二个用法: mybatis定义的java类型的别名  parameterType="int"

parameterType:mybatis通过反射机制可以获取 dao接口方法参数的类型, 可以不写


3.2.2 dao接口方法是一个简单类型的参数

//dao接口的方法形参是一个简单类型的
//简单类型: java基本数据类型和String
Student selectByEmail(String email);


3.2.3 dao接口方法有多个简单类型的参数

@Param: 命名参数, 在方法的形参前面使用的, 定义参数名。 这个名称可以用在mapper文件中。

dao接口,方法的定义

/*
  多个简单类型的参数
  使用@Param命名参数, 注解是mybatis提供的
  位置:在形参定义的前面
  属性:value 自定义的参数名称
 */
List selectByNameOrAge(@Param("myname") String name,
                                @Param("myage") Integer age);

mapper文件



3.2.4 dao接口方法使用一个对象作为参数

方法的形参是一个java对象。这个java对象表示多个参数。使用对象的属性值作为参数使用

java对象

public class Student {
    private Integer id;
    private String name;
    private String email;
    private Integer age;
    //set|get方法
}

public class QueryParam {
    private Object p1;
    private Object p2;
    //set|get方法
}

dao接口中的方法定义

/*
 * 一个java对象作为参数( 对象由属性, 每个属性有set,get方法)
 */
List selectByObject(Student student);

List selectByQueryParam(QueryParam param);

mapper文件








3.2.5 dao接口中多个简单类型的参数,使用位置(了解)

参数位置: dao接口中方法的形参列表,从左往右,参数位置是 0 , 1, 2......

语法格式:#{arg0} ,#{arg1}

dao接口的方法

/*
   使用位置,获取参数
 */
List selectByPosition(String name,Integer age);


3.2.6 dao接口参数是一个Map(了解)

map作为dao接口的参数, 使用 key 获取参数值,mapper文件中,语法格式 #{key}

/*
   使用Map作为参数
 */
List selectStudentByMap(Map map);

mapper文件



测试,调用方法的位置

@Test
public void testSelectByMap(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao  = sqlSession.getMapper(StudentDao.class);

    //使用map传递参数
    Map data = new HashMap<>();
    data.put("myname", "李思思");
    data.put("myage", 20);
    List students = dao.selectStudentByMap(data);

    students.forEach( stu-> System.out.println("stu="+stu));
    sqlSession.close();

}

3.3 #和$的区别

3.3.1 # 占位符

语法: #{字符}

mybatis处理#{} 使用jdbc对象是 PrepareStatment对象



mybatis出创建PrepareStatement对象,执行sql语句
String sql=" select id,name,email,age from student where id=?";
PrepareStatement pst = conn.prepareStatement(sql);
pst.setInt(1,1001);  //传递参数
ResultSet rs  = pst.executeQuery(); //执行sql语句


{}特点:

1)使用的PrepareStatement对象,执行sql语句,效率高。

2)使用的PrepareStatement对象,能避免sql语句, sql语句执行更安全。

3) #{} 常常作为 列值使用的, 位于等号的右侧, #{}位置的值和数据类型有关的。

3.3.2 $ 占位符

语法 : ${字符}

mybatis执行${}占位符的sql语句

	

${} 表示字符串连接, 把sql语句的其他内容和 ${}内容使用 字符串(+) 连接的方式连在一起
String sql="select id,name,email,age from student where id=" + "1001";

mybatis创建Statement对象, 执行sql语句。
Statement stmt  = conn.createStatement(sql);
ResultSet rs  = stmt.executeQuery();

${} 的特点

1)使用Statement对象,执行sql语句,效率低

2)${}占位符的值,使用的字符串连接方式, 有sql注入的风险。 有代码安全的问题

  1. ${} 数据是原样使用的, 不会区分数据类型。

4)${} 常用作 表名或者列名, 在能保证数据安全的情况下使用 ${}

总结

{}使用的PrepareStatement对象,执行sql语句,效率高

{}能避免sql注入,更安全

{}使用占位符

${}使用字符串连接的方式

${}使用Statement对象执行sql,效率较低

${}有sql注入风险,缺乏安全性

3.4 封装MyBatis输出结果

封装输出结果: MyBatis执行sql语句,得到ResultSet, 转为java对象。

讲两个 resultType, resultMap

resultType和resultMap不能一起用

3.4.1 resultType

resultType属性: 在执行select时使用, 作为 select id,name,email,age from student where id=#{studentId} resultType:现在使用java类型的全限定名称。 表示的意思 mybatis执行sql,把ResultSet中的数据转为Student类型的对象。 mybatis会做以下操作: 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集合。 所以执行 Student mystudent = dao.selectById(1001); 得到 数据库中 id=1001这行数据, 这行数据的列值, 付给了mystudent对象的属性。 你能得到mystudent对象。 就相当于是 id=1001这行数据。 2)resultType表示简单类型 dao方法 long countStudent(); mapper文件 3) resultType:表示一个map结构 //查询结果返回是一个Map Map selectMap(@Param("stuid") Integer id); 别名 在mybatis主配置文件中加入typeAliases标签 的name属性是包名,表示这个包中的所有类,以类名作为别名 3.4.2 resultMap resultMap: 结果映射。 自定义列名和java对象属性的对应关系。 常用在列名和属性名不同的情况。 用法: 1.先定义 resultMap标签, 指定列名和属性名称对应关系 2.在select标签使用resultMap属性,指定上面定义的resultMap的id值 3.5 自定义别名 mybatis提供的对java类型定义简短,好记名称。 自定义别名的步骤: 1)在mybatis主配置文件,使用 typeAliases标签声明别名 2)在mapper文件中, resultType="别名" 声明别名(mybatis主配置文件) mapper文件中使用 resultType="别名" 3.6 列名和java对象属性名称不一样解决方式 1) 使用resultMap: 自定义列名和属性名称对应关系 2)使用resultType: 直接在sql语句中使用列别名(as),让别名和java对象属性名称一样 3.7 like 第一种方式: 在java程序中,把like的内容组装好。 把这个内容传入到sql语句 //like第一种方式 List selectLikeOne(@Param("name") String name); mapper 执行like @Test public void testLikeOne(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); String name="%李%"; List students = dao.selectLikeOne(name); sqlSession.close(); students.forEach( stu-> System.out.println(stu)); } 第二种方式: 在sql语句,组织like的内容。 sql语句like的格式: where name like "%"空格#{name}空格"%" //like第二种方式 List selectLikeTwo(@Param("name") String name); @Test public void testLikeTwo(){ SqlSession sqlSession = MyBatisUtil.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); String name="李"; List students = dao.selectLikeTwo(name); sqlSession.close(); students.forEach( stu-> System.out.println(stu)); } 第四章 动态sql(核心) 什么是动态sql: 同一个dao的方法, 根据不同的条件可以表示不同的sql语句, 主要是where部分有变化 使用mybatis提供的标签,实现动态sql的能力, 主要讲 if ,where ,foreach, sql。 使用动态sql的时候, dao方法的形参使用java对象。 什么时候使用动态sql: 4.1 if 标签 语法: sql 代码 在mapper文件中 例子: List selectIf(Student student); 4.2 where 标签 使用if标签时,容易引起sql语句语法错误。 使用where标签解决if产生的语法问题。 使用时 where ,里面是一个或多个if 标签, 当有一个if标签 判断条件为true, where标签会转为 WHERE 关键字附加到sql语句的后面。 如果 if 没有一个条件为true , 忽略where和里面的if。 where标签删除 和他最近的or 或者 and。 语法: sql语句1 sql语句2 例子: //where List selectWhere(Student student); 4.3 foreach 循环 使用foreach可以循环数组,list集合, 一般使用在in语句中。 语法: < foreach collection="集合类型" open="开始的字符" close="结束的字符" item="集合中的成员" separator="集合成员之间的分隔符"> #{item 的值} 标签属性: collection: 表示,循环的对象是 数组, 还是list集合。 如果dao接口方法的形参是 数组, collection="array" ,如果dao接口形参是List, collection="list" open:循环开始时的字符。 sql.append("("); close:循环结束时字符。 sql.append(")"); item:集合成员, 自定义的变量。 Integer item = idlist.get(i);// item是集合成员 separator:集合成员之间的分隔符。 sql.append(","); //集合成员之间的分隔符 #{item 的值}:获取集合成员的值。 第一种方式: //foreach-1 List selectForeachOne(List idlist); @Test public void testSelectForeachOne(){ //1.获取SqlSession SqlSession session = MyBatisUtil.getSqlSession(); //2.获取dao的代理 StudentDao dao = session.getMapper(StudentDao.class); List idlist = new ArrayList<>(); idlist.add(1001); idlist.add(1002); idlist.add(1003); List students = dao.selectForeachOne(idlist); students.forEach( stu-> System.out.println("stu=="+stu)); //3.关闭SqlSession对象 session.close(); } 第二种方式: //foreach-2 List selectForeachTwo(List studentList); @Test public void testSelectForeachTwo(){ //1.获取SqlSession SqlSession session = MyBatisUtil.getSqlSession(); //2.获取dao的代理 StudentDao dao = session.getMapper(StudentDao.class); List list = new ArrayList<>(); Student s1 = new Student(); s1.setId(1001); Student s2 = new Student(); s2.setId(1002); list.add(s1); list.add(s2); List students = dao.selectForeachTwo(list); students.forEach( stu-> System.out.println("stu=="+stu)); //3.关闭SqlSession对象 session.close(); } 4.4 sql标签 sql标签标示 一段sql代码, 可以是表名,几个字段, where条件都可以, 可以在其他地方复用sql标签的内容。 使用方式: 1) 在mapper文件中定义 sql代码片段 部分sql语句 2)在其他的位置,使用include标签引用某个代码片段 例如: select * from student id,name,email 第五章 MyBatis配置文件 mybatis配置文件两大类: 1 mybatis主配置文件; 2 mybatis的mapper文件 mybatis主配置文件,提供mybatis全局设置的。包含的内容 日志, 数据源,mapper文件位置 mapper文件: 写sql语句的。 一个表一个mapper文件 5.1 settings部分 settings是mybatis的全局设置,影响整个mybatis的运行。 这个设置一般使用默认值就可以了。 5.2 typeAliase 别名 设置别名 5.3 配置环境 environments: 环境标签, 在他里面可以配置多个environment 属性: default ,必须是某个environment的id属性值。 表示mybatis默认连接的数据库 environment: 表示一个数据库的连接信息。 属性: id 自定义的环境的标识。 唯一值。 transactionManager:事务管理器 属性: type 表示事务管理器的类型。 属性值:1)JDBC: 使用Connection对象, 由mybatis自己完成事务的处理。 2) MANAGED: 管理,表示把事务的处理交给容器实现(由其他软件完成事务的提交,回滚) dataSource: 数据源,创建的Connection对象,连接数据库。 属性: type 数据源的类型 属性值:1) POOLED, mybatis会在内存中创建PooledDataSource类,管理多个Connection连接对象,使 用的连接池 2) UNPOOLED ,不使用连接池, mybatis创建一个UnPooledDataSource这个类, 每次执行sql 语句先创建Connection对象,再执行sql语句,最后关闭Connection 3) JNDI : java的命名和目录服务。 5.4 使用数据库属性配置文件(掌握) 需要把数据库的配置信息放到一个单独文件中, 独立管理。 这个文件扩展名是 properties. 在这个文件中,使用自定义的key=value的格式表示数据 使用步骤: 1.在resources目录中,创建xxxx.properties 2.在文件中,使用 key=value的格式定义数据。 例如 jdbc.url=jdbc:mysq://localhost:3306/springdb 3.在mybatis主配置文件, 使用properties标签引用外部的属性配置文件 4.在使用值的位置, 使用${key}获取key对应的value(等号右侧的值) 例子: jdbc.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8 jdbc.username=root jdbc.password=123 mybatis主配置文件 5.5 mapper 标签(*) 使用mapper指定其他mapper文件的位置, mapper标签使用的格式有两个常用的方式: 第六章 PageHelper PageHelper做数据分页。 在你的select语句后面加入 分页的 sql 内容, 如果你使用的mysql数据库, 它就是在select * from student 后面加入 limit 语句。 使用步骤: 1.加入依赖pagehelper依赖 com.github.pagehelper pagehelper 5.1.10 2.在mybatis主配置文件, 加入plugin声明 在 之前加入 3.在select语句之前,调用PageHelper.startPage(页码, 每页大小) 对比: 没有使用PageHelper select * from student order by id 使用PageHelper SELECT count(0) FROM student select * from student order by id LIMIT ?