MyBatis自用MyBatis学习笔记

Posted 王六六的IT日常

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis自用MyBatis学习笔记相关的知识,希望对你有一定的参考价值。

2021.20.10-----2021.10.13 完成MyBatis的系统学习 😐

对学习完的内容进行归纳总结-----------------


第一章 框架的概述

三层架构

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等等。

三层架构请求的处理流程

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

为什么要使用三层?

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

三层架构模式和框架

每一层对应着一个框架
1)界面层—SpringMVC框架
2)业务层—Spring框架
3)持久层—MyBatis框架

框架

1.什么是框架(framework)
框架:就是一个软件, 完成了部分的功能。 软件中的类和类之间的方法调用都已经规定好了。 通过这些可以完成某些功能。 框架看做是模版。
框架是可以升级的,改造的。 框架是安全的。
框架是对某一个方面有用的,不是全能的。

框架解决的问题

1)框架能实现技术的整合。
2)提供开发的效率。 降低难度。

jdbc访问数据库的优缺点

优点:

  • 直观,好理解

缺点:

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

MyBatis框架

什么是 mybatis:
是一个持久层框架, 原名是ibatis, 2013改名为 MyBatis. MyBatis可以操作数据库,对数据执行增删改查。 看做是高级的jdbc。 解决jdbc的缺点。
mybatis能做什么?
1) 注册驱动 。
2) 创建jdbc中使用的Connection, Statement,ResultSet
3)执行sql语句, 得到ResultSet
4)处理ResultSet, 把记录集中的数据转为java对象, 同时还能把java对象放入到List集合。
5)关闭资源
6)实现sql语句和java代码的解耦合。

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

第二章 MyBatis入门

第一个例子 ---- 实现步骤:

  1. 创建student表(id,name,email,age)
  2. 新建maven项目
  3. 修改pom.xml
    1)加入依赖(本地仓库/联网下载) mybatis依赖, mysql驱动, junit
    2)在<build>加入资源插件
  4. 创建实体类Student。定义属性, 属性名和列名保持一致
  5. 创建Dao接口, 定义操作数据库的方法。
  6. 创建xml文件(mapper文件), 写sql语句。
    mybatis框架推荐是把sql语句和java代码分开
    mapper文件:定义和dao接口在同一目录, 一个表一个mapper文件。
  7. 创建mybatis的主配置文件(xml文件):有一个, 放在resources目录下
    1)定义创建连接实例的数据源(DataSource)对象
    2)指定其他mapper文件的位置
  8. 创建测试的内容。(2种方法)
    1)使用main方法,测试mybatis访问数据库
    2)可以使用junit 访问数据库

概念

1.自动提交:当你的 sql语句执行完毕后, 提交事务。 数据库更新操作之间保存到数据
2.手动(手工)提交事务:在你需要提交事务的位置, 执行方法,提交事务或者回顾事务。

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

4)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()

使用工具类和模版

1)创建模版,mapper文件模版和mybatis主配置文件模版
创建模版的步骤:

创建模版文件:

创建文件选择使用的模版: 创建文件快捷键(Alt + insert)

第三章 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接口方法参数的类型, 可以不写 

<select id="selectById" parameterType="integer" 
			resultType="com.bjpowernode.domain.Student"> 
	select id,name,email,age from student where id=#{studentId} 
</select>

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

StudentDao.java

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

mapper文件:

<!--dao接口是一个简单类型的参数 mapper文件,获取这个参数值,使用#{任意字符} --> 
<select id="selectByEmail" resultType="com.bjpowernode.domain.Student"> 
	select id,name,email,age from student where email=#{studentEmail} 
</select>

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

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

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

mapper文件

<!--多个简单类型的参数:
	当使用了@Param命名后,例如@Param("myname"). 
	在mapper中,使用#{命名的参数}, 例如 #{myname} --> 
<select id="selectByNameOrAge" resultType="com.bjpowernode.domain.Student"> 
	select id,name,email,age from student where name=#{myname} or age=#{myage} 
</select>

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<Student> selectByObject(Student student);

    List<Student> selectByQueryParam(QueryParam param);

mapper文件

<!--一个java对象作为方法的参数,使用对象的属性作为参数值使用 简单的语法: #{属性名} , mybatis调用此属性的getXXX()方法获取属性值 --> 
<select id="selectByObject" resultType="com.bjpowernode.domain.Student"> 
	select id,name,email,age from student where name=#{name} or age=#{age} 
</select> 

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

<!--负责的语法格式: 
	#{属性名,javaType=java类型的全限定名称,jdbcType=mybatis中定义列的数据类型}
	--> 

<select id="selectByObject" resultType="com.bjpowernode.domain.Student"> 
	select id,name,email,age from student where 
	name=#{name,javaType=java.lang.String,jdbcType=VARCHAR} 
	or
	age=#{age,javaType=java.lang.Integer,jdbcType=INTEGER} 
</select>

3.2.5 dao接口中多个简单类型的参数--------使用位置

参数位置: dao接口中方法的形参列表,从左往右,参数位置是 0 , 1, 2…
语法格式:#{arg0} ,#{arg1}

dao接口的方法

 	/*
       使用位置,获取参数
     */
    List<Student> selectByPosition(String name, Integer age);
<!--	mybatis版本是 3.5.1
       使用位置获取参数值, dao接口方法是多个简单类型的参数
       语法: #{arg0}, #{arg1}....
    -->
    <select id="selectByPosition" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student where name=#{arg0} or age=#{arg1}
    </select>

3.2.6 dao接口参数是一个Map

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

	/*
       使用Map作为参数
     */
    List<Student> selectStudentByMap(Map<String, Object> map);

mapper文件

<!--
      使用Map传递参数,
      在mapper文件中,获取map的值,是通过key获取的,语法:#{key}
   -->
    <select id="selectStudentByMap" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student where name=#{myname} or age=#{myage}
    </select>

测试,调用方法的位置

@Test
    public void testSelectByMap(){

        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        //使用map
        HashMap<String, Object> data = new HashMap<>();
        data.put("myname","王六六");
        data.put("myage",19);
        List<Student> students = dao.selectStudentByMap(data);

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

    }

3.3 #和$的区别

3.3.1 # 占位符

语法: #{字符}
mybatis处理#{} 使用jdbc对象是 PrepareStatment对象

<select id="selectById" parameterType="integer" 
				resultType="com.bjpowernode.domain.Student"> 
	select id,name,email,age from student where id=#{studentId} 
</select> 

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语句

<select id="selectById" parameterType="integer" 
			resultType="com.bjpowernode.domain.Student"> 
	select id,name,email,age from student where id=${studentId} 
</select> 

${} 表示字符串连接, 把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注入的风险。 有代码安全的问题
3. ${} 数据是原样使用的, 不会区分数据类型。
4)${} 常用作 表名或者列名, 在能保证数据安全的情况下使用 ${}

3.4 封装MyBatis输出结果

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

3.4.1 resultType

resultType属性: 在执行select时使用, 作为<select>标签的属性出现的。

resultType:表示结果类型 , mysql执行sql语句,得到java对象的类型。
它的值有两种:
1) java类型的全限定名称 2)使用别名

1) resultType:表示java自定义对象

Student selectById(Integer id);

<select id="selectById"  parameterType="integer"
             resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where id=#{studentId}
</select>

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文件

<!--执行sql语句,得到是一个值(一行一列) --> 
<select id="countStudent" resultType="java.lang.Long"> 
	select count(*) from student 
</select>

3) resultType:表示一个map结构

//查询结果返回是一个
Map Map<Object,Object> selectMap(@Param("stuid") Integer id);
<!--执行sql得到一个Map结构数据, mybatis执行sql,把ResultSet转为map 
sql执行结果, 列名做map的key , 列值作为value 
sql执行得到是一行记录,转为map结构是正确的。 

dao接口返回是一个map, sql语句最多能获取一行记录,多余一行是错误 --> 
<select id="selectMap" resultType="java.util.HashMap"> 
	select id,name,email from student where id != #{stuid} 
</select>

3.4.2 resultMap

resultMap: 结果映射。 自定义列名和java对象属性的对应关系。 常用在列名和属性名不同的情况。
用法:
1.先定义 resultMap标签, 指定列名和属性名称对应关系
2.在select标签使用resultMap属性,指定上面定义的resultMap的id值

<!--使用resultMap定义列和属性的关系-->
    <!--定义resultMap
        id:给resultMap的映射关系起个名称,唯一值
        type:java类型的全限定名称
    -->
    <resultMap id="customMap" type="com.bjpowernode.vo.CustomObject">

        <!--定义列名和属性名的对应-->
        <!--主键类型使用id标签-->
        <id column="id" property="cid" />
        <!--非主键类型使用result标签-->
        <result column="name" property="cname" />
        <!--列名和属性名相同不用定义-->
        <result column="email" property="email" />
        <result column="age" property="age" />
    </resultMap>

    <!--使用resultMap属性,指定映射关系的id
        resultMap和resultType 不能同时使用, 二选一。
    -->
    <select id="selectById2" resultMap="customMap">
      select id,name,email,age from student where id=#{stuid}
    </select>

3.5 自定义别名

mybatis提供的对java类型定义简短,好记名称。

自定义别名的步骤:

1)在mybatis主配置文件,使用 typeAliases标签声明别名
2)在mapper文件中, resultType=“别名”

声明别名(mybatis主配置文件)

<typeAliases> 
<!--第一种语法格式 type:java类型的全限定名称(自定义类型) alias:自定义别名 --> 
	<typeAlias type="com.bjpowernode.domain.Student" alias="stu" /> 
</typeAliases>

mapper文件中使用

resultType="别名" 
<select id="selectById" parameterType="integer" resultType="stu"> 
	select id,name,email,age from student where id=#{studentId} 
</select>

3.6 列名和java对象属性名称不一样解决方式

1) 使用resultMap: 自定义列名和属性名称对应关系
2) 使用resultType: 使用列别名,让别名和java对象属性名称一样

3.7 like

第一种方式: 在java程序中,把like的内容组装好。 把这个内容传入到sql语句

List<Student> selectLikeOne(@Param("name") String name);

mapper

<select id="selectLikeOne" resultType="com.bjpowernode.domain.Student"> 
	select * from student where name like #{name} 
</select>

执行like

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

        String name="%丸%";
        List<Student> students = dao.selectLikeOne(name);

        sqlSession.close();

        students.forEach( stu-> System.out.println(stu));
    }

第二种方式: 在sql语句,组织like的内容。
sql语句like的格式: where name like "%"空格#{name}空格"%"

List<Student> selectLikeTwo(@Param("name") String name);
<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
        select * from student where name like "%" #{name} "%"
</select>
@Test
    public void testLikeTwo(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao  = sqlSession.getMapper(StudentDao.class);

        String name="丸";
        List<Student> students = dao.selectLikeTwo(name)以上是关于MyBatis自用MyBatis学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis学习笔记:动态SQL

MyBatis-05-笔记

mybatis学习(39):动态sql片段

MyBatis学习笔记 —— MyBatis简介

mybatis学习笔记使用generator生成mybatis基础配置代码和目录结构

Mybatis-Plus学习笔记