MyBatis

MyBatis,第1张

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框架

MyBatis框架:

MyBatis是一个优秀的基于java的持久层框架,内部封装了jdbc,开发者只需要关注sql语句本身,而不需要处理加载驱动、创建连接、创建statement、关闭连接

Spring框架:

Spring框架为了解决软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前非常复杂的企业级开发。Spring解决了业务对象,功能模块

SpringMVC框架:

SpringMVC属于SpringframeWork3.0版本加入的一个模块,为Spring框架提供了构建Web应用程序的能力

5、框架

框架(framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构建实例间交互的方法:另一种认为,框架是可被应用开发者定制的应用骨架、模板

简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架是一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能

框架是安全的,可复用的,不断升级的软件

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

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

6、框架解决的问题

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

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

​ 框架要解决的最重要的一个问题是技术整合,在J2EE的框架中,有着各种各样的技术,不同的应用,系统使用不同的技术解决问题,需要从J2EE中选择不同的技术,而技术自身的复杂性,有导致更大的风险。企业在开发软件项目时,主要目的是解决业务问题,既要求企业负责技术本身,又要求解决业务问题,这是大多数企业不能完成的,框架把相关的技术融合在一起,企业开发可以集中在业务领域方面

​ 另一个方面可以提供开发的效率

7、JDBC访问数据库的优缺点

优点:1、直观、好理解

缺点:

1、创建很多对象Connection,Statement,ResultSet

2、注册驱动

3、执行sql语句

4、把ResultSet转为Student,List集合

5、关闭资源

6、sql语句和业务逻辑代码混在一起

8、MyBatis框架

什么是MyBatis?是一个持久层框架

MyBatis框架:MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到GitHub

MyBatis解决的问题:减轻使用JDBC的复杂性,不用编写重复的创建Connection,Statement;不用编写关闭资源代码

直接使用java对象,表示结果数据,让开发者专注SQL的处理,其它分心的工作由MyBatis代劳

MyBatis可以完成:

1、注册数据库的驱动,例如Class.forName(“com.mysql.cj.jdbc.Driver”)

2、创建JDBC中必须使用的Connection,Statement,ResultSet对象

3、从xml中获取sql,并执行sql语句,把ResultSet结果转换为java对象

4、关闭资源

ResultSet.close(),Statement.close(),Connection.close()

MyBatis可以 *** 作数据库,对数据执行增删改查,看做是高级的jdbc,解决jdbc的缺点

第二章 MyBatis框架快速入门 2.1 入门案例

MyBatis开发准备

​ 下载MyBatis:https://github.com/mybatis/mybatis-3/releases


    org.mybatis
    mybatis
    3.5.7

搭建MyBatis开发环境,实现第一个案例

​ (1)创建mysql数据库和表

数据库名ssm;表名student

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4OJrUqAe-1642483473066)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828134238544.png)]

(2)新建maven项目

(3)修改pom.xml

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

2)在加入资源插件

(4)创建实体类Student,定义属性,属性名和列名保持一致

(5)创建Dao接口,定义 *** 作数据库的方法

(6)创建xml文件(mapper文件),写sql语句

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

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

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

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

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

(8)创建测试的内容

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

也可以使用junit访问数据库


    
      
      
        src/main/java
        
          ***.xml
        
        false
      
    




    
        select * from Blog where id = #{id}
    

约束文件:“http://mybatis.org/dtd/mybatis-3-mapper.dtd”

约束文件作用:定义和限制当前文件中可以使用的标签和属性,以及标签出现的顺序

mapper是根标签

namespace:命名空间,必须有值,不能为空,唯一值,推荐使用Dao接口的权限定名称,作用:参与识别sql语句的作用

在mapper里面可以写,,,里面是select语句

    
        select id,name,email,age from student where id=#{studentId}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r5qToowf-1642483473067)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828155936395.png)]

insert需要提交事务

日志功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vJ7DNfFk-1642483473068)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828160502771.png)]

2.2 概念

自动提交:当你的sql语句执行完毕后,提交事务,数据库更新 *** 作直接保存到数据库

手动提交事务:在你需要提交事务的位置,执行方法,执行事务或者回滚事务

mybatis默认执行sql语句是手工提交事务模式,在做insert,update,delete后需要提交事务

session.commit()

如果传入给mybatis是一个java对象,使用#{属性名}获取此属性的值

属性值放到#{}占位符的位置,mybatis执行此属性对应的getXXX()

例如#{id},执行getId();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U5qFG4bx-1642483473069)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828185733066.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iDjDTugm-1642483473070)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828185806214.png)]

2.3Mybatis的一些重要对象

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

2)SqlSessionFactoryBuilder:负责创建SqlSessionFactory对象

3)SqlSessionFactory:重要对象

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

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

DefaultSessionFactory实现类

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语句,最多得到一行记录,多余一行是错误
selectList:执行sql语句,返回多行数据
selectMap:执行sql语句,得到一个Map结果
insert:执行insert语句
update:执行update语句
delete:执行delete语句
commit:提交事务
rollback:回滚事务

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

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

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

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

mybatis的底层是jdbc

2.4使用工具类和模板

创建mapper文件的模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKaa5YkL-1642483473071)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828200448855.png)]

加号添加自定义模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtEHgKz7-1642483473073)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828201056999.png)]

创建主配置文件的模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Mqrea8w-1642483473074)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828201834355.png)]

创建工具类MyBatisUtil

public class MyBatisUtil {
    private static SqlSessionFactory factory = null;
    static {
        String config = "mybatis.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(config);
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    //创建方法,获取SqlSession对象
    public static SqlSession getSqlSession(){
        SqlSession session = null;
        if (factory != null){
            session = factory.openSession();//openSion(true);
        }
        return session;
    }
}
@Test
    public void testSelectById(){
        //1、获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2、指定sqlid
        String sqlId = "org.example.mybatis.dao.StudentDao" + "." + "InsertStudent";
        //3、执行SqlSession的方法,执行sql语句
        session.insert(sqlId,new Student(1005,"hhahhvsah","hahsak@qq.com",78));
        session.commit();
        //4、关闭SqlSession对象
        session.close();
    }

查询所有

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HHc0GvQ1-1642483473074)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828204628579.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gJi0Vl0N-1642483473076)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828204653535.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCvAxEFs-1642483473076)(C:UserspumpkinAppDataRoamingTyporatypora-user-imagesimage-20210828204726087.png)]

使用传统的dao执行sql

public class StudentDaoImpl implements StudentDao {
    @Override
    public Student selectStudentById(Integer id) {
        SqlSession session = MyBatisUtil.getSqlSession();
        String sqlId = "org.example.mybatis.dao.StudentDao" + "."+ "selectStudentById";
        Student student = session.selectOne(sqlId, id);
        session.close();
        return student;
    }

    @Override
    public int InsertStudent(Student student) {
        SqlSession session = MyBatisUtil.getSqlSession();
        String sqlId = "org.example.mybatis.dao.StudentDao" + "."+"InsertStudent";
        int hah = session.insert(sqlId, student);
        session.commit();
        session.close();
        return hah;
    }

    @Override
    public List selectAllStudent() {
        SqlSession session = MyBatisUtil.getSqlSession();
        String sqlId = "org.example.mybatis.dao.StudentDao" + "."+ "selectAllStudent";
        List students = session.selectList(sqlId);
        session.close();
        return students;
    }
}
public class StudentDaoImplTest extends TestCase {

    private StudentDaoImpl studentDao = new StudentDaoImpl();

    public void testSelectStudentById() {
        Student student = studentDao.selectStudentById(1002);
        System.out.println("student = " + student);
    }

    public void testInsertStudent() {
        int i = studentDao.InsertStudent(new Student(1006, "ahhvsah", "hsak@qq.com", 78));
        System.out.println("i = " + i);
    }

    public void testSelectAllStudent() {
        List students = studentDao.selectAllStudent();
        for (Student stu:students){
            System.out.println("stu = " + stu);
        }
    }
}

测试方法中:调用dao的方法

Student student = dao.selectById(1002);

1)dao:通过反射能够得到全限定类型名称

dao是StudentDao类型的,全限定类型名称org.example.mybatis.dao.StudentDao

2)selectById:dao中的方法名称,方法名称就是mapper文件中标签的id

通过dao.selectById()能得到sqlId=“com.example.mybatis.dao.StudentDao.selectById”;

3)确定调用SqlSession的那个方法

1、根据dao接口的方法返回类型,如果返回是一个对象,例如Student,调用SqlSession.selectOne();

如果dao接口中的方法返回List,调用SqlSession的selectList();

2、根据mapper文件中的标签,如果标签是,调用SqlSession.insert()方法

mybatis代理的说明

mybatis框架,发现使用dao的方法调用能确定执行sql语句的必要信息,mybatis简化dao对象的实现

由mybatis框架在程序执行期间,根据你的Dao接口,创建一个内存中的接口的实现类对象

mybatis把这个技术叫做dao技术(动态代理,dao的动态代理)

dao代理技术:由mybatis创建StudentDao接口的实现类StudentDaoImpl,使用框架创建的StudentDaoImpl代替你自己手动实现的StudentImpl类的功能,不用开发人员写dao接口的实现类

使用dao的代理要求:

1、mapper文件中的namespace:必须是dao接口的全限定名称

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

2.5dao代理

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

使用mybatis代理要求

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

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

mybatis代理实现方式

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

例如:现在有StudentDao接口

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

//上面代码中
StudentDao dao = session.getMapper(StudentDao.calss);
//等同于
StudentDao dao = new StudentDaoImpl();
@Test
    public void testInserttStudentById() throws IOException {
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        Student student = dao.selectStudentById(1003);
        System.out.println("student = " + student);
        session.close();
    }

不需要StudentDao实现类了

@Test
public void testSelectById(){
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    int i = dao.InsertStudent(new Student(1007, "jajc", "jdnacj@qq.com", 18));
    System.out.println("i = " + i);
    session.commit();
    session.close();
}

@Test
public void testSelectAllStudent(){
    SqlSession session = MyBatisUtil.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    List students = dao.selectAllStudent();
    students.forEach(student -> {
    System.out.println("student = " + student);
    });
    session.close();
}

(1)去掉Dao接口的实现类

(2)getMapper获取代理对象

​ 只需调用SqlSeesion的getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定Dao接口类的class值

SqlSession session = factory.openSession();
StudentDao dao = session.getMapper(StudentDao.class);

使用工具类:

StudentDao studentDao = MyBatisUtil.getSqlSession().getMapper(StudentDao.class);

(3)使用Dao代理对象方法执行sql语句

第三章 mybatis的dao代理 3.2 深入理解参数

从java代码中把参数传递到mapper.xml文件

理解参数是:通过java程序把数据传入到mapper文件中的sql语句

参数主要是指dao接口方法的形参

3.2.1 parameterType

parameterType:接口中方法参数的类型,类型的完全限定名或别名。这个属性是可选的,因为mybatis可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从java代码传入到mapper文件的sql语句

select id,name,email,age from student where id=#{studentId}

mybatis执行的sql语句:select id,name,email,age from student where id=?

?是占位符,使用jdbc中的PreparedStatement执行这样的sql语句

PreparedStatement pst = conn.preparedStatement("select id,name,email,age from student where id=?")

给?位置赋值

参数是Integer,执行pst.setInt(1,1005);

参数是String,执行pst.setString(1,“1005”);

第一种用法:java类型的全限定类型名称 parameterType=”java.lang.Integer"

第二种用法:mybatis定义的java类型的别名

官方文档

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

3.2.2 一个简单参数

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

接口方法:Student selectById(int id);

mapper文件:获取这个参数值,使用#{任意字符}

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

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

dao接口,方法的定义

List selectByNameOrAge(@Param("myname") String name,
                                @Param("myage") Integer age);

mapper文件


	insert into student values (#{id},#{name},#{email},#{age})



	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}

多个参数——按位置

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

注意:mybatis-3.3版本和之前的版本使用#{0},#{1}方式,从mybatis3.4开始使用#{arg0}方式

接口方法:List selectByNameAndAge(String name,int age);

mapper文件:


	select id,name,email,age from student where name=#{myname} or age=#{myage}

更新


	update student set name=#{name},email=#{email} where id=#{id}

#和$

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

mapper文件

标签的属性出现的

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

1)resultType表示自定义对象


        select count(*) from student
    

3)resultType为Map类型

sql的查询结果作为Map的key和value,推荐使用Map

注意:Map作为接口返回值,sql语句的查询结果最多只能有一条记录,大于一条记录是错误

执行sql语句得到一个Map结构数据,mybatis执行sql,把ResultSet转为map

sql执行结果,列名做map的key,列值作为value

sql执行得到是一行记录,转为map结构是正确的

dao方法:

Map selectReturnMap(int id);

mapper文件:


	select id,name,email,age from student where id=#{studentId}

resultMap和resultType不能同时使用,二选一

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

(1)使用列别名和

步骤:

1、创建新的实体类PrimaryStudent

package org.example.pojo;

public class PrimaryStudent{
    private Integer stuId;
    private String stuName;
    private Integer stuAge;
    //set,get方法
}

2、接口方法

List selectUserFieldAlias(QueryParam param);

mapper文件


	select * from student where name like #{name}

String name = "%李%";

第二种方式:在sql语句中,组织like的内容

sql语句中like的格式:where name like “%“空格#{name}空格”%”

第四章 MyBatis框架动态SQL

动态SQL,通过MyBatis提供的各种标签对条件作出判断以实现动态拼接SQL语句。这里的条件判断使用的表达式为OGNL表达式。常用的动态SQL标签有

MyBatis的动态SQL语句,与JSTL的语句非常相似

什么是动态sql:同一个dao的方法,根据不同的条件可以表示不同的sql语句,主要是where部分有变化

使用mybatis提供的标签,实现动态sql的能力

使用动态sql时,dao方法的形参使用java对象

动态SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询,提交的查询条件不同,执行的SQL语句不同,若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的sql语句。此时,可使用动态sql来解决这样的问题

4.1 if

语法


	sql代码

多个if可以同时存在,但没有else

mapper文件中

    select * from student
    where
    
    	name = #{name}
    
    
    
		or age < #{age}    
    

多条件查询时使用动态sql和实体

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

特别是对于小于号(<),在XML中是绝不能出现的,否则解析mapper文件会出错

实体符号表:

<小于<>大于>>=大于等于&get;=<=小于等于<= 4.2 where标签

使用if标签时,容易引起sql语句语法错误,使用where标签解决if产生的语法问题

使用时,先写where,里面时一个或多个if标签,当有一个if标签判断条件为true,where标签会转为WHERe关键字,附加到sql语句的后面。如果if没有一个条件为true,忽略where和里面的if

语法:

	sql语句1
    sql语句2


    select * from student 
	
    	where id in
        
    		#{myid}
    	
    

(2)foreach对象类型的List

dao方法

List selectForeach(List studentList);

mapper文件



	id,name,email